Install & Publish:
composer require rinvex/laravel-categories
php artisan rinvex:publish:categories
php artisan migrate
config/categories.php for core settings (e.g., model, sluggable, translatable).categories table structure (supports polymorphic relationships via categoryable table).First Use Case: Categorize a Model
use Rinvex\Categories\Traits\HasCategories;
use Rinvex\Categories\Traits\HasCategory;
public function categories()
{
return $this->morphToMany(Category::class, 'categoryable');
}
$post = Post::find(1);
$post->categories()->attach([1, 2]); // Attach by IDs
Key Initial Commands:
php artisan rinvex:categories:seed (if using seeds).php artisan rinvex:categories:make:model (for custom category models).Hierarchical Categories (Nested Sets)
lazychaser/laravel-nestedset for tree-like structures:
$parent = Category::find(1);
$child = $parent->children()->create(['name' => 'Subcategory']);
$post->categories->whereHas('descendants'); // Posts in subcategories
Polymorphic Categorization
HasCategories trait to categorize any model (e.g., Post, Product):
$product = Product::find(1);
$product->categories()->sync([3, 4]); // Sync replaces existing
Post::whereHas('categories', function($q) {
$q->where('name', 'Tech');
})->get();
Slugs & Translations
spatie/laravel-sluggable:
use Sluggable;
class Category extends Model {
use Sluggable;
public function getSlugOptions() { return ['source' => 'name']; }
}
spatie/laravel-translatable:
$category->setTranslations('name', [
'en' => 'Electronics',
'es' => 'Electrónicos'
]);
API & Frontend Integration
return Category::with('children')->get()->toJson();
rinvex/categories in Vue/React via API endpoints (e.g., /api/categories).Rinvex\Categories\Models\Category for domain-specific logic.$activeCategories = Category::active()->get(); // Uses `is_active` column
CategoryCreated, CategoryDeleted events for side effects (e.g., cache updates).Migration Conflicts:
categories table exists, drop it before publishing new migrations.php artisan migrate:fresh or manually resolve column conflicts.Polymorphic Relationships:
categoryable table or using incorrect morph keys (e.g., categoryable_type/id).morphToMany setup:
Schema::create('categoryable', function (Blueprint $table) {
$table->unsignedBigInteger('category_id');
$table->unsignedBigInteger('categoryable_id');
$table->string('categoryable_type');
$table->foreign('category_id')->references('id')->on('categories');
});
Nested Set Performance:
depth or path optimizations:
Category::where('path', 'like', '1.2.%')->get(); // Subcategories of ID 2
Slug Collisions:
source isn’t unique. Use unique:categories,slug in validation.getSlugOptions to include a counter:
public function getSlugOptions() {
return ['source' => 'name', 'unique' => true];
}
APP_DEBUG=true) to inspect nested set queries.php artisan rinvex:categories:seed --force to reset test data.translations table exists and translated attribute is defined:
protected $translatable = ['name', 'description'];
Custom Validation:
Override Category model rules:
public static function boot() {
parent::boot();
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('is_active', true);
});
}
API Resources:
Extend Rinvex\Categories\Http\Resources\CategoryResource for custom fields.
Service Providers: Bind custom category repositories:
$this->app->bind(
\Rinvex\Categories\Contracts\CategoryRepository::class,
\App\Repositories\CustomCategoryRepository::class
);
Testing:
Use rinvex/categories factories:
$category = Category::factory()->create(['name' => 'Books']);
$post->categories()->attach($category);
Assert relationships:
$this->assertCount(1, $post->categories);
config['model'] if not using Rinvex\Categories\Models\Category.config['sluggable']['source'] to control slug fields (e.g., title).config['translatable']['locales'] for supported languages.
```markdown
## Performance Considerations
- **Eager Loading**: Always eager-load relationships to avoid N+1 queries:
```php
Post::with('categories.children')->get();
Cache::remember('categories-tree', now()->addHours(1), function() {
return Category::with('children')->get();
});
categoryable table for polymorphic queries:
Schema::table('categoryable', function (Blueprint $table) {
$table->index(['categoryable_type', 'categoryable_id']);
});
How can I help you explore Laravel packages today?