Eloquent: シリアライズ
イントロダクション
Laravelを使用してAPIを構築する際、モデルやリレーションシップを配列やJSONに変換する必要が頻繁にあります。Eloquentには、これらの変換を行うための便利なメソッドや、モデルのシリアライズ表現に含まれる属性を制御するためのメソッドが含まれています。
EloquentモデルとコレクションのJSONシリアライズをさらに堅牢に処理する方法については、Eloquent APIリソースのドキュメントをご覧ください。
モデルとコレクションのシリアライズ
配列へのシリアライズ
モデルと、そのロード済みリレーションシップを配列に変換するには、toArrayメソッドを使用します。このメソッドは再帰的であるため、すべての属性とすべてのリレーション(リレーションのリレーションも含む)が配列に変換されます。
1use App\Models\User;2 3$user = User::with('roles')->first();4 5return $user->toArray();
attributesToArrayメソッドは、モデルの属性を配列に変換しますが、リレーションシップは変換しません。
1$user = User::first();2 3return $user->attributesToArray();
コレクションインスタンスでtoArrayメソッドを呼び出すことで、モデルのコレクション全体を配列に変換することもできます。
1$users = User::all();2 3return $users->toArray();
JSONへのシリアライズ
モデルをJSONに変換するには、toJsonメソッドを使用します。toArrayと同様に、toJsonメソッドは再帰的であるため、すべての属性とリレーションがJSONに変換されます。PHPがサポートするJSONエンコーディングオプションを指定することもできます。
1use App\Models\User;2 3$user = User::find(1);4 5return $user->toJson();6 7return $user->toJson(JSON_PRETTY_PRINT);
または、モデルやコレクションを文字列にキャストすることもできます。これにより、モデルやコレクションのtoJsonメソッドが自動的に呼び出されます。
1return (string) User::find(1);
モデルとコレクションは文字列にキャストされるとJSONに変換されるため、アプリケーションのルートやコントローラからEloquentオブジェクトを直接返すことができます。Laravelは、Eloquentモデルとコレクションがルートやコントローラから返されると、自動的にJSONにシリアライズします。
1Route::get('/users', function () {2 return User::all();3});
リレーションシップ
EloquentモデルがJSONに変換されると、そのロード済みのリレーションシップは自動的にJSONオブジェクトの属性として含まれます。また、Eloquentのリレーションシップメソッドは「キャメルケース」のメソッド名で定義されていますが、リレーションシップのJSON属性は「スネークケース」になります。
JSONから属性を隠す
モデルの配列やJSON表現に含まれる、パスワードなどの属性を制限したい場合があります。そのためには、モデルに$hiddenプロパティを追加します。$hiddenプロパティの配列にリストされている属性は、モデルのシリアライズ表現に含まれなくなります。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7class User extends Model 8{ 9 /**10 * The attributes that should be hidden for serialization.11 *12 * @var array<string>13 */14 protected $hidden = ['password'];15}
リレーションシップを非表示にするには、リレーションシップのメソッド名をEloquentモデルの$hiddenプロパティに追加します。
または、visibleプロパティを使用して、モデルの配列やJSON表現に含めるべき属性の「許可リスト」を定義することもできます。$visible配列に存在しないすべての属性は、モデルが配列またはJSONに変換されるときに非表示になります。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7class User extends Model 8{ 9 /**10 * The attributes that should be visible in arrays.11 *12 * @var array13 */14 protected $visible = ['first_name', 'last_name'];15}
属性の表示状態を一時的に変更する
特定のモデルインスタンスで、通常は非表示になっている属性をいくつか表示したい場合は、makeVisibleメソッドを使用できます。makeVisibleメソッドはモデルインスタンスを返します。
1return $user->makeVisible('attribute')->toArray();
同様に、通常は表示されているいくつかの属性を非表示にしたい場合は、makeHiddenメソッドを使用できます。
1return $user->makeHidden('attribute')->toArray();
表示または非表示の属性すべてを一時的に上書きしたい場合は、それぞれsetVisibleメソッドとsetHiddenメソッドを使用できます。
1return $user->setVisible(['id', 'name'])->toArray();2 3return $user->setHidden(['email', 'password', 'remember_token'])->toArray();
JSONへ値を追加する
モデルを配列やJSONに変換する際に、データベースに対応するカラムがない属性を追加したい場合があります。そのためには、まずその値のアクセサを定義します。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Casts\Attribute; 6use Illuminate\Database\Eloquent\Model; 7 8class User extends Model 9{10 /**11 * Determine if the user is an administrator.12 */13 protected function isAdmin(): Attribute14 {15 return new Attribute(16 get: fn () => 'yes',17 );18 }19}
アクセサを常にモデルの配列やJSON表現に追加したい場合は、モデルのappendsプロパティに属性名を追加します。属性名は、アクセサのPHPメソッドが「キャメルケース」で定義されていても、通常は「スネークケース」のシリアライズ表現で参照されることに注意してください。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7class User extends Model 8{ 9 /**10 * The accessors to append to the model's array form.11 *12 * @var array13 */14 protected $appends = ['is_admin'];15}
属性がappendsリストに追加されると、モデルの配列とJSONの両方の表現に含まれるようになります。appends配列の属性は、モデルで設定されたvisibleとhiddenの設定も尊重します。
実行時に追加する
実行時に、appendメソッドを使用して、モデルインスタンスに追加の属性を追加するように指示できます。または、setAppendsメソッドを使用して、特定のモデルインスタンスの追加プロパティの配列全体を上書きすることもできます。
1return $user->append('is_admin')->toArray();2 3return $user->setAppends(['is_admin'])->toArray();
日付のシリアライズ
デフォルトの日付フォーマットをカスタマイズする
serializeDateメソッドをオーバーライドすることで、デフォルトのシリアライズ形式をカスタマイズできます。このメソッドは、日付がデータベースに保存される際のフォーマット方法には影響しません。
1/**2 * Prepare a date for array / JSON serialization.3 */4protected function serializeDate(DateTimeInterface $date): string5{6 return $date->format('Y-m-d');7}
属性ごとに日付フォーマットをカスタマイズする
モデルのキャスト宣言で日付フォーマットを指定することにより、個々のEloquentの日付属性のシリアライズ形式をカスタマイズできます。
1protected function casts(): array2{3 return [4 'birthday' => 'date:Y-m-d',5 'joined_at' => 'datetime:Y-m-d H:00',6 ];7}