見出し画像

Laravel: 色んなModelで共通のメソッドをTraitで定義する


この記事が役立ちそうなひと

・色んな Model に似たような処理をたくさん書いてる人
・View にif文を書きすぎて大変な思いをしている人
・いつ Trait を使うべきかよくわからない人

今回やりたいこと

・色んなModel に created_atupdated_at のカラムがある
updated_at があるなら updated_at 更新日として表示したい
updated_at がないときは代わりに created_at 更新日として表示する
・上記の処理を、色んな Model 共通で実装したい

やらなきゃいけないこと

・Trait に共通の処理を書く
・その Trait を Model で使う
・あとは好きなところで Trait の処理を呼ぶ

実際にやってみる

今回は以下のような Model を前提としてみます。

・User(ユーザー)
・Post(投稿)
・Comment(投稿に対するユーザーコメント)

まずプロジェクトの app ディレクトリ直下に Traits フォルダを作ります。

cd path/to/laravel-project/app
mkdir Traits

次に app/Traits の中に Timestamp.php というファイルを作成します。やりたいことの通り、updated_at の有無によって、updated_at か created_at のどちらかを返すだけです。

<?php namespace App\Traits;

trait Timestamp
{
    public function getModifiedAtAttribute()
    {
        return ($this->updated_at) ? $this->updated_at : $this->created_at;
    }
}

これを User.php の Model内で使えるように宣言しましょう。

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Traits\Timestamp; //追加

class User extends Authenticatable
{
    use Notifiable;
    use Timestamp; //追加

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];
}

あとはこんな風に呼び出すだけで、Timestamp.php で定義された getModifiedAtAttribute() の値を取得することができます。

$user = App\Modesl\User::find(1);
echo $user->modified_at; // Timestamp.php の getModifiedAtAttribute() が実行される

共通処理なので、 Post.php Comment.php の Model でも Trait を宣言してみましょう。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\Timestamp; //追加

class Post extends Model
{
    use Timestamp; //追加
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable')->whereNull('parent_id');
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\Timestamp; //追加

class Comment extends Model
{
    use Timestamp; //追加
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function replies()
    {
        return $this->hasMany(Comment::class, 'parent_id');
    }
}

これで全ての Model で、Trait の関数が使えるようになりました。

$user = App\Modesl\User::find(1);
echo $user->modified_at;

$post = App\Modesl\Post::find(1);
echo $post->modified_at;

$comment = App\Modesl\Comment::find(1);
echo $comment->modified_at;

何をしてるのかわからんぞ!

「いきなり getModifiedAtAttributeってなんじゃい!」という方へ説明しますと、これは Laravel の機能の一つである「アクセサ(Accessor」を使っています。詳しくはリファレンスをお読みください。

リファレンスの命名規則にしたがって関数を定義すれば、いい感じに Attributes へ要素を動的に追加できるステキ機能です。これでViewもスッキリしますね!

サンプルソース

上記で使ったソースはGitHubに公開しています。(モデル定義の練習も含めて、こちらのリポジトリをForkさせて頂いています)

cloneしたら .env を書き換えて、下記のコマンドでサンプルデータをもりっと生成して動作確認できます。よかったらどうぞ。

cd path/to/project
composer install
php artisan key:generate
php artisan migrate:refresh --seed


さいごに

サンプルソースが動かなかったらおしえて!なおすよ!

この記事が気に入ったらサポートをしてみませんか?