Laravel非递归toArray()

时间:2019-05-31 16:30:55

标签: php laravel eloquent

尝试在两个表as I've done before之间建立hasMany()hasOne()关系。

我有一个Account模型,该模型同时具有users()(一对多)和superUser()(一对一),两者均存储在内部-在User模型中。与普通的一对多关系一样,“许多”表(users)将关系存储为与“一个”关系,但是对于一对一关系,我将关联存储在{ {1}}表。

帐户:

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中的错误,还是我必须提防的正常行为?还是我做错了?

1 个答案:

答案 0 :(得分:0)

在Laravel代码库中,toArray()是一个便捷函数,它将attributesToArray()relationsToArray()的结果合并到single merged array中:

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

我怀疑,relationsToArray()在每个可排列的关系causing the infinite recursion上调用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,
   ]

编辑:此行为也是设计使然,因为文档明确states递归:

  

此方法是递归的,因此所有属性和所有关系(包括关系的关联)都将转换为数组(强调我的意思)