全16実例!Laravelのモデルで使えるメンバ変数

さてさて、Laravelのモデル(Eloquent)といえば開発者が喜ぶ「かゆいところに手が届く」機能がたくさんついているのですが、今回はその中でも「メンバ変数」にフォーカスを当ててみます。

メンバ変数で有名なものでいうと$guarded$castsがありますが、これらの変数を指定しておくだけで、モデルに様々な設定や制限をつくることができるので、よりフレキシブルな開発を進められます。

そのため、知っておいて損はないで機能と言っていいでしょう。ということで、ぜひLaravelを勉強中の方は参考にしてみてくださいね。

実行環境: Laravel 5.7, MySQL 5.7

メンバ変数の設定方法

まずは設定方法ですが、とても簡単です。
次のようにモデルのクラス内に変数を指定するだけです。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    protected $guarded = ['id'];
}

この時注意が必要なのが、protectedなどのアクセス制御部分です。実は設定が可能なメンバ変数はすでに他の所で定義されています。そして、我々がメンバ変数を指定するとデータを上書きをする形になるので、protectedなどは元の定義に合わせる必要があるというわけですね。

Eloquentモデルで使えるメンバ変数

$guarded でフィールドへの代入を拒否する

create()でデータを追加する際に、値を代入「させない」フィールドを設定します。(つまりそれ以外は代入が許可されます)

実際の例を見てみましょう。

protected $guarded = ['id'];

まず$guardedを使ってidフィールドを守る設定にします。
そして、次のようにデータ追加してみましょう。

\App\Item::create([
    'id' => 9999,
    'name' => '商品名'
]);

これを実行するとDBはこうなります。

id9999に指定しましたが、実際に登録されたidはオートインクリメントされた番号になっています。

※ ただし、この設定はsave()には適用されません。

※ なお、create()を実行する場合、必ず$guarded$fillableを指定しておく必要があります。

$fillable でフィールドへの代入を許可する

create()でデータを追加する際に、値を代入を許可するフィールドを設定します。(つまりそれ以外は代入が拒否されます)

内容としては、$guardedの逆になりますのでそちらを参照してください。

$casts でデータを自動変換する

DBから取得したデータを自動変換する変数です。詳しくは、全12種類!Laravel5.6のキャスト(型変換)実例をご覧ください。

$dispatchesEvents で各イベントを設定する

DBに各操作が行われたときに実行される「イベント」を設定する変数です。(以前は$eventsでしたが名称変更されました)
例えば、注文データが登録されたら受注メールを送信するなどの場合に使えます。

設定できるイベントは次のとおりです。

  • retrieved ・・・ データが取得されたとき
  • creating ・・・ データを新しく登録する直前
  • created ・・・ データを新しく登録した直後
  • updating ・・・ データを更新する直前
  • updated ・・・ データを更新した直後
  • saving ・・・ データを保存する直前(つまり、creating & updating)
  • saved ・・・ データを保存した直後(つまり、created & updated)
  • deleting ・・・ データを削除する直前
  • deleted ・・・ データを削除した直後
  • restoring ・・・ ソフトデリートを元に戻す直前
  • restored ・・・ ソフトデリートを元に戻した直後

では今回は実際にsavedイベントを作ってみます。
まず次のコマンドでItemSavedというイベントを作成します。

php artisan make:event ItemSaved

すると、app/Events/ItemSaved.phpというファイルができているのでこれを開いてコンストラクタの引数を次のようにすれば該当するItemデータが取得できます。

public function __construct(Item $item)
{
    echo '保存されました!';
}

続いてこのイベントを$dispatchesEventsへ登録します。

protected $dispatchesEvents = [
    'saved' => \App\Events\ItemSaved::class
];

こうすることで、データが保存されたときに先ほどのコードが実行されます。

$timestamps で日時データを設定する

LaravelのDBテーブルは初期状態で次の2つの日時データが用意されています。

  • created_at ・・・ データが作成された日時
  • updated_at ・・・ データが更新された日時

ただ、この日時情報は例えば都道府県のマスターデータなどではあまり必要ないことが多いため、以下のように省略したテーブル構造にすることもあります。

その場合には、次のようにモデル内で$timestampsを指定しておきましょう。

public $timestamps = false;

ちなみに、もし2つの日時フィールドが無いのにデータ登録しようとすると次のようなエラーが発生します。

Column not found: 1054 Unknown column 'updated_at' in 'field list'

$appends で追加データを常に呼び出す

例えば、DBテーブルにpriceという金額が入るフィールドがあり、ここに10000というデータが入っていたとします。

この場合、金額を表示することになるわけですが、10000ではなく、10,000円と表示したくありませんか??

そんな場合はaccessorを作っておくといつでも加工データを取得できます(詳しくは、全15件!Laravel・使い回しできるAccessor実例をご覧ください)。そして、このaccessorを常に呼び出したい場合に$appendsを使うことになります。

では実際に見てみましょう。
以下のようにしてデータを取得してみます。

$item = \App\Item::first();

まずは、$appendsがない無い場合です。

もちろんこの中には通常のデータしか入ってきません。
では次に$item->yen_priceとしてデータ取得できるaccessorを作って、これを$appendsに登録してみましょう。

protected $appends = [
    'yen_price'
];

public function getYenPriceAttribute() {

    return number_format($this->price) .'円';

}

すると、次のようにいつでもyen_priceがデータ内に用意されることになります。

そのため、Ajaxでデータを返す場合などに重宝するでしょう。

$dateFormat で日付データのフォーマットを指定する

初期状態でcreated_atupdated_atなどの日時フィールドは、2000-01-01 00:00:00というような形式をとっています。

ただ、もしかするとUnixタイムスタンプを使いたい場合もあるでしょう。
そんな場合は$dateFormatが使えます。

protected $dateFormat = 'U';

なお、この場合フィールドは数値型でないといけませんので、以下のようにマイグレーションを変更しておく必要があります。

Schema::create('items', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    // $table->timestamps();
    $table->integer('created_at');
    $table->integer('updated_at');
});

実際にデータを保存したものがこちらです。

$dates で日時データをCarbonインタンスへ自動変換する

初期状態で、created_atupdated_atのデータは自動的に日付パッケージCarbonのインスタンスで取得されるようになっていますが、もし他にもCarbonインスタンス化したい場合は$datesを使いましょう。

では実際の例です。
もし次のように販売を開始した日時released_atというデータがあるとしましょう。

そして、この販売開始日時をCarbonインスタンス化するにはこのようにします。

protected $dates = [
    'created_at',
    'updated_at',
    'released_at'
];

すると、取得したデータはCarbonインスタンスになります。

$item = \App\Item::first();
$released_at = $item->released_at; // Carbonインスタンス

$hidden でデータ取得しないフィールドを指定する

例えば、「売値(price)」と「仕入れ値(cost_price)」があり、仕入れ値は社外秘で、絶対に外に出すべきではないデータだとします。

この場合、もちろん仕入れ値を表示しないよう注意していればいいわけですが、やはり人間ですからこの作業を忘れてしまうかもしれません。そんな場合は$hiddenを指定しておいて、前もってデータ取得をしないようにしておけばいいでしょう。

protected $hidden = [
    'cost_price'
];

実際に実行した結果はこうなります。(cost_priceは存在していません)

$visible でデータ取得するフィールドを指定する

$hiddenとは逆に、データ取得するフィールドを指定します。
次の例では指定した3つのフィールドしかデータを取得しません。

protected $visible = [
    'id',
    'name',
    'price'
];

実行結果はこうなります。

$perPage でpaginate()のデフォルト件数を変更する

例えば、以下のようにページ処理ができるデータ取得をする場合です。(引数は空)

$item = \App\Item::paginate();

初期状態では15件ずつデータ取得するようになっていますが、$perPageを指定するとこの件数を変更することができます。

protected $perPage = 5;

※ なお、以下のように件数を直接指定するとそちらが優先されます。

$item = \App\Item::paginate(50);

$table でテーブル名を指定する

例えば、モデル名がItemという名前の場合、初期状態ではitemsというDBテーブルが参照されるようになっています。

ただ、もしかすると過去に作られたテーブルを参照したい場合や、もしくは別システムのテーブルを参照する場合もあるかもしれません。その場合、以下のように$tableを指定すると自動でそちらを参照するようになります。

protected $table = 'old_items';

$touches で親テーブルの更新日時を自動更新する

例えば、ブログ記事を保存するPostというモデルがあり、各記事に対するコメントはPostCommentモデルが担当しているとします。

そして、もしかするとコメントが保存されたら、親テーブルの記事データも更新日時(updated_at)を新しくしたい場合もあるでしょう。
例えば、記事の「最終更新日時」を表示したい場合などですね。

この場合は、以下のように$touchesへリレーションシップを登録します。

class PostComment extends Model
{
    protected $touches = ['post'];

    public function post()
    {
        return $this->belongsTo('App\Post');
    }

$primaryKey でプライマリーキーを変更する

protected $primaryKey = 'product_id';

$incrementing でオートインクリメントをしないようにする

public $incrementing = false;

$keyType でプライマリーキーの型を指定する

protected $keyType = 'string';