Laravel нерекурсивный toArray () - PullRequest
0 голосов
/ 31 мая 2019

Попытка установить отношения hasMany() и hasOne() между двумя таблицами , как я делал раньше .

У меня есть модель Account, в которой есть users() (один-ко-многим) и superUser() (один-к-одному), оба из которых хранятся во встроенной модели User , Как и в случае обычных отношений «один ко многим», таблица «многие» (users) хранит отношение к «одному», но для отношения «один к одному» я сохраняю связь в accounts таблица.

Счета:

/* model */
public function superUser()
{
    return $this->hasOne(User::class, 'id', 'superuser_id');
}

public function users()
{
    return $this->hasMany(User::class);
}

/* migration */
public function up()
{
    Schema::create('accounts', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->bigInteger('superuser_id')->unsigned();
        $table->string('name');
        $table->timestamps();

        $table->foreign('superuser_id')
            ->references('id')
            ->on('users')
            ->onDelete('cascade');
    });
}

Пользователи

/* model */
public function account()
{
    return $this->belongsTo(Account::class);
}

/* migration */
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->bigInteger('account_id')->unsigned()->index()->nullable();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

Тестирование отношений

Создать пользователя:

>>> $user = factory(App\User::class)->create()
=> App\User {#3014
     name: "Rose Grant II",
     email: "ernser.thomas@example.com",
     email_verified_at: "2019-05-31 15:38:32",
     updated_at: "2019-05-31 15:38:32",
     created_at: "2019-05-31 15:38:32",
     id: 23,
   }

Создать учетную запись с $user в качестве суперпользователя:

>>> $account = factory(App\Account::class)->create(['superuser_id' => $user]);
=> App\Account {#3024
     name: "Kuhic-Price",
     superuser_id: 23,
     updated_at: "2019-05-31 15:39:11",
     created_at: "2019-05-31 15:39:11",
     id: 17,
   }
>>> $account->superUser
=> App\User {#3011
     id: 23,
     account_id: null,
     name: "Rose Grant II",
     email: "ernser.thomas@example.com",
     email_verified_at: "2019-05-31 15:38:32",
     api_token: null,
     created_at: "2019-05-31 15:38:32",
     updated_at: "2019-05-31 15:38:32",
   }

account_id равно нулю, поскольку мы еще не связали $user с Account:

>>> $account->superUser->account()->associate($account)->save()
=> true
>>> $account->superUser
=> App\User {#3011
     id: 23,
     account_id: 17,
     name: "Rose Grant II",
     email: "ernser.thomas@example.com",
     email_verified_at: "2019-05-31 15:38:32",
     api_token: null,
     created_at: "2019-05-31 15:38:32",
     updated_at: "2019-05-31 15:43:55",
     account: App\Account {#3024
       name: "Kuhic-Price",
       superuser_id: 23,
       updated_at: "2019-05-31 15:39:11",
       created_at: "2019-05-31 15:39:11",
       id: 17,
       superUser: App\User {#3011},
     },
   }

Но как только мы это сделаем, он зависнет:

>>> $account->toArray()
^C

Я думаю, что это связано с тем, что каждая модель указывает на другую: суперпользователь Account загружает User, который загружает Account до бесконечности. Это ошибка в toArray() или просто нормальное поведение, за которым я должен следить? Или я делаю это неправильно?

1 Ответ

0 голосов
/ 31 мая 2019

В кодовой базе Laravel toArray() - это удобная функция, объединяющая результаты attributesToArray() и relationsToArray() в единый объединенный массив :

public function toArray()
{
    return array_merge($this->attributesToArray(), $this->relationsToArray());
}

Как я и подозревал, relationsToArray() вызывает toArray() при каждом массивном отношении, вызывает бесконечную рекурсию :

public function relationsToArray()
{
    $attributes = [];

    foreach ($this->getArrayableRelations() as $key => $value) {
        // If the values implements the Arrayable interface we can just call this
        // toArray method on the instances which will convert both models and
        // collections to their proper array form and we'll set the values.
        if ($value instanceof Arrayable) {
            $relation = $value->toArray();   // <-- here's the recursive call
        }

    ...

Если все, что нужно, - это атрибуты (как в моем случае), то вызов attributesToArray() для модели - хороший обходной путь:

>>> $account->attributesToArray()
=> [
     "name" => "Kuhic-Price",
     "superuser_id" => 23,
     "updated_at" => "2019-05-31 15:39:11",
     "created_at" => "2019-05-31 15:39:11",
     "id" => 17,
   ]

РЕДАКТИРОВАТЬ: Это поведение также предусмотрено проектом, поскольку документация явно заявляет рекурсия:

Этот метод является рекурсивным , поэтому все атрибуты и все отношения (, включая отношения отношений ) будут преобразованы в массивы (выделено мной)

...