abdylreshit / laravel-eav
A lightweight EAV package for Laravel: add dynamic, typed attributes to any Eloquent model with validation and easy querying.
Installs: 9
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
pkg:composer/abdylreshit/laravel-eav
Requires
- php: ^8.2
- illuminate/console: ^12.0
- illuminate/database: ^12.0
- illuminate/support: ^12.0
- spatie/laravel-translatable: ^6.11
README
A lightweight, powerful EAV (Entity-Attribute-Value) package for Laravel. Add dynamic, typed attributes to any Eloquent model without modifying your database schema. Perfect for e-commerce platforms, CMS systems, and applications requiring flexible data structures.
Features
✨ Dynamic Attributes - Add unlimited attributes to any model without schema changes
🎯 Type Support - String, text, integer, decimal, boolean, date, datetime, JSON, image, and file types
✅ Validation Ready - Built-in validation support for attribute values
🔍 Easy Querying - Filter models by EAV attributes with fluent API
🌍 Translatable - Support for multi-language attribute names
📦 Zero Configuration - Works out of the box with sensible defaults
🚀 Performance Optimized - Efficient queries with eager loading support
Installation
Install the package via Composer:
composer require abdylreshit/laravel-eav
The package will auto-discover and register its service provider.
Configuration
Publish the migration:
php artisan vendor:publish --provider="Abdylreshit\LaravelEav\Providers\LaravelEavServiceProvider" --tag="migrations"
Run the migration:
php artisan migrate
This creates the necessary tables: attributes and attribute_values.
Quick Start
1. Add the Trait to Your Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Abdylreshit\LaravelEav\Traits\HasEavAttributes; class Product extends Model { use HasEavAttributes; }
2. Create Attributes
use Abdylreshit\LaravelEav\Models\Attribute; use Abdylreshit\LaravelEav\Enums\AttributeType; // Create a color attribute Attribute::create([ 'name' => 'Color', 'code' => 'color', 'type' => AttributeType::STRING, ]); // Create a price attribute Attribute::create([ 'name' => 'Price', 'code' => 'price', 'type' => AttributeType::DECIMAL, ]);
3. Use Attributes on Your Model
$product = Product::find(1); // Set a single attribute $product->setAttribute('color', 'red'); // Set multiple attributes $product->setAttributes([ 'color' => 'blue', 'price' => 99.99, 'in_stock' => true, ]); // Get an attribute $color = $product->getAttribute('color'); // 'blue' // Get multiple attributes $attrs = $product->getAttributes(['color', 'price']); // Get all attributes $allAttrs = $product->getAllAttributes(); // Check if attribute exists if ($product->hasAttribute('color')) { // ... } // Delete an attribute $product->deleteAttribute('color');
Querying with Attributes
Filter models by attribute values:
// Find products with a specific color $redProducts = Product::whereAttribute('color', 'red')->get(); // Find products by multiple attributes $products = Product::whereAttributes([ 'color' => 'blue', 'in_stock' => true, ])->get(); // Combine with other queries $products = Product::where('category_id', 1) ->whereAttribute('price', '>', 50) ->get();
Attribute Types
The package supports the following attribute types:
| Type | Description | Column |
|---|---|---|
| STRING | Short text | string_value |
| TEXT | Long text | text_value |
| INTEGER | Whole numbers | integer_value |
| DECIMAL | Decimal numbers | decimal_value |
| BOOLEAN | True/false | boolean_value |
| DATE | Date (Y-m-d) | date_value |
| DATETIME | DateTime (Y-m-d H:i:s) | datetime_value |
| JSON | JSON data | json_value |
| IMAGE | Image file | image_value |
| FILE | File attachment | file_value |
Define Attribute Type
use Abdylreshit\LaravelEav\Enums\AttributeType; Attribute::create([ 'name' => 'Description', 'code' => 'description', 'type' => AttributeType::TEXT, ]); Attribute::create([ 'name' => 'Launch Date', 'code' => 'launch_date', 'type' => AttributeType::DATETIME, ]);
Translatable Attributes
Attribute names are translatable out of the box:
$attribute = Attribute::create([ 'name' => ['en' => 'Color', 'fr' => 'Couleur'], 'code' => 'color', 'type' => AttributeType::STRING, ]); // Get the name in a specific language $nameEn = $attribute->getTranslation('name', 'en'); // 'Color' $nameFr = $attribute->getTranslation('name', 'fr'); // 'Couleur'
Eager Loading
Eager load EAV values with your model to avoid N+1 queries:
// Eager load all EAV values $products = Product::with('eavValues.attribute')->get(); foreach ($products as $product) { $color = $product->getAttribute('color'); // No additional query }
Validation
Validate EAV attributes in your request:
use Abdylreshit\LaravelEav\Models\Attribute; $validated = $request->validate([ 'name' => 'required|string', 'color' => 'nullable|string|max:50', 'price' => 'nullable|numeric|min:0', ]); $product = Product::create($validated); $product->setAttributes($validated);
Available Methods
Getting Attributes
getAttribute(string $code)- Get a single attribute valuegetAttributes(array $codes)- Get multiple attribute valuesgetAllAttributes()- Get all attributes as an arrayhasAttribute(string $code)- Check if attribute exists
Setting Attributes
setAttribute(string $code, $value)- Set a single attributesetAttributes(array $attributes)- Set multiple attributes
Deleting Attributes
deleteAttribute(string $code)- Delete an attribute value
Querying
whereAttribute(string $code, $value)- Filter by single attributewhereAttributes(array $attributes)- Filter by multiple attributes
Relationships
eavValues()- MorphMany relationship to attribute values
Database Schema
Attributes Table
id - bigInteger, primary key
name - json, translatable attribute name
code - string, unique identifier
type - string, attribute type enum
created_at - timestamp
updated_at - timestamp
Attribute Values Table
id - bigInteger, primary key
attribute_id - bigInteger, foreign key to attributes
model_type - string, polymorphic model type
model_id - bigInteger, polymorphic model id
string_value - string, nullable
text_value - text, nullable
integer_value - integer, nullable
decimal_value - decimal(8,2), nullable
boolean_value - boolean, nullable
date_value - date, nullable
datetime_value - datetime, nullable
json_value - json, nullable
image_value - string, nullable
file_value - string, nullable
created_at - timestamp
updated_at - timestamp
Examples
E-Commerce Product Catalog
// Create attributes for a shoe product Attribute::create(['name' => 'Size', 'code' => 'size', 'type' => AttributeType::STRING]); Attribute::create(['name' => 'Color', 'code' => 'color', 'type' => AttributeType::STRING]); Attribute::create(['name' => 'Material', 'code' => 'material', 'type' => AttributeType::STRING]); // Set attributes on a product $shoe = Product::find(1); $shoe->setAttributes([ 'size' => '42', 'color' => 'black', 'material' => 'leather', ]); // Query products $blackShoes = Product::whereAttribute('color', 'black')->get();
CMS Page Attributes
// Create attributes for a page Attribute::create(['name' => 'Author', 'code' => 'author', 'type' => AttributeType::STRING]); Attribute::create(['name' => 'SEO Title', 'code' => 'seo_title', 'type' => AttributeType::STRING]); Attribute::create(['name' => 'Published Date', 'code' => 'published_date', 'type' => AttributeType::DATE]); // Use on your Page model $page = Page::find(1); $page->setAttributes([ 'author' => 'John Doe', 'seo_title' => 'Best Laravel Tips', 'published_date' => now()->format('Y-m-d'), ]);
Performance Tips
- Use Eager Loading - Always eager load EAV values when querying multiple models
- Index the code Column - Add a database index to
attributes.codefor faster queries - Cache Attributes - Cache commonly used attributes
- Batch Operations - Use batch setting/getting instead of individual calls
Console Commands
Publish Assets
php artisan eav:publish
Publishes migrations and configuration files.
Migrate EAV Tables
php artisan eav:migrate
Runs EAV-specific migrations.
Troubleshooting
Attribute Not Found
Ensure the attribute exists before setting a value:
$attribute = Attribute::where('code', 'color')->first(); if (!$attribute) { Attribute::create([...]); }
N+1 Query Problem
Use eager loading:
$products = Product::with('eavValues.attribute')->get();
Type Mismatch
Ensure the value type matches the attribute type:
$price = Attribute::where('code', 'price')->first(); // $price->type will be AttributeType::DECIMAL // Always pass numeric values for decimal attributes
License
The Laravel EAV package is open-sourced software licensed under the MIT license.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For support, please open an issue on the GitHub repository.
Changelog
See CHANGELOG.md for recent changes.
Credits
Created by Abdylreshit
Made with ❤️ for Laravel developers