CakePHP 3 で仮想フィールドを使う方法と注意点

はじめに
CakePHP 3 のエンティティには仮想フィールドの機能があります。この機能を使うことで、コントローラやテンプレート内のコードを簡潔にし、保守性を高めることができます。
公式ドキュメントにも実装方法が掲載されているのですが、文量が少ないためか、見逃す場合もあるようです。また toArray() した際に、その配列に仮想フィールドを含める方法がちょっと離れたところに書かれていて、こちらも見逃しやすいかもしれません。
今日は仮想フィールドの実装方法と、toArray() 時にそれを含む方法、そして実装上の注意点をご紹介します。
今回使用した CakePHP のバージョンは 3.8.5 です。
1. 実装方法と使い方
例として、users テーブルに tel_1、tel_2、tel_3 のフィールドがあるものとします。
(varchar型、未入力時はNULL)
Entity/User.php に下記のように追加します。
class User extends Entity
{
// ~~~省略~~~
/**
* TEL番号をハイフンで結合したものを取得
*
* @return string TEL番号
*/
protected function _getTel()
{
if ($this->_properties['tel_1'] === NULL) {
return '';
}
return implode('-', [
$this->_properties['tel_1'],
$this->_properties['tel_2'],
$this->_properties['tel_3']
]);
}
}
あとは、コントローラやテンプレートで通常のフィールドと同様に呼び出すことができます。
(下記コードは実装例です)
public function detail($userId)
{
$user = $this->Users->get($userId);
$this->set(compact('user'));
}
<dt>Tel</dt>
<dd><?= $user->tel ?></dd>
- 仮想プロパティーの生成 (CakePHP3 Cookbook)
- https://book.cakephp.org/3.0/ja/orm/entities.html#entities-virtual-properties
2. toArray() の結果に含める
デフォルトでは、toArray() の結果に仮想フィールドは含まれません。試しに下記のように debug() するとわかります。
public function detail($userId)
{
$user = $this->Users->get($userId)
->toArray();
debug($user);
exit;
}
toArray() の結果に含めるためには、エンティティに下記を追記します。
class User extends Entity
{
// ~~~省略~~~
/**
* toArray()の結果に含める仮想フィールド
*/
protected $_virtual = [
'tel'
];
// ~~~省略~~~
}
これで再度上記の debug() のコードを実行してみてください。
「tel」のフィールドが追加されているはずです。
- 仮想プロパティーが含まれるようにする (CakePHP3 Cookbook)
- https://book.cakephp.org/3.0/ja/orm/entities.html#exposing-virtual-properties
3. 注意点
仮想フィールドを使用する際の注意ですが、これは使用する度に関数が実行されます。今回の例だと $user->tel を呼び出す度に _getTel() が実行されます。仮想フィールドの取得処理が重い場合で、それを複数回呼び出す場合には、一度別の変数に入れるとよさそうです。
また書籍「リーダブルコード」によると get●●●() というメソッドには、軽い処理を書くべきとあります。そもそも重くなる処理は仮想フィールドにせず、Table や Component などに書いた方がいいのかもしれません。