#php #laravel
#php #laravel
Вопрос:
Итак, рассмотрим следующую миграцию:
use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
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 IlluminateDatabaseEloquentModel;
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
в другое? Мне не нужно было этого делать.
Комментарии:
1. Можете ли вы сделать простое
var_dump($value)
в этой функции, чтобы мы могли видеть, что на самом деле в этом поле2. @RiggsFolly это то, что показывает дамп:
""[{"adventure":"sample"}]""
3. Итак, где
getLogsAttribute($value)
вызывается? И откуда вы беретесь$value
, прежде чем передать его этой функции4. @RiggsFolly Прочитайте атрибуты документов для моделей.
Ответ №1:
Из документов (https://laravel.com/docs/7.x/eloquent-mutators#array-and-json-casting ):
… если ваша база данных имеет тип JSON или ТЕКСТОВОГО поля, который содержит сериализованный JSON, добавление приведения массива к этому атрибуту автоматически десериализует атрибут в массив PHP при доступе к нему в вашей модели Eloquent
Так что просто добавьте
protected $casts = [
...
'logs' => 'array',
];