staudenmeir / laravel-adjacency-list

Recursive Laravel Eloquent relationships with CTEs
MIT License
1.34k stars 109 forks source link

What's the best way to get relationship of all nodes in tree #25

Closed patrickomeara closed 2 years ago

patrickomeara commented 4 years ago

I have a situation where Category has hierarchy and all categories have Posts.

class Category extends Model 
{
    use HasRecursiveRelationships;

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}

class Post extends Model 
{
    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }
}

Is there a relationship I can put on Category to get the posts from itself and it's descendants?

staudenmeir commented 4 years ago

There is no relationship, but I'll look into it.

patrickomeara commented 4 years ago

It would also be handy to get the count of posts cleanly. This is initially why I mentioned joins in https://github.com/staudenmeir/laravel-adjacency-list/issues/29#issuecomment-610696255

Category | Product Count
Electronics           23
-- Radios              4
-- TVs                 5
-- Portable           14
---- iPhone            7
---- Android           7
------ Galaxy          3
------ Pixel           4

Any idea if this is currently possible @staudenmeir ?

staudenmeir commented 4 years ago

It's possible with a custom query:

$cte = Category::select('categories.*')
    ->join('posts', 'posts.category_id', 'categories.id')
    ->unionAll(
        Category::select('categories.*')
            ->join('cte', 'cte.parent_id', 'categories.id')
    );

$posts = DB::table('cte')
    ->withRecursiveExpression('cte', $cte)
    ->selectRaw('COUNT(*)')
    ->whereColumn('cte.id', 'laravel_cte.id');

Category::tree()
    ->select('*')
    ->selectSub($listings, 'posts_count')
    ->get();

For the past few weeks, I've been working on a new relationship type that will allow you to get the descendants' posts recursively and easily count them with withCount(). I should be able to release it soon.

staudenmeir commented 4 years ago

The latest release adds a HasManyOfDescendants relation: https://github.com/staudenmeir/laravel-adjacency-list#custom-relationships

class Category extends Model
{
    use \Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;

    public function recursivePosts()
    {
        return $this->hasManyOfDescendantsAndSelf(Post::class);
    }
}

$recursivePosts = Category::find($id)->recursivePosts;

$categories = Category::withCount('recursivePosts')->get();
SagarNaliyapara commented 4 years ago

AWESOME, Great work 👏 @staudenmeir Thanks a lot

vanthao03596 commented 4 years ago

The latest release adds a HasManyOfDescendants relation: https://github.com/staudenmeir/laravel-adjacency-list#custom-relationships

class Category extends Model
{
    use \Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;

    public function recursivePosts()
    {
        return $this->hasManyOfDescendantsAndSelf(Post::class);
    }
}

$recursivePosts = Category::find($id)->recursivePosts;

$categories = Category::withCount('recursivePosts')->get();

Is it possible to make polymorphic relationship work. I have 4 table categories, categorizables, posts, products. categorizable: category_id: categorizable_type: (products or posts) categorizable_id: (product id or post id)

I want to get all posts or products like "hasManyOfDescendantsAndSelf relationship"

staudenmeir commented 4 years ago

I'll look into it.

staudenmeir commented 2 years ago

@vanthao03596 The latest release adds support for MorphedByManyOfDescendants relationships: https://github.com/staudenmeir/laravel-adjacency-list#morphedbymanyofdescendants

class Category extends Model
{
    use \Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;

    public function recursiveProducts()
    {
        return $this-> morphedByManyOfDescendantsAndSelf(Product::class, 'categorizable');
    }
}