#CakePHP3では、saveAllがない
cakephp2系だと、saveAllというのがあって、
複数行INSERTするときにはそれを使ってました。
でも、cakephp3.xだと、saveAllはなくなっていました。
これがCakePHP3式のsaveAllだ...!
で、どうしたらいいか調べたところ、
ドキュメント(英語)にこんな記載がありました。
そちらで示されているサンプルコードを、一部変更して記述すると、
下記のような形になってます。
// 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()とかで省略したりとかもできそうですね。
より良いやりかたを発見されましたら、ぜひ教えて下さい!