CakePHP 4 で beforeSave() を使う際に Argument ● passed to ~ エラーが出る場合の対処方法

はじめに

CakePHP 4 のモデルで beforeSave() を使うときに、公式ドキュメントにある通りタイプヒンティングをつけると、下記いずれかのエラーが出る場合があります。

/src/Model/Table/Articles.php
class ArticlesTable extends Table
{
  ...
  public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
  {
    // 何か処理
  }
  ...
}

Argument 1 passed to App\Model\Table\ArticlesTable::beforeSave() must be an instance of App\Model\Table\EventInterface, instance of Cake\Event\Event given, called in \path\to\my-cake-app\vendor\cakephp\cakephp\src\Event\EventManager.php on line 310

Argument 2 passed to App\Model\Table\ArticlesTable::beforeSave() must be an instance of App\Model\Table\EntityInterface, instance of App\Model\Entity\Article given, called in \path\to\my-cake-app\vendor\cakephp\cakephp\src\Event\EventManager.php on line 310

Argument 3 passed to App\Model\Table\ArticlesTable::beforeSave() must be an instance of App\Model\Table\ArrayObject, instance of ArrayObject given, called in \path\to\my-cake-app\vendor\cakephp\cakephp\src\Event\EventManager.php on line 310

今日はそのエラーの対処方法をご紹介します。

目次
  1. 対処方法
  2. 注意
  3. おわりに

1. 対処方法

解決方法は簡単で、当該モデルの use の部分に下記を追加するだけです。

/src/Model/Table/Articles.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use ArrayObject;
use Cake\Datasource\EntityInterface;
use Cake\Event\EventInterface;
...

EntityInterfaceEventInterface の namespace は、/src/Model/Entity/Article.php の 継承元(/vendor/cakephp/cakephp/src/ORM/Entity.php)の use を調べるなどして把握したのですが、公式ドキュメントの behavior にサンプルが掲載されていました。

2. 注意

僕は最初、エラーメッセージを読んで、下記のようにタイプヒンティング側を変更しました。そして、これで動作するケースもあります。

/src/Model/Table/Articles.php
<?php
...
// 下記3行を追加
use App\Model\Entity\Article;
use ArrayObject;
use Cake\Event\Event;
...
class ArticlesTable extends Table
{
  ...
  // ↓ $event と $entity のタイプヒンティング変更
  public function beforeSave(Event $event, Article $entity, ArrayObject $options)
  {
    // 何か処理
  }
  ...
}

しかし、わざわざ上記で実装する理由はないかなと考えています。

むしろ Behavior 化するときにタイプヒンティングを戻す手間が発生するなどのデメリットもあるので、先に紹介したサンプルのように、タイプヒンティングを変えずに use を追加するのが良いと思います。

3. おわりに

今回は EntityInterface と EventInterface の namespace を調べるのに CakePHP 4 本体のソースコードを調べましたが、何か分からないことがあったときには、公式ドキュメントの Cookbook で検索してサンプルコードを探すのもいいなと思いました。

ただし、サンプルコードではタイプヒンティングが省略されているような場合もあるので、注意も必要ですね。