PHPackages                             esslassi/metable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. esslassi/metable

ActiveLibrary[Database &amp; ORM](/categories/database)

esslassi/metable
================

Laravel MetaData for Eloquent Models

2.0.0(2y ago)031MITPHPPHP &gt;=7.3

Since Apr 19Pushed 2y ago1 watchersCompare

[ Source](https://github.com/esslassi/metable)[ Packagist](https://packagist.org/packages/esslassi/metable)[ RSS](/packages/esslassi-metable/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (4)Versions (12)Used By (0)

Add Meta Data To Eloquent Models
================================

[](#add-meta-data-to-eloquent-models)

Laravel MetaData for Eloquent Models

[![Laravel](https://camo.githubusercontent.com/532da8ea0a303ec469774829517af33e851a04c448e0bbc47add5558d4e5513d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d7e392e302d677265656e2e7376673f7374796c653d666c61742d737175617265)](http://laravel.com)[![Source](https://camo.githubusercontent.com/ac218e0a34b5a1efbdb031faff2d2f124ebc57ae5a94b5de3f7845fd605459da/687474703a2f2f696d672e736869656c64732e696f2f62616467652f736f757263652d6573736c617373692f6d657461626c652d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/esslassi/metable/)[![License](https://camo.githubusercontent.com/30597ff9a350144f03bffdd9183e16468e0b3ca1193e1d08591d992622738d55/687474703a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://tldrlegal.com/license/mit-license)

Installation
------------

[](#installation)

#### Composer

[](#composer)

Laravel can be installed on laravel `9.x` or higher.

Run:

```
composer require esslassi/metable

```

Register the package's service provider in config/app.php:

```
'providers' => [
    ...
    Esslassi\Metable\MetableServiceProvider::class,
    ...
];
```

You should publish the migration and the config/metable.php config file with:

```
php artisan vendor:publish --provider="Esslassi\Metable\MetableServiceProvider::class"
```

You can customize the default meta table (default: `meta`) in the config/metable.php:

```
return [

    /*
	 *
     * You can customize default table name by relacing 'meta' to your own
     *
     */

    'tables' => [

        // default table for all models

        'default' => 'meta'

    ]
];
```

Execute the migration command to create the meta table after the config and migration have been published and configured:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

#### Model Setup

[](#model-setup)

Add the Metable trait to your models you need to be metable:

```
use Esslassi\Metable\Metable;

class User extends Eloquent
{
    use Metable;
    ...
}
```

#### Default Model Attribute values

[](#default-model-attribute-values)

Additionally, you can specify default values by assigning an array called `$defaultMetaValues` to the model. This configuration has two side effects:

1. If a meta attribute does not exist, the default value will be returned instead of null.
2. If you set a meta attribute to its default value, the row in the meta table will be removed, causing the default value to be returned as described in rule 1.

This is being the desired and expected functionality for most projects, but be aware that you may need to reimplement default functionality with your own custom accessors and mutators if this functionality does not fit your needs.

This functionality is most suited for meta entries that note exceptions to rules. For example: users re not admins (default value: not admin), nodes taken down for maintenance (default value: node up), etc. This means the table doesn't need to store data on every entry which is in the expected state, only those rows in the exceptional state, and allows the rows to have a default state upon creation without needing to add code to write it.

```
   public $defaultMetaValues = [
      'is_admin' => false,
   ];

```

Metable Proccess
----------------

[](#metable-proccess)

#### Setting Content Meta

[](#setting-content-meta)

To set a meta value on an existing attribute or create new data:

1. Fluent way: You can set meta values seamlessly just like you do with regular Eloquent models.
2. Metable checks if the attribute belongs to the model; if it doesn't, it will access the meta model to append or set a new meta value.

```
$user = new User;
$user->name = 'Esslassi Mohammed'; // model attribute
$user->country = 'Morocco'; // meta data attribute
$user->save(); // save model
```

You can use `setMeta` to set or add a meta value

```
$user = new User;
$user->name = 'Esslassi Mohammed';
$user->setMeta('country', 'Morocco');
$user->save();
```

Setting multiple metas:

```
$user = new User;
$user->name = 'Esslassi Mohammed';
$user->setMeta([
    'country' => 'Morocco',
    'city' => 'Fez'
    ...
]);
$user->save();
```

Setting multiple metas with model columns:

```
$user = new User;
$user->setAttributes([
    'name' => 'Esslassi Mohammed',
    'country' => 'Morocco',
    'city' => 'Fez'
    ...
]);
$user->save();
```

Using standard `create` method to create model:

> If an attribute doesn't exists on model attributes it will added as meta values.

```
User::create([
    'name' => 'Esslassi Mohammed',
    'country' => 'Morocco',
    'city' => 'Fez'
    ...
]);
```

#### Removing Content Meta

[](#removing-content-meta)

As usual if you want to remove a meta value you can use `unset` and the save the model:

```
$user = User::find(1);
$user->name // model attribute
unset($user->country) // remove meta on save
$user->save();
```

Using `removeMeta`:

```
$user = User::find(1);
$user->removeMeta('country');
$user->save();
```

Removing multiple metas:

```
$user = User::find(1);

$user->removeMeta(['country', 'city']);
OR
$user->removeMeta('country', 'city');

$user->save();
```

Deleting all meta at once:

```
$user = User::find(1);
$user->deleteAllMeta();
```

> **Note:** This function will delete all metas from database directly with no rollback available.

#### Checking for Metas

[](#checking-for-metas)

To see if a piece of content has a meta:

```
...
if (isset($user->country)) {
    ...
}
...
```

You can check if meta exists by `hasMeta` method:

```
...
if ($user->hasMeta('country')){

}
...
```

You may also check if model has multiple metas:

```
//By providing an array
$user->hasMeta(['country', 'city']);
// By pipe spliter
$user->hasMeta('country|city');
// By comma spliter
$user->hasMeta('country,city');
```

> **Note:** It will return true only if all the metas exist.

If you provide a `true` in second arg it will return true even if meta marked for deletion:

```
$user = User::find(1);
$user->removeMeta('country');

$user->hasMeta('country', true); // Return true

$user->hasMeta('country'); // Return false
...
```

#### Retrieving Meta

[](#retrieving-meta)

> **Fluent way**, You can access meta data as if it is a property on your model. Just like you do on your regular eloquent models.

```
$user = User::find(1);
$user->name; // Return Eloquent value
$user->country; // Return meta value
```

You can retrieve a meta value by using the `getMeta` method:

```
$user = $user->getMeta('country');
```

Or specify a default value, if not exists:

```
$user = $user->getMeta('country', 'Morocco');
```

> **Note:** default values set in the `$defaultMetaValues` property take precedence over any default value passed to this method.

You can also retrieve multiple meta values at once and receive them as an collection.

```
// By comma
$user = $user->getMeta('country,city');
// By pipe
$user = $user->getMeta('country|city');
// By an array
$user = $user->getMeta(['country', 'city']);
```

#### Disable Fluent Access

[](#disable-fluent-access)

In some cases you want to disable fluent access or setting:

```
protected $disableFluentMeta = true;
```

By setting that property, you will no longer setting or accessing to meta value by fluent way:

```
$user = User::find(1);
$user->country = 'Morocco';// This will not set meta, this action will call setAttribute() of model class.
$user->country;// Here will not retrieve meta
unset($user->country);// No action will take
isset($user->country);// Will not check if meta exists
```

So the only way to set a meta is calling `setMeta` or `addMeta` methods

#### Retrieving All Metas

[](#retrieving-all-metas)

To fetch all metas associated with a piece of content, use the `getMeta` without any params

```
$user = User::find(1);
$metas = $user->getAllMeta();
```

Meta Clauses
------------

[](#meta-clauses)

#### Where Meta Clauses

[](#where-meta-clauses)

You can use the meta query builder's `whereMeta` method to add `where` clauses to the meta query. The most basic call to the `whereMeta` method requires three arguments: the name of the column, the operator (which can be any of the database's supported operators), and the value to compare against the column's value.

For instance, the following query retrieves users whose country meta key value is 'Morocco':

```
$users = User::whereMeta('country', '=', 'Morocco')
    ->get();
```

For convenience, if you want to verify that a column equals a given value, you can pass the value as the second argument to the `whereMeta` method. The package will assume you want to use the `=` operator:

```
$users = User::whereMeta('country', 'Morocco')
    ->get();
```

#### Or Where Meta Clauses

[](#or-where-meta-clauses)

When chaining calls to the meta query builder's `whereMeta` method, the clauses will be joined using the `AND` operator. However, you can use the `orWhereMeta` method to join a clause to the meta query using the `OR` operator. The `orWhereMeta` method accepts the same arguments as the `whereMeta` method:

```
$users = User::whereMeta('country', 'Morocco')
    orWhereMeta('continent', 'Africa')
    ->get();
```

If you need to group an "or" condition within parentheses, this package doesn't support this option to do that just use Laravel where grouping:

```
$users = User::whereMeta('country', 'Morocco')
    ->orWhere(function (Builder $query) {
        $query->whereMeta('continent', 'Africa')
            ->whereMeta('competition', 'CAN');
    })
    ->get();
```

#### Where Meta Not Clauses

[](#where-meta-not-clauses)

The `whereMetaNot` and `orWhereMetaNot` methods can be used to negate specific query constraints. For example, the following query excludes users who live in Morocco:

```
$users = User::whereMetaNot('country', 'Morocco')
    ->get();
```

#### Where Meta Not Clauses

[](#where-meta-not-clauses-1)

The `whereMetaIn` and `orWhereMetaNotIn` methods testing if a meta in an array given:

```
$users = User::whereMetaIn('country', ['Morocco', 'Algeria', 'Egypt', 'Tunisia'])
    ->get();
```

#### Additional Where Clauses

[](#additional-where-clauses)

##### whereMetaNull / orWhereMetaNull

[](#wheremetanull--orwheremetanull)

The whereMetaNull method verifies that a meta's value is null:

```
$users = User::whereMetaNull('country')
    ->get();
```

##### whereMetaNotNull / orWhereMetaNotNull

[](#wheremetanotnull--orwheremetanotnull)

The whereMetaNotNull method verifies that a meta's value is not null:

```
$users = User::whereMetaNotNull('country')
    ->get();
```

##### whereMetaHas / orWhereMetaHas

[](#wheremetahas--orwheremetahas)

The whereMetaHas method verifies that a meta key exists:

```
$users = User::whereMetaNotNull('country')
    ->get();
```

##### whereMetaDoesntHave / orWhereMetaDoesntHave

[](#wheremetadoesnthave--orwheremetadoesnthave)

The whereMetaDoesntHave method verifies that a meta key not exists:

```
$users = User::whereMetaDoesntHave('country')
    ->get();
```

##### whereInMetaArray / whereNotInMetaArray (MySQL Only)

[](#whereinmetaarray--wherenotinmetaarray-mysql-only)

The whereInMetaArray method verifies if given value is in meta value. The following example retrieves users whose 'Morocco' in meta key value:

```
$users = User::whereInMetaArray('countries', 'Morocco')
    ->get();
```

> **Note:** This method is equals to Laravel's `whereJsonContains` but since value column's type is long text we couldn't work with it so we decided to create this method to help us with this problem.

Defining Relationships
----------------------

[](#defining-relationships)

Actually metable has one relationship so our trip in this section will be short.

### One to One

[](#one-to-one)

Imagin that we have in our app three roles `manager`, `driver`, `supervisor` but the only role must have a car is `driver` and you can't set forign key `user_id` to cars table because a car can be driven by one or more drivers:

```
users
    id - integer
    name - string
    role - string

cars
    id - integer
    model - string
    marque - string

```

So we decided to create an metable relationship calls MetaOne with initialization method `hasMetaOne`:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Esslassi\Metable\Relations\MetaOne;

class User extends Model
{
    /**
     * Get the car.
     */
    public function car(): MetaOne
    {
        return $this->hasMetaOne(Car::class, 'car_id');
    }
}
```

The first argument passed to the hasMetaOne method is the name of the final model we wish to access, while the second argument is the name of the meta key.

```
$user = User::find(1);
$car = $user->car;
```

#### Key Conventions

[](#key-conventions)

Basically metable automatically recognize the local key of the model but the meta key name is required. So no need to identify the local key. If you would like to customize the local key of the relationship, you may pass it as the third argument to the hasMetaOne method.

```
class User extends Model
{
    /**
     * Get the car.
     */
    public function car(): MetaOne
    {
        return $this->hasMetaOne(
            Car::class,
            'car_id', // Meta key of the users meta...
            'id' // Local key on the users table...
        );
    }
}
```

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

11

Last Release

769d ago

Major Versions

1.9.0 → 2.0.02024-05-24

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/54247306?v=4)[MOHAMMED ESSLASSI](/maintainers/esslassi)[@esslassi](https://github.com/esslassi)

---

Top Contributors

[![esslassi](https://avatars.githubusercontent.com/u/54247306?v=4)](https://github.com/esslassi "esslassi (10 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/esslassi-metable/health.svg)

```
[![Health](https://phpackages.com/badges/esslassi-metable/health.svg)](https://phpackages.com/packages/esslassi-metable)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.4M96](/packages/mongodb-laravel-mongodb)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8793.2M25](/packages/yajra-laravel-oci8)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45444.2k1](/packages/pressbooks-pressbooks)[watson/validating

Eloquent model validating trait.

9803.5M54](/packages/watson-validating)[glushkovds/phpclickhouse-laravel

Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel

2051.5M2](/packages/glushkovds-phpclickhouse-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
