そこで、次の移行を検討してください。
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAdventureLogs extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('adventure_logs', function (Blueprint $table) {
$table->id();
$table->bigInteger('character_id')->unsigned();
$table->foreign('character_id')
->references('id')->on('characters');
$table->bigInteger('adventure_id')->unsigned();
$table->boolean('in_progress')->nullable()->default(false);
$table->boolean('complete')->nullable()->default(false);
$table->integer('last_completed_level')->nullable();
$table->json('logs')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('adventure_logs');
}
}
私が作成した json 列に注目してください。 $table->json('logs')->nullable();
ここから、モデルを作成しましょう:
use Illuminate\Database\Eloquent\Model;
class AdventureLog extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'character_id',
'adventure_id',
'complete',
'in_progress',
'last_completed_level',
'logs',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'complete' => 'boolean',
'in_progress' => 'boolean',
'last_completed_level' => 'integer',
];
public function getLogsAttribute($value) {
return json_decode(json_decode($value));
}
public function setLogsAttribute($value) {
$this->attributes['logs'] = json_encode($value);
}
public function character() {
return $this->belongsTo(Character::class);
}
public function adventure() {
return $this->hasOne(Adventure::class, 'id', 'adventure_id');
}
}
このメソッドに注目してください:
public function getLogsAttribute($value) {
return json_decode(json_decode($value));
}
これは間違っています。当然です。
保存される json は次のとおりです。
[{"adventure":"sample"}]
$character->adventureLogs()->first()->logs を呼び出すと、次の結果が得られます: [{"adventure":"sample"}]。
しかし、関数を想定どおりに変更すると次のようになります。
public function getLogsAttribute($value) {
return json_decode($value);
}
次に、「[{"adventure":"sample"}]" を取得します。
次のようにしてデータを保存します。
AdventureLog::create([
// .... Other attributes
'logs' => ['adventure' => 'sample']
]);
では、最初の json_decode を別の json_decode にラップしなければならないという点で、私は何を間違っているのでしょうか?そんなことをする必要はないはずです。
その関数で単純な var_dump($value) を実行して、実際にそのフィールドに何が入っているかを確認できますか
– リッグスフォリー
2020 年 9 月 3 日 17:29
@RiggsFolly これはダンプで示される内容です: ""[{\"adventure\":\"sample\"}]""
– TheWebs
2020 年 9 月 3 日 17:34
では、getLogsAttribute($value) はどこで呼び出されるのでしょうか?そして、その関数に渡す前に $value をどこから取得しますか?
– リッグスフォリー
2020 年 9 月 3 日 17:37
@RiggsFolly モデルのドキュメント属性を読みます。
– TheWebs
2020 年 9 月 3 日 19:02
------------------------
ドキュメントより (https://laravel.com/docs/7.x/eloquent-mutators#array-and-json-casting):
...データベースにシリアル化された JSON を含む JSON または TEXT フィールド タイプがある場合、その属性にキャストされた配列を追加すると、Eloquent モデルでアクセスするときに属性が自動的に PHP 配列に逆シリアル化されます。
それでは追加するだけです
protected $casts = [
...
'logs' => 'array',
];