Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Add Docs
Rinvex Categories
https://github.com/rinvex/laravel-categories
Admin
Rinvex Categories is a polymorphic Laravel package for category management, allowing easy
...
Tokens:
12,799
Snippets:
103
Trust Score:
9.6
Update:
3 months ago
Context
Skills
Chat
Benchmark
92.5
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Rinvex Categories Rinvex Categories is a polymorphic Laravel package for hierarchical category management. It enables you to categorize any Eloquent model with ease, utilizing Nested Sets for tree structures, automatic slug generation via Spatie's Sluggable package, and multi-language support through Spatie's Translatable package. The package provides a complete category management solution with parent-child relationships, breadcrumbs, and tree operations. The package integrates seamlessly with Laravel 10/11 applications through a service provider that auto-registers models, migrations, and artisan commands. Categories support soft deletes, validation rules, and polymorphic many-to-many relationships, allowing any model to be associated with multiple categories. The nested set implementation enables efficient queries for ancestors, descendants, siblings, and tree traversal operations. ## Installation Install the package and run migrations to set up the category tables. ```bash # Install via Composer composer require rinvex/laravel-categories # Publish config and migrations php artisan rinvex:publish:categories # Run migrations php artisan rinvex:migrate:categories ``` ## Configuration The package configuration allows customization of table names and the Category model class. ```php // config/rinvex.categories.php return [ // Enable/disable automatic migration loading 'autoload_migrations' => true, // Database table names 'tables' => [ 'categories' => 'categories', 'categorizables' => 'categorizables', ], // Model class (can be extended) 'models' => [ 'category' => \Rinvex\Categories\Models\Category::class, ], ]; ``` ## Making a Model Categorizable Add the `Categorizable` trait to any Eloquent model to enable category relationships. ```php <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Rinvex\Categories\Traits\Categorizable; class Post extends Model { use Categorizable; protected $fillable = ['title', 'content']; } // Now you can use category methods on Post $post = Post::find(1); $post->categories; // Get attached categories $post->attachCategories([1, 2, 3]); // Attach by IDs $post->syncCategories(['tech', 'news']); // Sync by slugs ``` ## Creating Categories Create categories with translatable names and optional descriptions. Categories auto-generate slugs. ```php <?php // Create a root category with translations $category = app('rinvex.categories.category')->create([ 'name' => [ 'en' => 'Technology', 'ar' => 'تكنولوجيا', ], 'description' => [ 'en' => 'All tech-related content', 'ar' => 'كل المحتوى المتعلق بالتكنولوجيا', ], ]); // Slug auto-generated: 'technology' // Create with custom slug $category = app('rinvex.categories.category')->create([ 'name' => ['en' => 'Web Development'], 'slug' => 'web-dev', ]); // Create nested categories (tree from array) $parent = app('rinvex.categories.category')->create([ 'name' => ['en' => 'Programming'], 'children' => [ [ 'name' => ['en' => 'PHP'], 'children' => [ ['name' => ['en' => 'Laravel']], ['name' => ['en' => 'Symfony']], ], ], ['name' => ['en' => 'JavaScript']], ], ]); // Creates: Programming -> PHP -> Laravel, Symfony // -> JavaScript ``` ## Attaching Categories to Models Multiple methods exist to attach categories using IDs, slugs, or model instances. ```php <?php $post = Post::find(1); // Attach by single ID $post->attachCategories(1); // Attach by multiple IDs $post->attachCategories([1, 2, 5]); // Attach by slug $post->attachCategories('technology'); // Attach by multiple slugs $post->attachCategories(['tech', 'programming', 'laravel']); // Attach by model instance $category = app('rinvex.categories.category')->first(); $post->attachCategories($category); // Attach by collection of models $categories = app('rinvex.categories.category')->whereIn('id', [1, 2, 5])->get(); $post->attachCategories($categories); // Sync categories (detaches those not in the list) $post->syncCategories([1, 3, 7]); // Sync without detaching existing $post->syncCategories([8, 9], false); // Detach specific categories $post->detachCategories([1, 2]); // Detach all categories $post->detachCategories(); ``` ## Checking Category Relationships Verify whether a model has specific categories attached. ```php <?php $post = Post::find(1); // Check if has ANY of the given categories $post->hasAnyCategories(1); // By ID $post->hasAnyCategories([1, 2, 5]); // By multiple IDs $post->hasAnyCategories('technology'); // By slug $post->hasAnyCategories(['tech', 'news']); // By multiple slugs $post->hasAnyCategories($categoryInstance); // By model // Check if has ALL of the given categories $post->hasAllCategories([1, 2, 3]); $post->hasAllCategories(['tech', 'programming']); // Examples with conditionals if ($post->hasAnyCategories('featured')) { // Post is in featured category } if ($post->hasAllCategories(['premium', 'verified'])) { // Post has both premium and verified categories } ``` ## Query Scopes for Filtering Use built-in scopes to query models by their categories. ```php <?php // Find posts with ANY of the given categories $posts = Post::withAnyCategories([1, 2, 5])->get(); $posts = Post::withAnyCategories(['tech', 'news'])->get(); $posts = Post::withCategories('programming')->get(); // Alias for withAnyCategories // Find posts with ALL of the given categories $posts = Post::withAllCategories([1, 2])->get(); $posts = Post::withAllCategories(['premium', 'featured'])->get(); // Find posts WITHOUT any of the given categories $posts = Post::withoutCategories([1, 2])->get(); $posts = Post::withoutCategories(['spam', 'hidden'])->get(); // Find posts without ANY categories at all $posts = Post::withoutAnyCategories()->get(); // Chain with other query methods $posts = Post::withAnyCategories('technology') ->where('published', true) ->orderBy('created_at', 'desc') ->paginate(15); ``` ## Category Tree Operations Navigate and manipulate the category hierarchy using nested set operations. ```php <?php $category = app('rinvex.categories.category')->find(1); // Get ancestors (parents chain to root) $ancestors = $category->getAncestors(); $ancestors = $category->ancestors()->get(); $ancestors = app('rinvex.categories.category')->ancestorsOf($category->id); // Get descendants (all children recursively) $descendants = $category->descendants; $descendants = $category->descendants()->get(); $descendants = app('rinvex.categories.category')->descendantsOf($category->id); $withSelf = app('rinvex.categories.category')->descendantsAndSelf($category->id); // Get siblings (same parent) $siblings = $category->getSiblings(); $siblings = $category->siblings()->get(); // Get next/previous siblings $next = $category->getNextSibling(); $allNext = $category->getNextSiblings(); $prev = $category->getPrevSibling(); $allPrev = $category->getPrevSiblings(); // Get direct children $children = $category->children; // Get parent $parent = $category->parent; // Build full tree $tree = app('rinvex.categories.category')->get()->toTree(); // Build flat tree (for dropdowns/lists) $flatTree = app('rinvex.categories.category')->get()->toFlatTree(); // Get subtree from a node $root = app('rinvex.categories.category')->find($rootId); $subtree = $root->descendants->toTree($root); ``` ## Moving and Reordering Categories Modify the category tree structure by moving nodes. ```php <?php $category = app('rinvex.categories.category')->find(5); $parent = app('rinvex.categories.category')->find(1); $neighbor = app('rinvex.categories.category')->find(3); // Make category a root node $category->saveAsRoot(); // Or with explicit save $category->makeRoot()->save(); // Append as last child of parent $category->appendToNode($parent)->save(); $parent->appendNode($category); // Prepend as first child of parent $category->prependToNode($parent)->save(); $parent->prependNode($category); // Insert before/after a sibling $category->afterNode($neighbor)->save(); $category->beforeNode($neighbor)->save(); // Or with implicit save $category->insertAfterNode($neighbor); $category->insertBeforeNode($neighbor); // Shift position within siblings $category->up(); // Move up one position $category->down(); // Move down one position $category->up(3); // Move up 3 positions $category->down(2); // Move down 2 positions // Check if category moved if ($category->save()) { $moved = $category->hasMoved(); } ``` ## Category Depth and Ordering Query categories by depth level and apply default ordering. ```php <?php // Get category with depth information $category = app('rinvex.categories.category')->withDepth()->find($id); echo $category->depth; // 0 = root, 1 = first level children, etc. // Get all categories at specific depth $firstLevelCategories = app('rinvex.categories.category') ->withDepth() ->having('depth', '=', 1) ->get(); // Default order (by nested set left value) $ordered = app('rinvex.categories.category')->defaultOrder()->get(); // Reversed order $reversed = app('rinvex.categories.category')->reversed()->get(); // Query constraints $roots = app('rinvex.categories.category')->whereIsRoot()->get(); $after = app('rinvex.categories.category')->whereIsAfter($id)->get(); $before = app('rinvex.categories.category')->whereIsBefore($id)->get(); // Descendant constraints $descendants = app('rinvex.categories.category') ->whereDescendantOf($category) ->get(); $withSelf = app('rinvex.categories.category') ->whereDescendantOrSelf($category) ->get(); // Ancestor constraints $ancestors = app('rinvex.categories.category') ->whereAncestorOf($category) ->get(); ``` ## Category Translations Manage multi-language category names and descriptions. ```php <?php $category = app('rinvex.categories.category')->find(1); // Set single translation $category->setTranslation('name', 'en', 'Technology')->save(); $category->setTranslation('name', 'fr', 'Technologie')->save(); // Update multiple translations at once $category->update([ 'name' => [ 'en' => 'Technology', 'ar' => 'تكنولوجيا', 'fr' => 'Technologie', ], 'description' => [ 'en' => 'Tech articles and tutorials', 'ar' => 'مقالات ودروس تقنية', ], ]); // Get translation for specific locale $englishName = $category->getTranslation('name', 'en'); $arabicName = $category->getTranslation('name', 'ar'); // Get all translations $allTranslations = $category->getTranslations('name'); // Returns: ['en' => 'Technology', 'ar' => 'تكنولوجيا', 'fr' => 'Technologie'] // Get name in current app locale $name = $category->name; ``` ## Retrieving Models from Category Get all models attached to a category and its descendants. ```php <?php $category = app('rinvex.categories.category')->find(1); // Get all posts attached to this category $posts = $category->entries(\App\Models\Post::class)->get(); // Get products from category $products = $category->entries(\App\Models\Product::class)->get(); // Get all posts from category AND all its descendants $categoryIds = $category->descendants()->pluck('id'); $categoryIds[] = $category->getKey(); // Using morphToMany relationship $posts = \App\Models\Post::withCategories($categoryIds)->get(); // Or using whereIn for HasMany relationships $products = \App\Models\Product::whereIn('category_id', $categoryIds)->get(); ``` ## Rebuilding and Fixing Trees Repair broken tree structures and rebuild from array data. ```php <?php // Check if tree structure is broken $isBroken = app('rinvex.categories.category')->isBroken(); // Get detailed error statistics $errors = app('rinvex.categories.category')->countErrors(); // Returns: [ // 'oddness' => 0, // Wrong lft/rgt values // 'duplicates' => 0, // Duplicate lft/rgt values // 'wrong_parent' => 0, // Invalid parent_id // 'missing_parent' => 0, // Parent doesn't exist // ] // Fix broken tree using parent_id relationships app('rinvex.categories.category')->fixTree(); // Rebuild entire tree from array $data = [ ['id' => 1, 'name' => ['en' => 'Electronics'], 'children' => [ ['id' => 2, 'name' => ['en' => 'Phones']], ['name' => ['en' => 'Laptops']], // New category (no id) ]], ['id' => 5, 'name' => ['en' => 'Clothing']], ]; // Rebuild without deleting missing categories app('rinvex.categories.category')->rebuildTree($data); // Rebuild and delete categories not in array app('rinvex.categories.category')->rebuildTree($data, true); ``` ## Helper Methods Utility methods for checking category relationships and properties. ```php <?php $category = app('rinvex.categories.category')->find(1); $parent = app('rinvex.categories.category')->find(2); $sibling = app('rinvex.categories.category')->find(3); // Check if root category (no parent) $isRoot = $category->isRoot(); // Check relationship to other categories $isDescendant = $category->isDescendantOf($parent); $isAncestor = $category->isAncestorOf($parent); $isChild = $category->isChildOf($parent); $isSibling = $category->isSiblingOf($sibling); // Example usage if ($category->isRoot()) { echo "This is a top-level category"; } if ($category->isDescendantOf($techCategory)) { echo "This category belongs under Technology"; } ``` ## Artisan Commands Built-in artisan commands for managing categories. ```bash # Publish config and migration files php artisan rinvex:publish:categories # Publish only config php artisan rinvex:publish:categories --resource=config # Publish only migrations php artisan rinvex:publish:categories --resource=migrations # Force overwrite existing files php artisan rinvex:publish:categories --force # Run category migrations php artisan rinvex:migrate:categories # Run in production (requires --force) php artisan rinvex:migrate:categories --force # Rollback category migrations php artisan rinvex:rollback:categories php artisan rinvex:rollback:categories --force ``` ## Summary Rinvex Categories provides a complete solution for hierarchical category management in Laravel applications. The package excels at handling complex category trees with features like ancestor/descendant queries, breadcrumb generation, tree reordering, and multi-language support. Common use cases include e-commerce product categorization, content management systems with article categories, forum topic organization, and any application requiring hierarchical taxonomies. Integration follows standard Laravel patterns through service providers, traits, and Eloquent relationships. Models become categorizable by adding a single trait, and categories themselves are Eloquent models that can be extended or customized through configuration. The polymorphic relationship design allows multiple model types to share the same category system, while the nested set implementation ensures efficient tree operations without recursive queries. For production applications, the package includes tree consistency checking and repair utilities to maintain data integrity.