九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、Laravelのモデル(Eloquent)といえば開発者が喜ぶ「かゆいところに手が届く」機能がたくさんついているのですが、今回はその中でも「メンバ変数」にフォーカスを当ててみます。
メンバ変数で有名なものでいうと$guarded
や$casts
がありますが、これらの変数を指定しておくだけで、モデルに様々な設定や制限をつくることができるので、よりフレキシブルな開発を進められます。
そのため、知っておいて損はないで機能と言っていいでしょう。ということで、ぜひLaravel
を勉強中の方は参考にしてみてくださいね。
実行環境: Laravel 5.7, MySQL 5.7
目次
- 1 メンバ変数の設定方法
- 2 Eloquentモデルで使えるメンバ変数
- 2.1 $guarded でフィールドへの代入を拒否する
- 2.2 $fillable でフィールドへの代入を許可する
- 2.3 $casts でデータを自動変換する
- 2.4 $dispatchesEvents で各イベントを設定する
- 2.5 $timestamps で日時データを設定する
- 2.6 $appends で追加データを常に呼び出す
- 2.7 $dateFormat で日付データのフォーマットを指定する
- 2.8 $dates で日時データをCarbonインタンスへ自動変換する
- 2.9 $hidden でデータ取得しないフィールドを指定する
- 2.10 $visible でデータ取得するフィールドを指定する
- 2.11 $perPage でpaginate()のデフォルト件数を変更する
- 2.12 $table でテーブル名を指定する
- 2.13 $touches で親テーブルの更新日時を自動更新する
- 2.14 $primaryKey でプライマリーキーを変更する
- 2.15 $incrementing でオートインクリメントをしないようにする
- 2.16 $keyType でプライマリーキーの型を指定する
メンバ変数の設定方法
まずは設定方法ですが、とても簡単です。
次のようにモデルのクラス内に変数を指定するだけです。
<?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はこうなります。
id
を9999
に指定しましたが、実際に登録された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
に登録してみましょう。
/app/Item.php
protected $appends = [ 'yen_price' ]; public function getYenPriceAttribute() { return number_format($this->price) .'円'; }
すると、次のようにいつでもyen_price
が入ってくることになります。
そのため、Ajax
でデータを返す場合などに重宝するでしょう。
$dateFormat で日付データのフォーマットを指定する
初期状態でcreated_at
やupdated_at
の日時フィールドは、2000-01-01 00:00:00
というY-m-d H:i:s
の形式でデータ保存しています。
ただ、もしかすると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_at
とupdated_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インスタンス
例えば、「売値(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';