HasMeta
The HasMeta trait adds metadata functionality to any Eloquent model, allowing you to store, retrieve, query, and manage arbitrary key-value pairs through a polymorphic relationship.
Namespace
JobMetric\Metadata\HasMeta
Overview
The HasMeta trait provides:
- Metadata Storage: Store key-value pairs for any model
- Key Whitelisting: Control which keys are allowed
- Automatic JSON Handling: Arrays are automatically JSON-encoded/decoded
- Query Scopes: Filter models by metadata
- Batch Operations: Store or delete multiple metadata entries
- Event Integration: Fires events on metadata operations
Basic Usage
Attach Trait to Model
use JobMetric\Metadata\HasMeta;
class Product extends Model
{
use HasMeta;
}
Optional: Limit Allowed Keys
Define allowed metadata keys in your model:
class Product extends Model
{
use HasMeta;
protected array $metadata = [
'color',
'size',
'weight',
'dimensions',
];
}
If omitted or set to ['*'], all keys are allowed.
Available Methods
Store Metadata
Store or update a single metadata value:
$product->storeMetadata('color', 'red');
$product->storeMetadata('dimensions', ['width' => 10, 'height' => 20]);
Parameters:
string $key- Metadata keyarray|string|bool|null $value- Metadata value
Returns: static - Fluent interface
Throws: ModelMetaableKeyNotAllowedFieldException if key is not allowed
Store Multiple Metadata
Store multiple metadata entries in a batch:
$product->storeMetadataBatch([
'color' => 'red',
'size' => 'large',
'weight' => 500,
'dimensions' => ['width' => 10, 'height' => 20],
]);
Parameters:
array $metas- Associative array of key => value pairs
Returns: static - Fluent interface
Get Metadata
Retrieve metadata value(s):
// Get single value
$color = $product->getMetadata('color');
// => 'red'
// Get single value with default
$price = $product->getMetadata('price', 0);
// => 0 (if 'price' doesn't exist)
// Get all metadata
$all = $product->getMetadata();
// => Collection with all key-value pairs
Parameters:
string|null $key- Metadata key (null for all)array|string|bool|null $default- Default value if key doesn't exist
Returns: mixed - Single value or Collection
Throws: ModelMetaableKeyNotAllowedFieldException if key is not allowed
Check Metadata Exists
Check if a metadata key exists:
if ($product->hasMetadata('color')) {
// Metadata exists
}
Parameters:
string $key- Metadata key to check
Returns: bool - true if key exists, false otherwise
Delete Metadata
Delete metadata by key or all metadata:
// Delete specific key
$product->forgetMetadata('color');
// Delete all metadata
$product->forgetMetadata();
Parameters:
string|null $key- Metadata key to delete (null for all)
Returns: static - Fluent interface
Throws: ModelMetaableKeyNotAllowedFieldException if key is not allowed
Get Metadata Keys
Get the list of allowed metadata keys:
$keys = $product->getMetaKeys();
// => ['color', 'size', 'weight', 'dimensions']
// or ['*'] if all keys are allowed
Returns: array - Array of allowed keys or ['*']
Merge Metadata Keys
Add additional allowed keys at runtime:
$product->mergeMeta(['nickname', 'website']);
Parameters:
array $meta- Array of keys to add
Returns: void
Remove Metadata Key
Remove a key from the allowed list:
$product->removeMetaKey('bio');
Parameters:
string $key- Key to remove
Returns: void
Throws: ModelMetaableKeyNotAllowedFieldException if key is not in allowed list
Relationships
Metas Relationship
Access the polymorphic relationship directly:
$metas = $product->metas;
// => Collection of Meta models
// Query relationship
$colorMeta = $product->metas()->where('key', 'color')->first();
Meta Key Relationship
Filter metadata by key:
$colorMeta = $product->metaKey('color')->first();
Parameters:
string $key- Metadata key
Returns: MorphMany - Query builder instance
Query Scopes
Has Meta Key
Filter models that have a specific metadata key:
$productsWithColor = Product::hasMetaKey('color')->get();
Parameters:
string $key- Metadata key to filter by
Returns: Builder - Query builder instance
Storing via Model Attributes
You can store metadata when creating or updating models:
$product = Product::create([
'name' => 'Test Product',
'metadata' => [
'color' => 'red',
'size' => 'large',
],
]);
The metadata will be validated against allowed keys and stored after the model is saved.
Events
The trait fires the following events:
MetadataStoringEvent- Before metadata is storedMetadataStoredEvent- After metadata is storedMetadataDeletingEvent- Before metadata is deletedMetadataDeletedEvent- After metadata is deleted
Listen to these events in your EventServiceProvider:
protected $listen = [
\JobMetric\Metadata\Events\MetadataStoredEvent::class => [
\App\Listeners\LogMetadataStored::class,
],
];
Complete Examples
E-Commerce Product Attributes
class Product extends Model
{
use HasMeta;
protected array $metadata = [
'color',
'size',
'weight',
'dimensions',
'material',
'warranty_period',
];
}
// Store product attributes
$product = Product::find(1);
$product->storeMetadataBatch([
'color' => 'blue',
'size' => 'large',
'weight' => 500,
'dimensions' => ['width' => 10, 'height' => 20, 'depth' => 5],
'material' => 'cotton',
'warranty_period' => '1 year',
]);
// Retrieve attributes
$color = $product->getMetadata('color');
$dimensions = $product->getMetadata('dimensions');
User Preferences
class User extends Model
{
use HasMeta;
// No $metadata array = all keys allowed
}
// Store user preferences
$user = User::find(1);
$user->storeMetadata('theme', 'dark');
$user->storeMetadata('notifications', [
'email' => true,
'sms' => false,
'push' => true,
]);
// Get preferences
$theme = $user->getMetadata('theme', 'light');
$notifications = $user->getMetadata('notifications', []);