Laravel Eloquent关联层级转换:将Person层级转为En层级
Got it, let's tackle this structure reversal with your existing Eloquent collections. Here's how you can flip the hierarchy so you can access properties like $en->accounts[0]->person->p1 seamlessly.
Step 1: Ensure Eager Loading (Avoid N+1 Queries)
First, make sure your $persons collection has all necessary relationships preloaded to prevent unnecessary database hits. If you haven't already, fetch the collection with nested eager loading:
$persons = Person::with('accounts.en')->get();
This loads all related Account and En models upfront, making the rest of the process efficient.
Step 2: Reorganize the Collection Hierarchy
We'll iterate through your existing $persons and their accounts, then build a new collection centered around En models, linking each to its associated Accounts and the parent Person:
// Initialize a collection to map En IDs to their instances with relationships $enCollection = collect(); foreach ($persons as $person) { foreach ($person->accounts as $account) { $en = $account->en; // If this En isn't in our collection yet, set it up with an empty accounts collection if (!$enCollection->has($en->getKey())) { // Add an empty "accounts" collection to the En instance $en->accounts = collect(); $enCollection->put($en->getKey(), $en); } // Attach the parent Person to the Account $account->person = $person; // Push the Account to the corresponding En's accounts collection $enCollection->get($en->getKey())->accounts->push($account); } } // Extract the final En collection (values() removes the ID keys) $ens = $enCollection->values();
Now you can access properties exactly as you wanted:
// Example access echo $ens[0]->e1; // Direct En property echo $ens[0]->accounts[0]->a1; // Account property echo $ens[0]->accounts[0]->person->p1; // Person property through Account
Step 3: (Optional) Define Permanent Reverse Relationships
For a more "native" Eloquent experience, define the reverse relationships in your models so you can query this structure directly from the database without manually restructuring collections:
In your En model:
public function accounts() { return $this->hasMany(Account::class); } // Optional: If you need direct access from En to Person (bypassing Account) public function persons() { return $this->hasManyThrough(Person::class, Account::class); }
In your Account model:
public function person() { return $this->belongsTo(Person::class); }
With these relationships defined, you can fetch the structured collection directly like this:
$ens = En::with('accounts.person')->get();
内容的提问来源于stack exchange,提问作者Mostafa Abedi

