CakePHP 4 のシードで独自の AbstractSeed を作り共通処理を実装
はじめに
前回の「CakePHP 4 のシードで CSV ファイルを使う方法」でご紹介したように、CakePHP 4 のシードでは PHP のプログラムを書くことができます。
今回はそんな場合に役立つ、CakePHP 4 のシードで継承するための、独自の AbstractSeed を作成し、そこに共通の処理を実装する方法をご紹介します。
検証に使用したのは CakePHP 4.2.3 (cakephp/app 4.2.1) です。
1. 下準備
前回と同様に、シードで CSV を使用する場面を想定し、独自の AbstractSeed を作って、そこに CSV 読込処理を実装します。
ファイル構成は下記のような感じで、マイグレーションと CSV の内容は前回と同じです。
/path/to/cakephp4/
├ config/
│ ├ Migrations/
│ │ └ 20210206000001_CreateDrinks.php
│ ├ Seeds/
│ │ └ DrinksSeed.php
│ ├ SeedsCSV/
│ │ └ Drinks.csv
│ ~
│
├ src/
│ ├ Migrations/
│ │ └ AbstractSeed.php
~ ~
<?php
declare(strict_types=1);
use Migrations\AbstractMigration;
class CreateDrinks extends AbstractMigration
{
public function change()
{
$table = $this->table('drinks');
$table->addColumn('name', 'string', [
'default' => null,
'limit' => 255,
'null' => false,
]);
$table->create();
}
}
CSV ファイルの文字コードは SJISで、改行コードが CRLF です。
1,"オレンジ
ジュース"
2,コーラ
3,Beer
AbstractSeed と DrinksSeed は次以降でご紹介します。
2. 独自の AbstractSeed を作成
今回は AbstractSeed クラスを src/Migrations フォルダの中に配置します。
別なところでもいいのですが、config/Migrations はマイグレーションファイルの置き場なので不適切と考えています。
今回は CSV ファイルから配列を生成する csvToArr() 関数を実装しています。
<?php
declare(strict_types=1);
namespace App\Migrations;
use Migrations\AbstractSeed as BaseAbstractSeed;
use SplFileObject;
abstract class AbstractSeed extends BaseAbstractSeed
{
public function csvToArr($filePath)
{
$file = new SplFileObject($filePath);
$file->setFlags(SplFileObject::READ_CSV);
$rows = [];
foreach ($file as $row) {
mb_convert_variables('UTF-8', 'SJIS-win', $row);
$rows[] = $row;
}
return $rows;
}
}
- PHP: クラスの抽象化 - Manual
- https://www.php.net/manual/ja/language.oop5.abstract.php
- PHP: SplFileObject::setFlags - Manual
- https://www.php.net/manual/ja/splfileobject.setflags.php
- PHP: mb_convert_kana - Manual
- https://www.php.net/manual/ja/function.mb-convert-kana.php
3. 各シードで継承
各シードで継承する際には use の部分を下記のように書き換えてください。
下記サンプルコードでは AbstractSeed に実装した csvToArr() を使用して、CSV からデータをインポートしています。
<?php
declare(strict_types=1);
// ↓ ここを変更
use App\Migrations\AbstractSeed;
class DrinksSeed extends AbstractSeed
{
public function run()
{
$rows = $this->csvToArr(CONFIG . DS . 'SeedsCSV' . DS . 'drinks.csv');
// insert() 用のデータ作成
// (カラム数が合わない場合はスキップ)
foreach ($rows as $row) {
if (count($row) !== 2) {
continue;
}
list($id, $name) = $row;
$data[] = [
'id' => $id,
'name' => mb_convert_kana($name, 'aKV')
];
}
$table = $this->table('drinks');
$table->insert($data)->save();
}
}
4. おわりに
今回のポイントは、独自の AbstractSeed を config/migrations に作らないことでしょうか。
元の AbstractSeed の namespace が Migrations なので、咄嗟に置きたくなりますね。
ところで今回実装した csvToArr() ですが、機能が汎用的で、コントローラなどでも使用可能な関数なので、AbstractSeed よりは CakePHP 本体にある下記 basics.php のように共通関数として実装したり、パッケージ化すると良いのかなと思います。