23
21

More than 5 years have passed since last update.

【CakePHP3】Entity の機能について(accessor, virtual fieldsなど)

Last updated at Posted at 2016-11-11

社内用にまとめた内容の転載。

ココらへんの話をします

  • Entityにキャスト、シリアライズといった「変換」を加えた時に走る処理について
  • アクセサー
  • 仮想フィールド

関連: [【CakePHP3】 `Type` の話 ](http://qiita.com/o0h/items/59772ee4e8eb4c91b26f)

そもそも: 配列ではなくオブジェクトを返してくれる有り難さについて

CakePHP2時にはモデルから読み取ったデータは全て配列として扱われ、 スカラ値など(というかboolとstringとnull)の集合でしかありませんでした。
例えば、「Userが登録した年を表示する」場合はこんな感じです。

$this->User->id = 1;
$this->User->field('created');
$reggedYear = CakeTime::format('Y', $regged);

CakePHP3では、テーブルから読み取った内容は Entityというクラスになったので、色々な機能を持てるようになりました。
Entity自体、あるいはEntityの持つプロパティに色々な機能(method)を実装できるということを意味します。
同じく「登録した年」を取るのであれば、これだけでOKです。

$user = $this->Users->get(1);
$reggedYear = $user->created->format('y');

なかなか直感的だな、と個人的には思うのでした。
コレは、「datetime型のカラムである created は、DateTime系の機能があった方が良いよいよね」という事をUsersテーブルが知っているからであり、実際にテーブルから取り出した時点で Cake\I18n\FrozenDate のインスタンスとして利用可能な状態になっています。1

仮想フィールド

CakePHP2でも$Model->virtualFields の機能はありましたが、CakePHP3ではEntityに仮想フィールドを設定していくことになります。
また、これは必ずしも「テーブルにカラムとして存在しない、SQL関数の結果を取り出す」という限定的な用途を意味しません。すなわち、フェッチした結果に対してPHP(CakePHP)側で生成した結果を1つのpropertyとしてセットすることができます。

bookで挙げられている非常にシンプルな例 でいえば、 first_name last_name が実際に存在するUsersTableにおいて、「氏名を扱いやすくする」やり方が詳解されています。

// CakePHP2のvirtualFieldsを使うならこうでしょうか
// モデル側 
class User extends AppModel
{ 
  public $virtualFields = [
    'full_name' => 'CONCAT(last_name, first_name)'
  ];
}

// コントローラー側
$this->User->id = 1;
$fullName = $this->User->field('full_name');

// CakePHP3では、こうです
// Entityにて
protected function _getFullName()
{
  return $this->_properties['last_name'] . $this->_properties['first_name'];
}

// コントローラー側
$fullName = $this->Users->get(1)->full_name;

cf: http://book.cakephp.org/3.0/ja/orm/entities.html#entities-virtual-properties

この様に、

  • Entity上にアクセサーを生やす
  • アクセサーは、 _getHogeHoge という命名でprotectedメソッドを生やす

だけで実現可能です。
また、アクセサーは(仮想フィールドではない)実際に存在するfieldを扱うこともできます。

protected _getLastName()
{
  return "{$this->_properties['last_name']}様";
}

protected _getPoint()
{
  return number_format($this->_properties['point']);
}

これは凶悪な例で実用性がないのですが、 例えばできるよ⚠という事になります。

Entityの出力

加えてCakePHP3では「出力するときにどうするか?」というのを定める機構も備えており、「APIの出力として(エンド)ユーザーに見せられる状態にするのも簡単だよ」となっています。

Kobito.vI9fHx.png

弊社プロダクトでも、実際にこれらの機能を用いて「APIでのレスポンスを打つ時に、コントローラー側の仕事を楽にさせる」という状態を実現させています。

  1. 配列・JSON への変換
  2. プロパティを隠す

配列・JSONへの変換

$entity->toArray()を使うことにより、Entityを連想配列へと変換できます。2
また、 EntityInterfaceはPHPのJsonSerializable インターフェイスを備えているため、「json_encode()をした時に行う処理」を定義可能です。3

$_hiddenの利用

Entityの持つfieldでは、必ずしも(エンド)ユーザーに見せたくないデータが存在することがあります(ex: passwordなど)。
コレに関して、 $Entity->_hidden フィールドに「見せたくないfiedle」の名前をセットしておけば、toArray()jsonSerialize()内で「結果から除外する」処理が走ることになります。
(具体的な処理については、そんなに複雑ではないので実際のコードを覗いてみて下さい)


  1. 「このfieldをこう!」な話は、別途【CakePHP3】 `Type` の話 - Qiitaに書き下してみました。 

  2. 似たメソッドに toList() というのがあり、コレは配列のkeyを0から埋めたものに置き換えてくれることで純粋配列を得ることが出来ます 

  3. 実際にjsonとして吐き出す場合、各propertyに対して toString()が走った上でレンダリングされるので注意 

23
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
21