LoginSignup
3
1

More than 1 year has passed since last update.

Laravel8以降でModelをjson化するときにaccessorにしてるプロパティを含めたいときの件

Posted at

はじめに

LaravelでModelといえばDBと一対一になってることが多いと思うんですが、たまにDBのテーブルのカラムにはないものを出力したいときってありますよね。
例えば住所とか顕著ですかね。

かんたんに一例としてこんな感じの users テーブルがあったとします。

物理名 論理名
id ID bigint(auto_increment)
name 名前 varchar
zip_code 郵便番号 varchar
prefecture 県名 varchar
city 市町村名 varchar
address 番地 varchar

それに対応する class はこんな感じだったりするわけじゃないですか。

App/Models/User.php
namespace App\Models;

class User extends Authenticatable
{

}

そこで、住所を全部表示させるときにbladeなんかにこういう書き方するじゃないですか。

<p>住所: {{ $user->zip_code }}{{ $user->prefecture }}{{ $user->city }}{{ $user->address }}</p>

これが1箇所ならまあ別にいいかなって思うんですが、複数出てくると指がつったりしますよね。
そんなときに accessor という便利テクをLaravelではよく使うことがあります。
DBにはないカラムをさもあるかのように出力させるやつですね。
これはModelに get{架空のカラム名}Attribute() っていうメソッドを追加してやることで実現します。
今回は住所全部なので getFullAddressAttribute() っていうメソッドを作ることにします。

App/Models/User.php
namespace App\Models;

class User extends Authenticatable
{
    public function getFullAddressAttribute(): string
    {
        return $this->zip_code . $this->prefecture . $this->city . $this->address;
    }
}

で、実際bladeに記述するときに

<p>住所: {{ $user->full_address }}</p>

ってやるとうまくいくってやつです。みんなよく知っていると思います。

ただこれ、vueコンポーネントのpropsに

<div id="app">
    <User
        users="@json($model)"
    />
</div>

みたいに雑に渡したいときとかにうまくいきません。まあそりゃ存在しないカラムですもんね。
ただ、accessorもさも普通にあるカラムのように渡してーなーって思うのが人情ってやつですよね。

力技でなんとかするパターン

bladeテンプレートに渡す前にModelをループしてねじ込むという方法があります。

$users = User::all();
if($users->count() > 0){
    foreach($users as $k => $u){
        $users[$key]->full_address = $u->full_address;
    }
}

これでできはするけど……んーーーー、もやもやしますね。

toArrayメソッドをオーバーライドしてどうにかするパターン

いにしえのQiita記事にはこんなのありました。

こちらはModel側のtoArray()メソッドをオーバーライドする一工夫入れるやつです。

App/Models/User.php
namespace App\Models;

class User extends Authenticatable
{
    public function getFullAddressAttribute(): string
    {
        return $this->zip_code . $this->prefecture . $this->city . $this->address;
    }

    public function toArray()
    {
        return array_merge(parent::toArray(), ['full_address' => $this->full_address]);
    }
}

なるほど……とはいえ、こんないかにも普段遣いしたいような機構をFW側で実装してないなんてないよなあ……って気持ちにもなります。

ドキュメントをちゃんと読め

まあ、ドキュメントちゃんと読むと書いてあるんですよね。
https://readouble.com/laravel/8.x/ja/eloquent-serialization.html#appending-values-to-json

アクセサを作成したら、モデルのappendsプロパティに属性名を追加します。

appends......!?

App/Models/User.php
namespace App\Models;

class User extends Authenticatable
{
    $appends = [
        'full_address'
    ];

    public function getFullAddressAttribute(): string
    {
        return $this->zip_code . $this->prefecture . $this->city . $this->address;
    }
}

なんとこれだけでいいのです!
どうもこれ、ドキュメント遡るとLaravel5.1の頃からあった機能のようです。
くっそー、知らんかった! このページ穴が空くほど呼んでたつもりだったのに!

おわりに

まー、Laravelにはまだまだ知らない(気づいてない?)機能が色々ありそうですね!
なんかまた思いついたり見つけたりしたら投稿します!

3
1
1

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
3
1