CakePHP3.8 と Laravel7.x の「書き方」の違い ~ORM周りその2~

# CakePHP3.8 と Laravel7.x の「書き方」の違い ~ORM周りその2~

今回はアクセサー周り

前: [クエリの要約](https://qiita.com/yokocho-comachi/items/30330f24dbdcc0c03720)

# そもそもクエリオブジェクトの返り値が別

## １件取得

* CakePHP

Table クラスとは別に、Entity クラスがあり、それが返ってくる

```php
// \App\Model\Entity\Users が返ってくる(Table クラスとは別)
$veteranHyphen = $usersTable->find('hyphen')->find('veteran')->first();
```

* Laravel

Model が Cake で言う Table, Entity の役割を持っている。
なので Model 自身のインスタンスが返ってくる。

```php
// \App\Users が返ってくる
$veteranHyphen = Users::hyphen()->veteran()->first();
```

## 複数件取得

* CakePHP

Collection インスタンスが返ってくる。
Collection の要素には Entity インスタンスが入っている。

```php
// \Cake\Collection\Collection
$veteranHyphenUsers = $usersTable->find('hyphen')->find('veteran')->all();
foreach ($veteranHyphenUsers as $veteranHyphenUser) // 中身は \App\Model\Entity\Users
```


* Laravel

Collection インスタンスが返ってくる。
Collection の要素には Model インスタンスが入っている。

```php
// \Illuminate\Database\Eloquent\Collection
$veteranHyphenUsers = Users::hyphen()->veteran()->get();
foreach ($veteranHyphenUsers as $veteranHyphenUser) // 中身は \App\Users
```

# アクセサー

fetch したレコードの値を、参照するときにフォーマットすることができます。
DB からとってくるとき、ちょっとした整形が面倒くさいなぁ(CASE文大量など)といったときに便利です。

個人的には表示系をここに書いても良いんじゃないかなって思います。
(郵便番号 => 住所 とか 0,1 => 男女 とか)

* CakePHP

CakePHP では「仮想プロパティ」と呼ばれています。
Entity クラスの中で、「_get」+ {仮想プロパティ名}で定義できます。

```php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class User extends Entity
{
    protected function _getFullName()
    {
        return $this->_properties['first_name'] . '  ' .
            $this->_properties['last_name'];
    }

}

// 参照する時
echo $user->full_name; // 横丁 小町
```

仮想プロパティはデータを保存するときには干渉しません。

* Laravel

Laravel では「アクセサ」と呼ばれています。
get + {プロパティ名} + Attribute で定義できます。

```php
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザーのフルネームを取得
     *
     * @return string
     */
    public function getFullNameAttribute()
    {
        return $this->first_name . '  ' .
            $this->last_name';
    }
}

// 参照する時
echo $user->full_name; // 横丁 小町
```

# 保存時にも影響を与えたい時

入力した値を、自動的に保存時にフォーマットしてほしい時

* CakePHP3

ややこしいですが、CakePHP ではこれを **アクセサ** と呼びます。
値を参照するときにはもちろん、DBにデータを保存するときにも適用されます。

**値を保存する時、値を参照する時、両方向に影響があるので、冪等性が担保されていなければなりません**

```php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Article extends Entity
{
    protected function _getTitle($title)
    {
        return ucwords($title);
    }
}
```

* Laravel

Laravel では、**カスタムキャスト** でこれを実現します。
CakePHPと違って、値を取得する時、保存する時で処理を分けられるので、冪等性をそんなに気にしなくても良いです。

キャストを定義して、

```php
namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Ucwords implements CastsAttributes
{
    /**
     * 指定された値をキャストする
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return array
     */
    public function set($model, $key, $value, $attributes)
    {
        return ucwords($value);
    }
}
```

Model で設定

```php
namespace App;

use App\Casts\Ucwords;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    /**
     * キャストする属性
     *
     * @var array
     */
    protected $casts = [
        'title' => Ucwords::class,
    ];
}
```

#　おわりに

フレームワークごとに単語を統一してほしい。