waad/laravel-model-metadata
Installation:
composer require waad/laravel-model-metadata
php artisan vendor:publish --tag=metadata-config --tag=metadata-migrations
php artisan migrate
Apply Trait to Model:
Use HasManyMetadata (for multiple metadata entries) or HasOneMetadata (for single metadata entry) on your Eloquent model:
use Waad\Metadata\Traits\HasManyMetadata;
class Post extends Model
{
use HasManyMetadata;
}
First Use Case: Attach metadata to a model instance:
$post = Post::find(1);
$post->metadata()->attach([
'author_notes' => 'Draft needs review',
'tags' => ['laravel', 'metadata']
]);
config/model-metadata.php for customization (e.g., table name, caching).database/migrations/ for schema details.Attaching Metadata:
// Single attachment (HasOneMetadata)
$post->metadata()->attach(['key' => 'value']);
// Multiple attachments (HasManyMetadata)
$post->metadata()->attach([
'key1' => 'value1',
'key2' => ['nested', 'array']
]);
Querying Metadata:
Use whereMetadata() for JSON-based queries:
// Exact match
Post::whereMetadata('author_notes', 'Draft needs review')->get();
// JSON array contains
Post::whereMetadata('tags', 'like', '%laravel%')->get();
// Nested JSON queries
Post::whereMetadata('settings.theme', 'dark')->get();
Caching:
Enable caching in config/model-metadata.php and leverage cache()->remember() for performance:
$metadata = Cache::remember("post.{$post->id}.metadata", now()->addHours(1), function () {
return $post->metadata()->first();
});
Custom Relation Names:
Override the default metadata() relation name:
class Post extends Model
{
use HasManyMetadata;
public function customMetadata()
{
return $this->metadata()->where('type', 'custom');
}
}
Mass Assignment:
Use fillMetadata() for bulk updates:
$post->fillMetadata(['status' => 'published', 'views' => 100])->save();
metadata.attached or metadata.updated events via Event::listen().Waad\Metadata\Observers\MetadataObserver for custom logic.$post->metadata->toArray() or use ->toJson() for JSON responses.JSON Casting Conflicts:
$casts = ['metadata' => 'array'], disable it to avoid conflicts with the package’s JSON handling.Migration Issues:
config/model-metadata.php for correct table names and run php artisan migrate:fresh.--pretend flag to debug migration SQL:
php artisan migrate --pretend
Caching Quirks:
MODEL_METADATA_CACHE_ENABLED). Enable it only in staging/production.php artisan cache:clear
Nested JSON Queries:
whereMetadata('user.settings.theme', 'dark')).Trait Conflicts:
HasManyMetadata and HasOneMetadata on the same model.\Log::info('Metadata:', ['data' => $post->metadata->toArray()]);
\DB::enableQueryLog();
Post::whereMetadata('key', 'value')->get();
\Log::info(\DB::getQueryLog());
Custom Metadata Model:
Extend Waad\Metadata\Models\Metadata to add fields:
class CustomMetadata extends Metadata
{
protected $casts = [
'custom_field' => 'boolean',
];
}
Update config:
'model' => App\Models\CustomMetadata::class,
Custom Accessors: Add dynamic accessors to your model:
public function getAuthorNotesAttribute()
{
return $this->metadata->get('author_notes');
}
Validation: Validate metadata before attachment:
use Waad\Metadata\Rules\ValidMetadata;
$request->validate([
'metadata' => ['required', new ValidMetadata],
]);
Schema::table('model_metadata', function (Blueprint $table) {
$table->index('key');
$table->index('model_type');
$table->index('model_id');
});
chunk() for large metadata updates:
Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
$post->metadata()->attach(['processed' => true]);
}
});
How can I help you explore Laravel packages today?