CakePHP 4 のシードで独自の AbstractSeed を作り共通処理を実装

はじめに

前回の「CakePHP 4 のシードで CSV ファイルを使う方法」でご紹介したように、CakePHP 4 のシードでは PHP のプログラムを書くことができます。

今回はそんな場合に役立つ、CakePHP 4 のシードで継承するための、独自の AbstractSeed を作成し、そこに共通の処理を実装する方法をご紹介します。

検証に使用したのは CakePHP 4.2.3 (cakephp/app 4.2.1) です。

目次
  1. 下準備
  2. 独自の AbstractSeed を作成
  3. 各シードで継承
  4. おわりに

1. 下準備

前回と同様に、シードで CSV を使用する場面を想定し、独自の AbstractSeed を作って、そこに CSV 読込処理を実装します。

ファイル構成は下記のような感じで、マイグレーションと CSV の内容は前回と同じです。

/path/to/cakephp4/
  ├ config/
  │  ├ Migrations/
  │  │  └ 20210206000001_CreateDrinks.php
  │  ├ Seeds/
  │  │  └ DrinksSeed.php
  │  ├ SeedsCSV/
  │  │  └ Drinks.csv
  │  ~
  │
  ├ src/
  │  ├ Migrations/
  │  │  └ AbstractSeed.php
  ~  ~
/config/Migrations/20210206000001_CreateDrinks.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 です。

/config/SeedsCSV/Drinks.csv
1,"オレンジ
ジュース"
2,コーラ
3,Beer

AbstractSeed と DrinksSeed は次以降でご紹介します。

2. 独自の AbstractSeed を作成

今回は AbstractSeed クラスを src/Migrations フォルダの中に配置します。

別なところでもいいのですが、config/Migrations はマイグレーションファイルの置き場なので不適切と考えています。

今回は CSV ファイルから配列を生成する csvToArr() 関数を実装しています。

/src/Migrations/AbstractSeed.php
<?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;
    }
}

3. 各シードで継承

各シードで継承する際には use の部分を下記のように書き換えてください。

下記サンプルコードでは AbstractSeed に実装した csvToArr() を使用して、CSV からデータをインポートしています。

/config/Seeds/DrinksSeed.php
<?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 のように共通関数として実装したり、パッケージ化すると良いのかなと思います。

/vendor/cakephp/cakephp/src/basics.php