Skip to main content

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 key
  • array|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 stored
  • MetadataStoredEvent - After metadata is stored
  • MetadataDeletingEvent - Before metadata is deleted
  • MetadataDeletedEvent - 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', []);