Laravel Recursive Relationships

Laravel Recursive Relationships

This is how you can use recursive relations:

public function childrenAccounts()
{
return $this->hasMany('Account', 'act_parent', 'act_id');
}

public function allChildrenAccounts()
{
return $this->childrenAccounts()->with('allChildrenAccounts');
}

Then:

$account = Account::with('allChildrenAccounts')->first();

$account->allChildrenAccounts; // collection of recursively loaded children
// each of them having the same collection of children:
$account->allChildrenAccounts->first()->allChildrenAccounts; // .. and so on

This way you save a lot of queries. This will execute 1 query per each nesting level + 1 additional query.

I can't guarantee it will be efficient for your data, you need to test it definitely.


This is for childless accounts:

public function scopeChildless($q)
{
$q->has('childrenAccounts', '=', 0);
}

then:

$childlessAccounts = Account::childless()->get();

Laravel Eloquent query recursive relationship model with pagination

You could use nested set technique to store categories.

Nested set technique allows to retrieve all descendants or ancestors for a certain node in hierarchical structures in one query.

You could try this package: https://github.com/lazychaser/laravel-nestedset. Imho it's the best implentation of nested set in laravel.

Installation and configuring will cost you 10 min.

After that you could retrieve your products something like this:

public function products($slug) 
{
//first query: retrieving current category
$category = CatalogCategory
::where('slug', $slug)
->first();

//second query: retrieving all category descendants and self ids.
$categoryIds = $category
->descendants
->pluck('id')
->push($category->id);

//third query: retrieving all products.
$products = CatalogProduct
::whereIn('parent_id', $categoryIds)
->where('is_active', 1)
->whereDate('active_from', '<=', Carbon::now('Europe/Sofia'))
->orderBy('created_at', 'desc');
->paginate(50);

return view('path_to_view', compact('products', 'category'));
}

Recursive relationship and nested eager loading with constraints

Assuming that HomeCity is one of the related models for GrandChild and the relationship is defined as

//GrandChild.php
public function home_city()
{
return $this->hasMany(HomeCity::class);
}

Then the query to return GrandChild records who live in HomeCity (id_something is a column on home_city table) identified by $id may written as:

public function read($id) 
{

$data = Hierarchy::query()
->whereNull('parent_id')
->with(['children' => function ($query) use($id) {
$query->with(['grandchildren' => function($query) use($id) {
$query->whereHas('home_city', fn($query) => $query->where('id_something', $id);
}]);
}])
->get();
}

laravel recursive relationship with directed acyclic graph

This is how you can use recursive relations:

public function dependsOn()
{
return $this->hasMany('Account', 'task_id','dependent_id');
}

public function dependents()
{
return $this->dependsOn()->with('dependents');

}

Then:

$dependents = Dependents::with('dependents')->first();

$dependents->dependents;

$dependents->dependents->first()->dependents; // .. and so on

Eloquent recursive relation

A collection only solution would be something like this (place the custom macro in a Service Provider of your application):

Collection::macro('whereDeep', function ($column, $operator, $value, $nested) {
return $this->where($column, $operator, $value)->map(function ($x) use ($column, $operator, $value, $nested) {
return $x->put($nested, $x->get($nested)->whereDeep($column, $operator, $value, $nested));
});
});

Then where needed call:

$yourArray->whereDeep('type', '!=', 1, 'children');

On your example, the macro works like this:

  1. Filter all the elements where: type != 1
    (the outer array will beuntouched as both items has type => 0)
  2. For each element of the current array:

    • Retrive the children property and apply the same filtering to this subarray starting with the first point of this instructions.
    • Replace the children property with the new children property just filtered.

Anyways, you should try to deep dive into why the relation filtering doesn't work. That solution would be more efficient if optimized correctly.



Related Topics



Leave a reply



Submit