Installation:
composer require seyedmr/laralight-metadata
php artisan migrate
metadata table via migration (check database/migrations/ for create_metadata_table.php).First Use Case:
HasMeta trait to a model (e.g., User):
use SeyedMR\LaraliteMetadata\Traits\HasMeta;
class User extends Model
{
use HasMeta;
}
metadata table.Basic CRUD:
$user = User::find(1);
$user->setMeta('profile.bio', 'Laravel Developer');
$user->save(); // Required to persist metadata
$bio = $user->getMeta('profile.bio'); // Returns 'Laravel Developer'
if ($user->hasMeta('profile.bio')) { ... }
database/migrations/create_metadata_table.php for schema (default: model_type, model_id, key, value).HasMeta trait in vendor/seyedmr/laralight-metadata/src/Traits/HasMeta.php for all available methods (setMeta, getMeta, hasMeta, deleteMeta, clearMeta).config/laralight-metadata.php (if auto-generated) for customization options.// Set nested metadata (dot notation)
$user->setMeta('preferences.notifications', 'email');
$user->setMeta('profile.avatar', $avatarPath);
$user->save();
// Retrieve nested values
$notifications = $user->getMeta('preferences.notifications');
key.subkey) for hierarchical data.$user = User::find(1);
$responseData = $user->toArray();
if ($user->hasMeta('api.hide_email')) {
unset($responseData['email']);
}
return response()->json($responseData);
$featuredProducts = Product::where('category', 'sale')->get();
foreach ($featuredProducts as $product) {
$product->setMeta('promotion.featured', true);
$product->save();
}
DB::transaction() for batch operations to avoid N+1 queries.created, updated).// app/Observers/UserObserver.php
public function created(User $user)
{
$user->setMeta('created_via', 'api');
$user->save();
}
Register the observer in AppServiceProvider@boot():
User::observe(UserObserver::class);
premium status).// Create a scope (add to User model)
public function scopePremium($query)
{
return $query->whereHas('metadata', function ($q) {
$q->where('key', 'status')
->where('value', 'premium');
});
}
Usage:
$premiumUsers = User::premium()->get();
$user->setMeta('settings', json_encode(['theme' => 'dark', 'font_size' => 14]));
$settings = json_decode($user->getMeta('settings'), true);
email must be valid).use Illuminate\Support\Facades\Validator;
public function setMeta($key, $value)
{
if ($key === 'contact.email') {
$validator = Validator::make(['email' => $value], ['email' => 'email']);
if ($validator->fails()) {
throw new \Exception('Invalid email format');
}
}
parent::setMeta($key, $value);
}
public function getMeta($key)
{
return cache()->remember("meta_{$this->id}_{$key}", now()->addHours(1), function () {
return parent::getMeta($key);
});
}
Missing save() After setMeta:
$model->save().$user->setMeta('key', 'value');
$user->save(); // Critical!
Case Sensitivity in Keys:
'Key' ≠ 'key').snake_case) in your application.No Built-in Encryption:
use Illuminate\Support\Facades\Crypt;
$user->setMeta('api_token', Crypt::encrypt($token));
$token = Crypt::decrypt($user->getMeta('api_token'));
Performance with Large Datasets:
No Built-in Soft Deletes:
deleted() observer or override delete():
public function delete()
{
$this->clearMeta();
parent::delete();
}
Check the metadata Table:
php artisan tinker
>>> \DB::table('metadata')->where('model_type', 'App\User')->get();
Enable Query Logging:
\DB::enableQueryLog();
$user->getMeta('key');
\DB::getQueryLog(); // Inspect queries
Validate Trait Usage:
metadata table exists.Custom Storage Engine:
metadata table by publishing the config:
php artisan vendor:publish --provider="SeyedMR\LaraliteMetadata\LaraliteMetadataServiceProvider"
config/laralight-metadata.php to use a different table or connection.Add Metadata Scopes:
// In HasMeta trait
public function scopeWithMeta($query, $key, $value)
{
return $query->whereHas('metadata', function ($q) use ($key, $value) {
$q->where('key', $key)->where('value', $value);
});
}
Usage:
User::withMeta('status', 'active')->get();
Event Dispatching:
// In HasMeta trait
protected function fireMetaEvents($key, $value)
{
event(new MetaUpdated($this, $key, $value));
}
Mass Assignment Protection:
protected $metaFillable = ['profile.*', 'settings.*'];
Then override setMeta to validate against `$metaFillHow can I help you explore Laravel packages today?