简体   繁体   English

Laravel非递归toArray()

[英]Laravel non-recursive toArray()

Attempting to do both hasMany() and hasOne() relationships between the two tables as I've done before . 正如我之前所做的那样,尝试在两个表之间执行hasMany()hasOne()关系。

I have an Account model which has both users() (one-to-many) and a superUser() (one-to-one), both of which are stored in the built-in User model. 我有一个Account模型,它包含users() (一对多)和superUser() (一对一),两者都存储在内置的User模型中。 As with normal one-to-many relationships, the "many" table ( users ) stores the relationship to the "one", but for the one-to-one relationship, I'm storing the association in the accounts table. 与正常的一对多关系一样,“many”表( users )将关系存储到“one”,但对于一对一关系,我将关联存储在accounts表中。

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');
    });
}

Users 用户

/* 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();
    });
}

Testing the relationships 测试关系

Create a user: 创建用户:

>>> $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,
   }

Create an account with $user as superuser: 使用$user以超级$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 is null because we haven't yet associated $user to the Account : account_id为null,因为我们尚未将$userAccount相关联:

>>> $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},
     },
   }

But once we do this, it hangs: 但是一旦我们这样做,它就会挂起:

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

I'm thinking that this is due to each model pointing towards the other: the superuser of the Account loads the User which loads the Account ad infinitum. 我认为这是由于每个模型都指向另一个模型: Account的超级User加载了无限加载AccountUser Is this a bug in toArray() or simply normal behavior that I have to watch out for? 这是toArray()的错误还是我必须注意的正常行为? Or am I doing it wrong? 或者我做错了吗?

In the Laravel codebase, toArray() is a convenience function merging the results of attributesToArray() and relationsToArray() into a single merged array : 在Laravel代码库中, toArray()是一个便利函数,它将attributesToArray()relationsToArray()的结果合并为一个合并的数组

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

As I suspected, relationsToArray() calls toArray() on every arrayable relationship, causing the infinite recursion : 我怀疑, 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
        }

    ...

If all that is needed is the attributes (as in my case), calling attributesToArray() on the model is a good workaround: 如果只需要属性(如我的情况),在模型上调用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,
   ]

EDIT: Also this behavior is by design, as the documentation explicitly states recursion: 编辑:此行为也是设计,因为文档明确说明了递归:

This method is recursive , so all attributes and all relations ( including the relations of relations ) will be converted to arrays (emphasis mine) 这个方法是递归的 ,所以所有属性和所有关系( 包括关系关系 )都将被转换为数组(强调我的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM