PHP
CakePHP
MySQL
SQL
cakephp3

[PHP]CakePHP 3.x でも、複数行INSERTできるよ!

More than 3 years have passed since last update.


CakePHP3では、saveAllがない

cakephp2系だと、saveAllというのがあって、

複数行INSERTするときにはそれを使ってました。

でも、cakephp3.xだと、saveAllはなくなっていました。


これがCakePHP3式のsaveAllだ...!

で、どうしたらいいか調べたところ、

ドキュメント(英語)にこんな記載がありました。

http://book.cakephp.org/3.0/en/orm/saving-data.html#converting-multiple-records

そちらで示されているサンプルコードを、一部変更して記述すると、

下記のような形になってます。

// TableRegistryでモデル取得

$articles = TableRegistry::get('Articles');

// 保存するデータ(2つ)
$data = [
[
'title' => 'First post',
'published' => 1
],
[
'title' => 'Second post',
'published' => 1
],
];

// Entities作成
$entities = $articles->newEntities($data);

// Entitiesの分だけ保存処理
foreach ($entities as $entity) {
// Save entity
$articles->save($entity);
}

で、atomicに保存したいならトランザクションかければいいよ、とか書いてます。

$articles->connection()->transactional(function () use ($articles, $entities) {

foreach ($entities as $entity) {
$articles->save($entity, ['atomic' => false]);
}
});


いやそうじゃねえよ、というあなたにクエリビルダー

複数行のsaveって、基本的にINSERT文ですし、

複数行INSERTしたいからといって、

行の数だけ数だけクエリ発行するのは、

パフォーマンスも損ねますし、

何より気持ち悪いですよね。

本当にここで発行したいSQLは、下記の形のはずです。

INSERT INTO articles (title, published) VALUES ('First post', 1), ('Second post', 1);

とはいえ、クエリを直接ソースコードに入れるのも気持ちわるいので、

せめてクエリビルダーを使って、なんとかならないか試してみました。

で、うまく行ったのが、こちらになります。

$articles = TableRegistry::get('Articles');

// 保存するデータ(2つ)
$data = [
[
'title' => 'First post',
'published' => 1
],
[
'title' => 'Second post',
'published' => 1
],
];
// 実行クエリ
$query = $articles->query();
$query->insert(['title', 'published']);
// dataの数だけvalues追加
foreach ($data as $d) {
$query->values($d);
}
// 実行
$query->execute();

これで、先ほど示した形のSQLが発行されました。

状況に応じて、insert()でカラム指定する部分は、

array_keys()とかで省略したりとかもできそうですね。

より良いやりかたを発見されましたら、ぜひ教えて下さい!