elhareth / laravel-eloquent-metable
A Laravel package to extend Eloquent models data
Requires
- php: ^8.0
- ext-json: *
- illuminate/collections: ^10.0
- illuminate/contracts: ^10.0
- illuminate/database: ^10.0
- illuminate/support: ^10.0
README
Laravel-Eloquent-Metable is a package for extending laravel Eloquent models without messing up with the database schema.
Example Usage
Adding metadata to an eloquent model
$user = User::create([ 'name' => 'User Name', 'email' => 'username@email.com', 'password' => 'password', ]); $user->setMeta('gender', 'male');
Query scope to fetch model by it's metadata
$user = User::whereMeta('gender', 'male');
Get attached metadata
$gender = $user->getMeta('gender');
Installation
Add the package to your Laravel app using composer
composer require elhareth/laravel-eloquent-metable
Run the migrations to add the required table to your database.
php artisan migrate
Add the Elhareth\LaravelEloquentMetable\IsMetable
trait to any eloquent model class that you want to be able to attach metadata to.
use Illuminate\Database\Eloquent\Model; use Elhareth\LaravelEloquentMetable\IsMetable; class User extends Model { use IsMetable; }
Documentation
Handling Meta
The IsMetable
trait will add metalist()
method to your model, which meant to handle the realtion between your model and the meta data model Metable
.
Attaching MetaData
Attach meta to a model with the setMeta()
method. The method accepts three arguments: a string to use as a meta name, a value and additionally a string for group. The value argument will accept a number of different inputs, which will be converted to a string for storage in the database.
$user->setMeta('key', 'value'); $user->setMeta('key', 'value', null); $user->setMeta('key', 'value', 'group');
If you want to add many meta records you may pass an array as first parameter
$user->setMeta([ 'full_name' => 'Full Name', 'gender' => 'male', 'bio' => 'Lorem absum...', ]);
Also you pass a second param as meta data group
$user->setMeta([ 'full_name' => 'Full Name', 'gender' => 'male', 'bio' => 'Lorem absum...', ], 'profile');
Be Carefull !
if you adding a meta record with value of type array if it has value/group key it will be treated as $value
/ $group
params, so when you adding an array that may have these keys consider using setMeta()
method where the value param is treated as value no matter what it does contain.
$user->setMeta('key', [ 'value' => 'random-content', ]); // 'a:1:{s:5:"value";s:14:"random-content";};' $value = $user->getMeta('key'); // ['value' => 'random-content']
Retrieving MetaData
You can retrieve the value of the meta at a given key with the getMeta()
method.
$gender = $user->getMeta('gender');
The method getMeta
accepts three arguments; getMeta(name: $name, default: $default nullable $nullable)
The first the name of meta record
The second parameter to specify a default value to return if no meta has been set at that key.
The third parameter is a boolean to set whether to treat null values as not found
$user->getMeta('gender', 'male'); // will return 'male' if not set $user->getMeta('gender', 'male', false); // will return male if not set or if value is null $user->getMeta('gender', 'male', true); // will return male if not set or null if is set to null
You may retrieve a collection of meta depending on specifec group
$profile = $user->getMetaGroup('profile'); // return collection
Checking For Presence of MetaData
You can check if a value has been assigned to a given key with the hasMeta()
method.
This method will return true if a record is found on database.
You may pass another boolean value to control how to treat null values.
if ($user->hasMeta('gender')) { // ... } if ($user->has(name: 'gender', nullable: true)) { // ... }
Queued Metables
You may mass assign metables and they will be attached once the model is created
$user = User::create([ 'name' => 'UserName', 'email' => 'username@email.com', 'password' => 'password', 'metables' => [ 'gender' => 'male', // OR 'gender' => [ 'value' => 'male', // OR ], 'gender' => [ 'value' => 'male', 'group' => 'profile', // If not specified group is null ], ], ]); $user->getMeta('gender') // male
Pre Metables
You may define default metables for each model and they'll be added once the model is created.
To do so you should implement Elhareth\LaravelEloquentMetable\IsMetableInterface
> And define a method defaultMetables()
which returns an array of metables you want to automatically attach to your model.
use Elhareth\LaravelEloquentMetable\IsMetableInterface; use Illuminate\Database\Eloquent\Model; class User extends Model implements IsMetableInterface { /** * Default Metables * * @return array */ protected function defaultMetables(): array { return [ 'gender' => [ 'value' => null, 'group' => 'profile', ], 'bio' => [ 'value' => null, 'group' => 'profile', ], 'locale' => [ 'value' => 'en', 'group' => null, ], 'avatar' => [ 'value' => 'avatar.png', ], 'theme' => 'dark', ]; } }
You can get list of model default metables by getDefaultMetables()
.
Deleting MetaData
To remove the meta stored at a given key, use removeMeta()
.
$user->removeMeta('bio');
To delete all meta records from a model, use deleteMetaRecords()
.
$user->deleteMetaRecords();
Attached meta is automatically purged from the database when a IsMetable
model is manually deleted. Metaable will not
be cascaded if the model is deleted by the query builder.
$user->delete(); // will delete attached meta User::where(...)->delete() // will NOT delete attached meta
Eager Loading MetaData
When working with collections of IsMetable
models, be sure to eager load the meta relation for all instances together to avoid repeated database queries (i.e. N+1 problem).
Eager load from the query builder:
$users = User::with('metalist')->where(...)->get();
Lazy eager load from an Eloquent collection:
$users->load('metalist');
You can also instruct your model class to always
eager load the meta relationship by adding 'metalist'
to your model's $with
property.
class User extends Model { use IsMetable; protected $with = ['metalist']; }
Querying Meta
The IsMetable
trait provides a number of query scopes to facilitate modifying queries based on the meta attached to your models
Checking for Presence of a key
To only return records that have a value assigned to a particular key, you can use whereHasMeta()
. You can also pass an array to this method, which will cause the query to return any models attached to one or more of the provided keys.
$users = User::whereHasMeta('gender')->get(); $users = User::whereHasMeta(['gender', 'bio'])->get();
You can also query for records that does not contain a meta key using the whereDoesntHaveMeta()
. Its signature is identical to that of whereHasMeta()
.
$users = User::whereDoesntHaveMeta('gender')->get(); $users = User::whereDoesntHaveMeta(['gender', 'bio'])->get();
You can restrict your query based on the value stored at a meta key. The whereMeta()
method can be used to compare the value using any of the operators accepted by the Laravel query builder's where()
method.
$users = User::whereMeta('letters', ['a', 'b', 'c'])->get();
The whereMetaIn()
method is also available to find records where the value is matches one of a predefined set of options.
$users = User::whereMetaIn('country', ['CAN', 'USA', 'MEX']);
License
This package is released under the MIT license (MIT).