Installation:
composer require phoenix/eloquent-meta
For Laravel 5.7+:
composer require phoenix/eloquent-meta:^1.9
Publish Migrations (if using Laravel):
php artisan vendor:publish --provider="Phoenix\EloquentMeta\EloquentMetaServiceProvider" --tag="migrations"
Run migrations:
php artisan migrate
Basic Usage:
use Phoenix\EloquentMeta\EloquentMetaTrait;
class Post extends Model
{
use EloquentMetaTrait;
}
// Set meta
$post = Post::find(1);
$post->setMeta(['author' => 'John Doe', 'views' => 100]);
// Get meta
$author = $post->getMeta('author');
Store and retrieve dynamic metadata for a User model (e.g., last_login_ip, preferences):
$user = User::find(1);
$user->setMeta(['last_login_ip' => request()->ip(), 'theme' => 'dark']);
$theme = $user->getMeta('theme', 'light'); // Fallback to 'light'
use EloquentMetaTrait; to any Eloquent model.$metaTable property:
class Post extends Model
{
use EloquentMetaTrait;
protected $metaTable = 'post_metadata';
}
Set Meta:
// Single key-value
$post->setMeta('views', 150);
// Multiple key-values
$post->setMeta(['author' => 'Jane Doe', 'tags' => ['laravel', 'php']]);
// Merge with existing meta
$post->setMeta(['views' => 150], true); // `true` = merge
Get Meta:
// Single key
$views = $post->getMeta('views');
// Multiple keys
$data = $post->getMeta(['author', 'tags']);
// Fallback value
$theme = $post->getMeta('theme', 'default');
Delete Meta:
$post->deleteMeta('views'); // Delete single key
$post->deleteMeta(['author', 'tags']); // Delete multiple keys
$post->deleteMeta(); // Delete all meta for the model
Filter models by meta data using query scopes:
// Find posts with >100 views
$posts = Post::whereMeta('views', '>', 100)->get();
// Find posts with specific tags
$posts = Post::whereMeta('tags', 'like', '%laravel%')->get();
Listen for meta changes via events:
// In EventServiceProvider
protected $listen = [
'Phoenix\EloquentMeta\Events\MetaSaved' => [
'App\Listeners\LogMetaChanges',
],
];
config/app.php under providers:
Phoenix\EloquentMeta\EloquentMetaServiceProvider::class,
php artisan vendor:publish --provider="Phoenix\EloquentMeta\EloquentMetaServiceProvider" --tag="config"
Customize config/eloquent-meta.php (e.g., default table name, fallback behavior).CREATE TABLE model_meta (
model_id INTEGER,
model_type VARCHAR(255),
key VARCHAR(255),
value TEXT,
PRIMARY KEY (model_id, model_type, key)
);
setMeta() with arrays for bulk updates.model_meta table has indexes on (model_id, model_type, key) for faster queries.Laravel Version Compatibility:
spatie/laravel-activitylog or stancl/tenancy for meta-like functionality.Migration Conflicts:
model_meta table, the package’s migrations will fail. Either:
Serialization Issues:
$post->setMeta('complex', new stdClass()); // May fail silently.
Query Scope Limitations:
whereMeta() only supports basic comparisons (=, >, <, like). Avoid complex queries like whereMeta('tags', 'json_contains', '["laravel"]').Model Type Collisions:
model_type column uses the fully qualified class name (e.g., App\Models\Post). Ensure this doesn’t exceed your database’s column length limits (default is often 255 chars).Missing Meta Data:
model_meta table exists and has data:
SELECT * FROM model_meta WHERE model_id = 1 AND model_type = 'App\Models\Post';
DB::enableQueryLog();
$post->setMeta('test', 'value');
dd(DB::getQueryLog());
Serialization Errors:
json_encode() before setting:
$post->setMeta('tags', json_encode(['laravel', 'php']));
json_decode():
$tags = json_decode($post->getMeta('tags'), true);
Event Firing:
EventServiceProvider. Test with:
event(new \Phoenix\EloquentMeta\Events\MetaSaved($post, ['key' => 'value']));
Fallback Values:
getMeta() to avoid null returns:
$theme = $post->getMeta('theme', 'light'); // Defaults to 'light'
Type Safety:
$views = (int) $post->getMeta('views', 0);
Testing:
public function test_meta()
{
$post = Post::factory()->create();
$this->actingAs(user())
->post('/posts/' . $post->id, ['meta' => ['views' => 100]])
->assertOk();
}
Alternatives:
cache()->put("post:{$post->id}:meta", $meta)).Extending Functionality:
getMetaTable() method in your model for dynamic table names:
protected function getMetaTable()
{
return "{$this->table}_meta";
}
trait ExtendedEloquentMetaTrait
{
public function incrementMeta($key, $value = 1)
{
$current = $this->getMeta($key, 0);
$this->setMeta($key, $current + $value);
}
}
How can I help you explore Laravel packages today?