PHPackages                             kodeine/laravel-meta - 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. kodeine/laravel-meta

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

kodeine/laravel-meta
====================

Fluent Meta Data for Eloquent Models, as if it is a property on your model.

2.2.5(1y ago)426756.0k—2%88[1 PRs](https://github.com/kodeine/laravel-meta/pulls)8MITPHPPHP &gt;=7.3

Since Sep 28Pushed 1y ago11 watchersCompare

[ Source](https://github.com/kodeine/laravel-meta)[ Packagist](https://packagist.org/packages/kodeine/laravel-meta)[ RSS](/packages/kodeine-laravel-meta/feed)WikiDiscussions 2.0 Synced 1mo ago

READMEChangelog (10)Dependencies (4)Versions (19)Used By (8)

Fluent Meta Data for Eloquent Models
====================================

[](#fluent-meta-data-for-eloquent-models)

[![Laravel](https://camo.githubusercontent.com/617de9936c8f5cf9445121bfecd60bab3acbd0fc8aa7424adaee4f86cf11de44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d7e382e302d677265656e2e7376673f7374796c653d666c61742d737175617265)](http://laravel.com)[![Source](https://camo.githubusercontent.com/23388f4cddf7a7a045716b5ac4c68dedc7947c2b33102aba548df3cde0ae8e2e/687474703a2f2f696d672e736869656c64732e696f2f62616467652f736f757263652d6b6f6465696e652f6c61726176656c2d2d6d6574612d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/kodeine/laravel-meta/)[![Build Status](https://camo.githubusercontent.com/f68fb93b5f112eb1366b9d78123b99058df3aeb88b36bdf5d4e6684ed982cdc9/687474703a2f2f696d672e736869656c64732e696f2f7472617669732f6b6f6465696e652f6c61726176656c2d2d6d6574612f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/kodeine/laravel-meta)[![License](https://camo.githubusercontent.com/30597ff9a350144f03bffdd9183e16468e0b3ca1193e1d08591d992622738d55/687474703a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://tldrlegal.com/license/mit-license)

Metable Trait adds the ability to access meta data as if it is a property on your model. Metable is Fluent, just like using an eloquent model attribute you can set or unset metas. Follow along the documentation to find out more.

Changelog
---------

[](#changelog)

visit [CHANGELOG.md](CHANGELOG.md)

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

[](#installation)

#### Composer

[](#composer)

Laravel meta can be installed on laravel `8.x` or higher.

Run:

```
composer require kodeine/laravel-meta

```

For laravel 7.x or below visit [this link](https://github.com/kodeine/laravel-meta/tree/master).

#### Upgrade guide

[](#upgrade-guide)

Change this line in `composer.json`:

```
"kodeine/laravel-meta": "master"

```

to:

```
"kodeine/laravel-meta": "^2.0"

```

after that, run `composer update` to upgrade the package.

##### Upgrade notice

[](#upgrade-notice)

Laravel meta 2 has some backward incompatible changes that listed below:

1. Laravel 7 or lower not supported.
2. Removed the following methods: `__get`, `__set`, `__isset`. If you have defined any of these methods, then you probably have something like this in your model:

    ```
    class User extends Model{
        use Metable{
            __get as __metaGet
        }
    ```

    You need to remove `as` operator of the methods.
3. Removed legacy getter. in older version if you had a method called `getSomething()` then you could access return value of this method using `$model->something`. this is no longer the case, and you have to call `$model->getSomething()`.
4. Added new method `setAttribute` that overrides parent method.
5. Renamed `getMetaDefaultValue` method to `getDefaultMetaValue`.
6. Second parameter of `getMeta` method is now default value when meta is null.
7. Removed `whereMeta` method in favor of `scopeWhereMeta`. example: `User::whereMeta($key,$value)->get();`
8. Removed `getModelKey` method.

#### Migration Table Schema

[](#migration-table-schema)

Each model needs its own meta table.

This is an example migration. you need change parts of it.

In this example we assume you have a model named `Post`.

Meta table name should be your model's table name + `_meta` which in this case, model's table name is pluralized form of the model name. so the table name becomes `posts_meta`.

If you don't want to follow this naming convention and use something else for table name, make sure you add this name to your model's body:

```
protected $metaTable = 'custom_meta_table';
```

the foreign key name should be your model's name + `_id` = `post_id`

If you used something else for foreign key, make sure you add this to your model's body:

```
protected $metaKeyName = 'custom_foreign_key';
```

```
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
    Schema::create('posts_meta', function (Blueprint $table) {
        $table->bigIncrements('id');

        $table->bigInteger('post_id')->unsigned();
        $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');

        $table->string('type')->default('null');

        $table->string('key')->index();
        $table->text('value')->nullable();

        $table->timestamps();
    });
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
    Schema::drop('posts_meta');
}
```

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

[](#configuration)

#### Model Setup

[](#model-setup)

Next, add the `Metable` trait to each of your metable model definition:

```
use Kodeine\Metable\Metable;

class Post extends Eloquent
{
    use Metable;
}
```

Metable Trait will automatically set the meta table based on your model name. Default meta table name would be, `models_meta` where `models` is pluralized form of the model name. In case you need to define your own meta table name, you can specify in model:

```
class Post extends Eloquent
{
    protected $metaTable = 'posts_meta'; //optional.
}
```

#### Default Model Attribute values

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

Additionally, you can set default values by setting an array called `$defaultMetaValues` on the model. Setting default has two side effects:

1. If a meta attribute does not exist, the default value will be returned instead of `null`.
2. if you attempt to set a meta attribute to the default value, the row in the meta table will be removed, which will cause the default value to be returned, as per 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: employees sick out of office (default value: in office), 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_user_home_sick' => false,
   ];

```

> **Note:** Make sure to use lowercase keys.

#### Gotcha

[](#gotcha)

When you extend a model and still want to use the same meta table you must override `getMetaKeyName` function.

```
class Post extends Eloquent
{

}

class Slideshow extends Post
{
    protected function getMetaKeyName()
    {
        return 'post_id' // The parent foreign key
    }
}

```

Working With Meta
-----------------

[](#working-with-meta)

#### Setting Content Meta

[](#setting-content-meta)

To set a meta value on an existing piece of content or create a new data:

> **Fluent way**, You can **set meta flawlessly** as you do on your regular eloquent models. Metable checks if attribute belongs to model, if not it will access meta model to append or set a new meta.

```
$post = Post::find(1);
$post->name = 'hello world'; // model attribute
$post->content = 'some content goes here'; // meta data attribute
$post->save(); // save attributes to respective tables
```

Or

```
$post = Post::find(1);
$post->name = 'hello world'; // model attribute
$post->setMeta('content', 'Some content here');
$post->save();
```

Or `set multiple metas` at once:

```
...
$post->setMeta([
    'content' => 'Some content here',
    'views' => 1,
]);
$post->save();
```

Or `set multiple metas and columns` at once:

```
...
$post->setAttributes([
    'name' => 'hello world', // model attribute
    'content' => 'Some content here',
    'views' => 1,
]);
$post->save();
```

> **Note:** If a piece of content already has a meta the existing value will be updated.

You can also save metas with `saveMeta` without saving the model itself:

```
$post->content = 'some content goes here'; // meta data attribute
$post->saveMeta(); // will save metas to database but won't save the model itself
```

#### Unsetting Content Meta

[](#unsetting-content-meta)

Similarly, you may unset meta from an existing piece of content:

> **Fluent way** to unset.

```
$post = Post::find(1);
$post->name // model attribute
unset($post->content) // delete meta on save
$post->save();
```

Or

```
$post->unsetMeta('content');
$post->save();
```

Or `unset multiple metas` at once:

```
$post->unsetMeta('content,views');
// or
$post->unsetMeta('content|views');
// or
$post->unsetMeta('content', 'views');
// or array
$post->unsetMeta(['content', 'views']);

$post->save();
```

> **Note:** The system will not throw an error if the content does not have the requested meta.

#### Checking for Metas

[](#checking-for-metas)

To see if a piece of content has a meta:

> **Fluent way**, Metable is clever enough to understand $post-&gt;content is an attribute of meta.

```
if (isset($post->content)) {

}
// or
if ($post->hasMeta('content')){

}
```

You may also check if model has multiple metas:

```
$post->hasMeta(['content','views']); // returns true only if all the metas exist
// or
$post->hasMeta('content|views');
// or
$post->hasMeta('content,views');
```

#### Retrieving Meta

[](#retrieving-meta)

To retrieve a meta value on a piece of content, use the `getMeta` method:

> **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.

```
$post = Post::find(1);
dump($post->name);
dump($post->content); // will access meta.
```

Or

```
$post = $post->getMeta('content');
```

Or specify a default value, if not set:

```
$post = $post->getMeta('content', 'Something');
```

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

You may also retrieve more than one meta at a time and get an illuminate collection:

```
// using comma or pipe
$post = $post->getMeta('content|views');
// or an array
$post = $post->getMeta(['content', 'views']);
// specify default values
$post->getMeta(['content', 'views'],['content'=>'something','views'=>0]);
// or specify one default value for all missing metas
$post->getMeta(['content', 'views'],'none');// result if the metas are missing: ['content'=>'none','views'=>'none']
// without specifying default value result will be null
$post->getMeta(['content', 'views']);// result if the metas are missing: ['content'=>null,'views'=>null]
```

#### Disable Fluent Access

[](#disable-fluent-access)

If you don't want to access metas in fluent way, you can disable it by adding following property to your model:

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

By setting that property, this package will no longer handle metas in the following ways:

```
$post->content='something';// will not set meta. original laravel action will be taken
$post->content;// will not retrieve meta
unset($post->content);// will not unset meta
isset($post->content);// will not check if meta exists
```

#### Using Original `getAttribute` and `setAttribute` Methods

[](#using-original-getattribute-and-setattribute-methods)

Laravel meta overrides these Laravel methods for fluent access. If you’ve already disabled fluent access using the method above, these methods' behavior won't change. Otherwise, you can use `getAttributeRaw` and `setAttributeRaw` to access the original methods.

#### Retrieving All Metas

[](#retrieving-all-metas)

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

```
$metas = $post->getMeta();
```

#### Retrieving an Array of All Metas

[](#retrieving-an-array-of-all-metas)

To fetch all metas associated with a piece of content and return them as an array, use the `toArray` method:

```
$metas = $post->getMeta()->toArray();
```

#### Meta Table Join

[](#meta-table-join)

When you need to filter your model based on the meta data , you can use `meta` scope in Eloquent Query Builder.

```
$post = Post::meta()
    ->where(function($query){
          $query->where('posts_meta.key', '=', 'revision')
                ->where('posts_meta.value', '=', 'draft');
    })
```

Alternatively you can use `whereMeta` scope to simplify your code:

```
$post = Post::whereMeta($key, $value, $alias = null, $operator = '=')->get();// "alias" and "operator" parameters are optional.
```

#### Eager Loading

[](#eager-loading)

When you need to retrieve multiple results from your model, you can eager load `metas`

```
$post = Post::with(['metas'])->get();
```

#### Prevent metas attribute from being populated

[](#prevent-metas-attribute-from-being-populated)

When you convert a model to an array (or json) and you don't need all meta fields, you can create a model's property to prevent metas from being added to the resulting array. You can also use it on eloquent relations.

```
/* Post model */
public $hideMeta = true; // Do not add metas to array
```

Events
------

[](#events)

Laravel meta dispatches several events, allowing you to hook into the following events: `metaCreating`, `metaCreated`, `metaSaving`, `metaSaved`, `metaUpdating`, `metaUpdated`, `metaDeleting` and `metaDeleted`. Listeners should expect two parameters, first an instance of the model and second, name of the meta that event occurred for it. To enable events you need to add `HasMetaEvents` trait to your model:

```
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;
}
```

After that, you can listen for events the [same way](https://laravel.com/docs/master/eloquent#events) you do for models.

> If you `return false;` in listener of any event ending with `ing`, that operation will be aborted.

### Additional events

[](#additional-events)

There are some additional events that extend existing laravel events. These events don't need `HasMetaEvents` trait and like default laravel events, the event listeners should expect one parameter. Event names: `createdWithMetas`, `updatedWithMetas`, `savedWithMetas`. These events fire exactly like default laravel events except that they are only fired after all metas saved to database. For example, you may need to access metas inside a queue job after model created. But because metas have not been saved to database yet (metas will be saved to database in `saved` event and this event has not been fired yet), job can't access them. by using `createdWithMetas` event instead of `created` event, the problem will be solved.

There are 3 ways to listen for events:

#### 1. By Defining `$dispatchesEvents` Property

[](#1-by-defining-dispatchesevents-property)

```
use App\Events\UserMetaSaved;
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;

    protected $dispatchesEvents = [
        'metaSaved' => UserMetaSaved::class,
    ];
}
```

#### 2. [Using Closures](https://laravel.com/docs/master/eloquent#events-using-closures)

[](#2-using-closures)

```
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;

    protected static function booted()
    {
        static::metaCreated(function ($user, $meta) {
            //
        });
    }
}
```

#### 3. [Observers](https://laravel.com/docs/master/eloquent#observers)

[](#3-observers)

```
class UserObserver
{
    public function metaCreated(User $user,$meta)
    {
        //
    }
}
```

###  Health Score

53

—

FairBetter than 97% of packages

Maintenance46

Moderate activity, may be stable

Popularity59

Moderate usage in the ecosystem

Community38

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~118 days

Recently: every ~105 days

Total

18

Last Release

404d ago

Major Versions

1.0.6 → 2.0.02022-06-05

PHP version history (2 changes)1.0.0PHP &gt;=5.4.0

2.0.0PHP &gt;=7.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/65c900c1f43775893b9ff90fdd9d31f32f5136a20c9b57d35d773bea7d695b5b?d=identicon)[kodeine](/maintainers/kodeine)

---

Top Contributors

[![siamak2](https://avatars.githubusercontent.com/u/20032689?v=4)](https://github.com/siamak2 "siamak2 (88 commits)")[![kodeine](https://avatars.githubusercontent.com/u/8620059?v=4)](https://github.com/kodeine "kodeine (53 commits)")[![stephandesouza](https://avatars.githubusercontent.com/u/159077?v=4)](https://github.com/stephandesouza "stephandesouza (7 commits)")[![todiadiyatmo](https://avatars.githubusercontent.com/u/2767210?v=4)](https://github.com/todiadiyatmo "todiadiyatmo (5 commits)")[![falestra](https://avatars.githubusercontent.com/u/12063138?v=4)](https://github.com/falestra "falestra (4 commits)")[![bfiessinger](https://avatars.githubusercontent.com/u/41627893?v=4)](https://github.com/bfiessinger "bfiessinger (4 commits)")[![olsgreen](https://avatars.githubusercontent.com/u/1324164?v=4)](https://github.com/olsgreen "olsgreen (4 commits)")[![AoumiS](https://avatars.githubusercontent.com/u/2528896?v=4)](https://github.com/AoumiS "AoumiS (3 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (3 commits)")[![philipnewcomer](https://avatars.githubusercontent.com/u/1446874?v=4)](https://github.com/philipnewcomer "philipnewcomer (3 commits)")[![dhcmega](https://avatars.githubusercontent.com/u/6719578?v=4)](https://github.com/dhcmega "dhcmega (2 commits)")[![sumityadav](https://avatars.githubusercontent.com/u/169143?v=4)](https://github.com/sumityadav "sumityadav (2 commits)")[![benyanke](https://avatars.githubusercontent.com/u/4274911?v=4)](https://github.com/benyanke "benyanke (2 commits)")[![goodevilgenius](https://avatars.githubusercontent.com/u/254662?v=4)](https://github.com/goodevilgenius "goodevilgenius (2 commits)")[![plivius](https://avatars.githubusercontent.com/u/1803825?v=4)](https://github.com/plivius "plivius (2 commits)")[![SebastienKPA6T](https://avatars.githubusercontent.com/u/177635074?v=4)](https://github.com/SebastienKPA6T "SebastienKPA6T (1 commits)")[![shemi](https://avatars.githubusercontent.com/u/10219407?v=4)](https://github.com/shemi "shemi (1 commits)")[![darrencoutts118](https://avatars.githubusercontent.com/u/9951843?v=4)](https://github.com/darrencoutts118 "darrencoutts118 (1 commits)")[![SneherAdor](https://avatars.githubusercontent.com/u/24508783?v=4)](https://github.com/SneherAdor "SneherAdor (1 commits)")[![ChrisThompsonTLDR](https://avatars.githubusercontent.com/u/348801?v=4)](https://github.com/ChrisThompsonTLDR "ChrisThompsonTLDR (1 commits)")

---

Tags

laraveldatamodeleloquentmetadatametameta datametaskodeinemetable

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/kodeine-laravel-meta/health.svg)

```
[![Health](https://phpackages.com/badges/kodeine-laravel-meta/health.svg)](https://phpackages.com/packages/kodeine-laravel-meta)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k7.2M71](/packages/mongodb-laravel-mongodb)[dyrynda/laravel-model-uuid

This package allows you to easily work with UUIDs in your Laravel models.

4802.8M8](/packages/dyrynda-laravel-model-uuid)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[cybercog/laravel-ban

Laravel Ban simplify blocking and banning Eloquent models.

1.1k651.8k11](/packages/cybercog-laravel-ban)[pdphilip/elasticsearch

An Elasticsearch implementation of Laravel's Eloquent ORM

145360.2k4](/packages/pdphilip-elasticsearch)

PHPackages © 2026

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