{"id":21327599,"url":"https://github.com/kolossal-io/laravel-multiplex","last_synced_at":"2025-04-13T04:14:02.641Z","repository":{"id":61754681,"uuid":"554284806","full_name":"kolossal-io/laravel-multiplex","owner":"kolossal-io","description":"A Laravel package to attach time-sliced meta data to Eloquent models.","archived":false,"fork":false,"pushed_at":"2024-03-26T16:15:51.000Z","size":285,"stargazers_count":253,"open_issues_count":1,"forks_count":10,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-03-27T12:54:47.022Z","etag":null,"topics":["eloquent","fluent","laravel","meta","metadata","timetravel"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kolossal-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-10-19T14:55:31.000Z","updated_at":"2024-04-15T10:57:46.547Z","dependencies_parsed_at":"2023-02-01T05:46:24.976Z","dependency_job_id":"19eb8ec8-2477-4773-9e34-bffacea714d8","html_url":"https://github.com/kolossal-io/laravel-multiplex","commit_stats":{"total_commits":116,"total_committers":6,"mean_commits":"19.333333333333332","dds":"0.19827586206896552","last_synced_commit":"a9332f37ffe05f0c038dcb809e7dc32a53af86eb"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kolossal-io%2Flaravel-multiplex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kolossal-io%2Flaravel-multiplex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kolossal-io%2Flaravel-multiplex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kolossal-io%2Flaravel-multiplex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kolossal-io","download_url":"https://codeload.github.com/kolossal-io/laravel-multiplex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248654724,"owners_count":21140352,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eloquent","fluent","laravel","meta","metadata","timetravel"],"created_at":"2024-11-21T21:18:27.024Z","updated_at":"2025-04-13T04:14:02.602Z","avatar_url":"https://github.com/kolossal-io.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cbr /\u003e\n  \u003ca href=\"https://github.com/kolossal-io/laravel-multiplex\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/logo-dark.svg\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/logo-light.svg\"\u003e\n      \u003cimg alt=\"Multiplex\" src=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/logo-light.svg\" width=\"316\" height=\"72\" style=\"max-width: 100%;\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  A Laravel package to attach time-sliced meta data to Eloquent models.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://packagist.org/packages/kolossal-io/laravel-multiplex\"\u003e\u003cimg src=\"https://img.shields.io/badge/Laravel-^9.0|^10.0|^11.0-green.svg?style=flat-square\" alt=\"Laravel\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/kolossal-io/laravel-multiplex\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/kolossal-io/laravel-multiplex.svg?style=flat-square\" alt=\"Latest Version on Packagist\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/kolossal-io/laravel-multiplex\" \u003e \n    \u003cimg src=\"https://codecov.io/gh/kolossal-io/laravel-multiplex/branch/main/graph/badge.svg?token=330354GI30\"/\u003e \n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/kolossal-io/laravel-multiplex/actions/workflows/tests.yml\"\u003e\u003cimg src=\"https://github.com/kolossal-io/laravel-multiplex/actions/workflows/tests.yml/badge.svg\" alt=\"GitHub Tests Action Status\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"#table-of-contents\"\u003eView Table of Contents\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## What it does\n\nMultiplex allows you to attach time-sliced metadata to Eloquent models in a convenient way.\n\n```php\n$post = \\App\\Models\\Post::first();\n\n// Set meta fluently for any key – `likes` is no column of `Post`.\n$post-\u003elikes = 24;\n\n// Or use the `setMeta` method.\n$post-\u003esetMeta('likes', 24);\n\n// You may also schedule changes, for example change the meta in 2 years:\n$post-\u003esetMetaAt('likes', 6000, '+2 years');\n```\n\n## Features\n\n-   Metadata is saved in versions: Schedule changes to metadata, change history or retrieve metadata for a specific point in time.\n-   Supports fluent syntax: Use your model’s metadata as if they were properties.\n-   Polymorphic relationship allows adding metadata to any Eloquent model without worrying about the database schema.\n-   Easy to try: Extend existing database columns of your model with versionable metadata without touching or deleting your original columns.\n-   Type conversion system heavily based on [Laravel-Metable](https://github.com/plank/laravel-metable) allows data of numerous different scalar and object types to be stored and retrieved.\n\n## Why another Metadata Package?\n\nThe main difference is that the metadata in Multiplex has a timestamp that defines validity. This allows changes to be tracked and planned. You can inspect all metadata on your model at a specific point in time and Multiplex will by default only give you the most current.\n\nSince Multiplex is storing the metadata in a [polymorphic](https://laravel.com/docs/9.x/eloquent-relationships#polymorphic-relationships) table, it can easily be plugged into existing projects to expand properties of your models. This even works without removing the relevant table columns of your model: They are used as a fallback.\n\nAnd it’s low profile: If you don't like it, just [remove the `HasMeta` Trait](#installation) and everything is back to normal.\n\n## Table of Contents\n\n-   [Installation](#installation)\n-   [Attaching Metadata](#attaching-metadata)\n-   [Retrieving Metadata](#retrieving-metadata)\n-   [Query by Metadata](#query-by-metadata)\n-   [Events](#events)\n-   [Time Traveling](#time-traveling)\n-   [Limit Meta Keys](#limit-meta-keys)\n-   [Extending Database Columns](#extending-database-columns)\n-   [Deleting Metadata](#deleting-metadata)\n-   [Performance](#performance)\n-   [Configuration](#configuration)\n-   [Enum Support](#enum-support)\n-   [UUID and ULID Support](#uuid-and-ulid-support)\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require kolossal-io/laravel-multiplex\n```\n\nPublish the migrations to create the `meta` table where metadata will be stored.\n\n```bash\nphp artisan migrate\n```\n\nAttach the `HasMeta` trait to any Eloquent model that needs meta attached.\n\n```php\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Kolossal\\Multiplex\\HasMeta;\n\nclass Post extends Model\n{\n    use HasMeta;\n}\n```\n\n## Attaching Metadata\n\nBy default you can use any `key` for attaching metadata. You can [limit which keys can be used](#limit-meta-keys).\n\n```php\n$model-\u003esetMeta('foo', 'bar');\n// or\n$model-\u003efoo = 'bar';\n```\n\nYou may also set multiple meta values by passing an `array`.\n\n```php\n$model-\u003esetMeta([\n    'hide' =\u003e true,\n    'color' =\u003e '#000',\n    'likes' =\u003e 24,\n]);\n```\n\nAll metadata will be stored automatically when saving your model.\n\n```php\n$model-\u003efoo = 'bar';\n\n$model-\u003eisMetaDirty(); // true\n\n$model-\u003esave();\n\n$model-\u003eisMetaDirty(); // false\n```\n\nYou can also save your model without saving metadata.\n\n```php\n$model-\u003esaveWithoutMeta();\n\n$model-\u003eisMetaDirty(); // true\n\n$model-\u003esaveMeta();\n```\n\nYou can reset metadata changes that were not yet saved.\n\n```php\n$model-\u003eresetMeta();\n```\n\nMetadata can be stored right away without waiting for the parent model to be saved.\n\n```php\n// Save the given meta value right now.\n$model-\u003esaveMeta('foo', 123.45);\n\n// Save only specific keys of the changed meta.\n$model-\u003esetMeta(['color' =\u003e '#fff', 'hide' =\u003e false]);\n$model-\u003esaveMeta('color');\n$model-\u003eisMetaDirty('hide'); // true\n\n// Save multiple meta values at once.\n$model-\u003esaveMeta([\n    'color' =\u003e '#fff',\n    'hide' =\u003e true,\n]);\n```\n\n### Schedule Metadata\n\nYou can save metadata for a specific publishing date.\n\n```php\n$user = Auth::user();\n\n$user-\u003esaveMeta('favorite_band', 'The Mars Volta');\n$user-\u003esaveMetaAt('favorite_band', 'Portishead', '+1 week');\n\n// Changing taste in music: This will return `The Mars Volta` now but `Portishead` in a week.\n$user-\u003efavorite_band;\n```\n\nThis way you can change historic data as well.\n\n```php\n$user-\u003esaveMetaAt('favorite_band', 'Arctic Monkeys', '-5 years');\n$user-\u003esaveMetaAt('favorite_band', 'Tool', '-1 year');\n\n// This will return `Tool` – which is true since this is indeed a good band.\n$user-\u003efavorite_band;\n```\n\nYou may also save multiple metadata records at once.\n\n```php\n$user-\u003esetMeta('favorite_color', 'blue');\n$user-\u003esetMeta('favorite_band', 'Jane’s Addiction');\n$user-\u003esaveMetaAt('+1 week');\n\n// or\n\n$user-\u003esaveMetaAt([\n    'favorite_color' =\u003e 'blue',\n    'favorite_band' =\u003e 'Jane’s Addiction',\n], '+1 week');\n```\n\n### How Metadata is stored\n\nMultiplex will store metadata in a polymorphic table and take care of serializing and unserializing datatypes for you. The underlying polymorphic `meta` table may look something like this:\n\n| metable_type    | metable_id | key   | value | type    | published_at        |\n| --------------- | ---------: | ----- | ----: | ------- | ------------------- |\n| App\\Models\\Post |        `1` | color |  #000 | string  | 2022-11-29 13:13:45 |\n| App\\Models\\Post |        `1` | likes |    24 | integer | 2020-01-01 00:00:00 |\n| App\\Models\\Post |        `1` | hide  |  true | boolean | 2022-11-27 16:32:08 |\n| App\\Models\\Post |        `1` | color |  #fff | string  | 2030-01-01 00:00:00 |\n\nThe corresponding meta values would look like this:\n\n```php\n$post = Post::find(1);\n\n$post-\u003ecolor; // string(4) \"#000\"\n$post-\u003elikes; // int(24)\n$post-\u003ehide; // bool(true)\n\n// In the year 2030 `$post-\u003ecolor` will be `#fff`.\n```\n\n## Retrieving Metadata\n\nYou can access metadata as if they were properties on your model.\n\n```php\n$post-\u003elikes; // (int) 24\n$post-\u003ecolor; // (string) '#000'\n```\n\nOr use the `getMeta()` method to specify a fallback value for non-existent meta.\n\n```php\n$post-\u003egetMeta('likes', 0); // Use `0` as a fallback.\n```\n\nYou can also retrieve the `meta` relation on your model. This will only retrieve the most recent value per `key` that is released yet.\n\n```php\n$post-\u003esaveMeta([\n    'author' =\u003e 'Anthony Kiedis',\n    'color' =\u003e 'black',\n]);\n\n$post-\u003esaveMetaAt('author', 'Jimi Hendrix', '1970-01-01');\n$post-\u003esaveMetaAt('author', 'Omar Rodriguez', '+1 year');\n\n$post-\u003emeta-\u003epluck('value', 'key');\n\n/**\n * Illuminate\\Support\\Collection {\n *   all: [\n *     \"author\" =\u003e \"Anthony Kiedis\",\n *     \"color\" =\u003e \"black\",\n *   ],\n * }\n */\n```\n\nThere is a shorthand to pluck all the current meta data attached to the model. This will include all [explicitly defined meta keys](#limit-meta-keys) with a default of `null`.\n\n```php\n// Allow any meta key and explicitly allow `foo` and `bar`.\n$post-\u003emetaKeys(['*', 'foo', 'bar']);\n\n$post-\u003esaveMeta('foo', 'a value');\n$post-\u003esaveMeta('another', true);\n\n$post-\u003epluckMeta();\n/**\n * Illuminate\\Support\\Collection {\n *   all: [\n *     \"foo\" =\u003e \"a value\",\n *     \"bar\" =\u003e null,\n *     \"another\" =\u003e true,\n *   ],\n * }\n */\n```\n\nIf you instead want to retrieve all meta that was published yet, use the `publishedMeta` relation.\n\n```php\n// This array will also include `Jimi Hendrix´.\n$post-\u003epublishedMeta-\u003etoArray();\n```\n\nIf you want to inspect _all_ metadata including unpublished records, use the `allMeta` relation.\n\n```php\n$post-\u003eallMeta-\u003etoArray();\n```\n\nYou can determine if a `Meta` instance is the most recent published record for the related model or if it is not yet released.\n\n```php\n$meta = $post-\u003eallMeta-\u003efirst();\n\n$meta-\u003eis_current; // (bool)\n$meta-\u003eis_planned; // (bool)\n```\n\n### Querying `Meta` Model\n\nThere are also some query scopes on the `Meta` model itself that may be helpful.\n\n```php\nMeta::published()-\u003eget(); // Only current and historic meta.\n\nMeta::planned()-\u003eget(); // Only meta not yet published.\n\nMeta::publishedBefore('+1 week')-\u003eget(); // Only meta published by next week.\n\nMeta::publishedAfter('+1 week')-\u003eget(); // Only meta still unpublished in a week.\n\nMeta::onlyCurrent()-\u003eget(); // Only current meta without planned or historic data.\n\nMeta::withoutHistory()-\u003eget(); // Query without stale records.\n\nMeta::withoutCurrent()-\u003eget(); // Query without current records.\n```\n\nBy default these functions will use `Carbon::now()` to determine what metadata is considered the most recent, but you can also pass a datetime to look from.\n\n```php\n// Get records that have been current a month ago.\nMeta::onlyCurrent('-1 month')-\u003eget();\n\n// Get records that will not be history by tommorow.\nMeta::withoutHistory(Carbon::now()-\u003eaddDay())-\u003eget();\n```\n\n## Query by Metadata\n\n### Querying Metadata Existence\n\nYou can query records having meta data for the given key(s).\n\n```php\n// Find posts having at least one meta records for `color` key.\nPost::whereHasMeta('color')-\u003eget();\n\n// Or pass an array to find records having meta for at least one of the given keys.\nPost::whereHasMeta(['color', 'background_color'])-\u003eget();\n```\n\n### Querying Metadata Absence\n\nYou can query records not having meta data for the given key(s).\n\n```php\n// Find posts not having any meta records for `color` key.\nPost::whereDoesntHaveMeta('color')-\u003eget();\n\n// Or find records not having meta for any of the given keys.\nPost::whereDoesntHaveMeta(['color', 'background_color'])-\u003eget();\n```\n\n### Querying Metadata by Value\n\nYou can retrieve models having meta with the given key and value.\n\n```php\n// Find posts where the current attached color is `black`.\nPost::whereMeta('color', 'black')-\u003eget();\n\n// Find posts where the current attached color is not `black`.\nPost::whereMeta('color', '!=', 'black')-\u003eget();\n\n// Find posts that are `visible`.\nPost::whereMeta('visible', true)-\u003eget();\n\n// There are alternatives for building `or` clauses for all scopes.\nPost::whereMeta('visible', true)-\u003eorWhere('hidden', false)-\u003eget();\n```\n\nMultiplex will take care of finding the right datatype for the passed query.\n\n```php\n// Matches only meta records with type `boolean`.\nPost::whereMeta('hidden', false)-\u003eget();\n\n// Matches only meta records with type `datetime`.\nPost::whereMeta('release_at', '\u003c=', Carbon::now())-\u003eget();\n```\n\nYou may also query by an array if values. Each array value will be typecasted individually.\n\n```php\n// Find posts where `color` is `black` (string) or `false` (boolean).\nPost::whereMetaIn('color', ['black', false])-\u003eget();\n```\n\nIf you would like to query without typecasting use `whereRawMeta()` instead.\n\n```php\nPost::whereRawMeta('hidden', '')-\u003eget();\n\nPost::whereRawMeta('likes', '\u003e', '100')-\u003eget();\n```\n\nYou can also define which [datatype](config/multiplex.php) to use.\n\n```php\nPost::whereMetaOfType('integer', 'count', '0')-\u003eget();\n\nPost::whereMetaOfType('null', 'foo', '')-\u003eget();\n```\n\n### Querying empty or non-empty Metadata\n\nYou can query for empty or non-empty metadata where `null` or empty strings would be considered being empty.\n\n```php\nPost::whereMetaEmpty('favorite_band')-\u003eget();\n\n// Get all posts having meta names `likes` and `comments` where *both* of them are not empty.\nPost::whereMetaNotEmpty(['likes', 'comments'])-\u003eget();\n```\n\n## Events\n\nYou can listen for the following events that will be fired by Multiplex.\n\n### `MetaHasBeenAdded`\n\nThis event will be fired once a new version of meta is saved to the model.\n\n```php\nuse Kolossal\\Multiplex\\Events\\MetaHasBeenAdded;\n\nclass SomeListener\n{\n    public function handle(MetaHasBeenAdded $event)\n    {\n        $event-\u003emeta; // The Meta model that was added.\n        $event-\u003emodel; // The parent model, same as $event-\u003emeta-\u003emetable.\n        $event-\u003etype; // The class name of the parent model.\n    }\n}\n```\n\n### `MetaHasBeenRemoved`\n\nThis event will be fired once metadata is removed by using [`deleteMeta`](#deleting-metadata). The event will fire only once per key and the `$meta` property on the event will contain the latest meta only.\n\n```php\nuse Kolossal\\Multiplex\\Events\\MetaHasBeenRemoved;\n\nclass SomeListener\n{\n    public function handle(MetaHasBeenRemoved $event)\n    {\n        $event-\u003emeta; // The Meta model that was removed.\n        $event-\u003emodel; // The parent model, same as $event-\u003emeta-\u003emetable.\n        $event-\u003etype; // The class name of the parent model.\n    }\n}\n```\n\n## Time Traveling\n\nYou can get the metadata for a model at a specific point in time.\n\n```php\n$user = Auth::user()-\u003ewithMetaAt('-1 week');\n$user-\u003efavorite_band; // Tool\n$user-\u003ewithMetaAt(Carbon::now())-\u003efavorite_band; // The Mars Volta\n```\n\nThis way you can inspect the whole set of metadata that was valid at the time.\n\n```php\nPost::first()-\u003ewithMetaAt('2022-10-01 15:00:00')-\u003emeta-\u003epluck('value', 'key');\n```\n\nYou can also query by meta for a specific point in time.\n\n```php\nPost::travelTo(Carbon::now()-\u003esubWeeks(2))-\u003ewhereMetaIn('foo', [false, 0])-\u003eget();\n\nPost::travelTo(Carbon::now()-\u003eaddYears(2))-\u003ewhere('category', 'tech')-\u003eget();\n```\n\nRemember to travel back if you want to perform further actions.\n\n```php\nPost::travelTo(Carbon::now()-\u003esubYear())-\u003ewhere('category', 'tech')-\u003eget();\nPost::where('category', 'tech')-\u003eget(); // Will still look for meta published last year.\n\nPost::travelBack();\nPost::where('category', 'tech')-\u003eget(); // Find current meta.\n```\n\n## Limit Meta Keys\n\nYou can limit which keys can be used for metadata by setting `$metaKeys` on the model.\n\n```php\nclass Post extends Model\n{\n    use HasMeta;\n\n    protected array $metaKeys = [\n        'color',\n        'hide',\n    ];\n}\n```\n\nBy default all keys are allowed.\n\n```php\nprotected array $metaKeys = ['*'];\n```\n\nYou can also change the allowed meta keys dynamically.\n\n```php\n$model-\u003emetaKeys(['color', 'hide']);\n```\n\nYou might as well cast your attributes using the `MetaAttribute` cast which will automatically allow the attribute being used as a meta key.\n\n```php\nuse Kolossal\\Multiplex\\MetaAttribute;\n\nclass Post extends Model\n{\n    use HasMeta;\n\n    protected $metaKeys = [];\n\n    protected $casts = [\n        'body' =\u003e MetaAttribute::class,\n    ];\n}\n```\n\nTrying to assign a value to a meta key that is not allowed will throw a `Kolossal\\Multiplex\\Exceptions\\MetaException`.\n\nIf you have [Eloquent Strictness](https://laravel.com/docs/10.x/eloquent#configuring-eloquent-strictness) enabled it is recommended to [explicitely cast the meta attributes to `MetaAttribute`](https://github.com/kolossal-io/laravel-multiplex/issues/19#issuecomment-1584150675).\n\n## Typecast Meta Keys\n\nSometimes you may wish to force typecasting of meta attributes. You can bypass guessing the correct type and define which type should be used for specific meta keys.\n\n```php\nprotected array $metaKeys = [\n    'foo',\n    'count' =\u003e 'integer',\n    'color' =\u003e 'string',\n    'hide' =\u003e 'boolean',\n];\n```\n\n## Extending Database Columns\n\nBy default Multiplex will not touch columns of your model. But sometimes it might be useful to have meta records as an extension for your existing table columns.\n\nConsider having an existing `Post` model with only a `title` and a `body` column. By explicitely adding `body` to our array of meta keys `body` will be handled by Multiplex from now on – not touching the `posts` table, but using the database column as a fallback.\n\n```php\nclass Post extends Model\n{\n    use HasMeta;\n\n    protected $metaKeys = [\n        '*',\n        'body',\n    ];\n}\n```\n\n```php\n\\DB::table('posts')-\u003ecreate(['title' =\u003e 'A title', 'body' =\u003e 'A body.']);\n\n$post = Post::first();\n\n$post-\u003ebody; // A body.\n\n$post-\u003ebody = 'This. Is. Meta.';\n$post-\u003esave();\n\n$post-\u003ebody; // This. Is. Meta.\n$post-\u003edeleteMeta('body');\n\n$post-\u003ebody; // A body.\n```\n\nIn case of using Multiplex for extending table columns, Multiplex will remove the original column when retrieving models from the database so you don’t get stale data.\n\n## Deleting Metadata\n\nYou can delete any metadata associated with the model from the database.\n\n```php\n// Delete all meta records for the `color` key.\n$post-\u003edeleteMeta('color');\n\n// Or delete all meta records associated with the model.\n$post-\u003epurgeMeta();\n```\n\n## Performance\n\nSince Multiplex stores metadata in a polymorphic [One To Many](https://laravel.com/docs/9.x/eloquent-relationships#one-to-many-polymorphic-relations) relationship querying your models could easily result in a [`N+1` query problem](https://laravel.com/docs/9.x/eloquent-relationships#eager-loading).\n\nDepending on your use case you should consider eager loading the `meta` relation, for example using `$with` on your model. This might be especially useful if you are [extending database columns](#extending-database-columns).\n\n```php\n// Worst case: 26 queries if `color` is a meta value.\n$colors = Post::take(25)-\u003eget()-\u003emap(\n    fn ($post) =\u003e $post-\u003ecolor;\n);\n\n// Same result with only 2 queries.\n$colors = Post::with('meta')-\u003etake(25)-\u003eget()-\u003emap(\n    fn ($post) =\u003e $post-\u003ecolor;\n);\n```\n\n## Configuration\n\nThere is no need to configure anything but if you like, you can publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"multiplex-config\"\n```\n\n## Enum Support\n\nMultiplex supports [backed enumerations](https://www.php.net/manual/en/language.enumerations.backed.php) introduced in PHP 8.1 whereas basic enumerations would not work.\n\n```php\nenum SampleEnum: string\n{\n    case Hearts = 'hearts';\n    case Diamonds = 'diamonds';\n}\n\n$model-\u003esaveMeta('some_key', SampleEnum::Diamonds);\n\n// true\n$model-\u003esome_key === SampleEnum::Diamonds;\n```\n\n## UUID and ULID Support\n\nIf your application uses UUIDs or ULIDs for the model(s) using metadata, you may set the `multiplex.morph_type` setting to `uuid` or `ulid` **before** running the migrations. You might as well set the `MULTIPLEX_MORPH_TYPE` environment variable instead, if you don’t want to publish the configuration file.\n\nThis will ensure `Meta` models will use UUID/ULID and that proper keys and foreign keys are used when running the migrations.\n\n## Credits\n\nThis package is heavily based on and inspired by [Laravel-Metable](https://github.com/plank/laravel-metable) by [Sean Fraser](https://github.com/frasmage) as well as [laravel-meta](https://github.com/kodeine/laravel-meta) by [Kodeine](https://github.com/kodeine). The [Package Skeleton](https://github.com/spatie/package-skeleton-laravel) by the great [Spatie](https://spatie.be/) was used as a starting point.\n\n## License\n\n\u003cp\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://kolossal.io\" target=\"_blank\"\u003e\n    \u003cpicture\u003e\n        \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/kolossal-logo-dark.svg\"\u003e\n        \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/kolossal-logo-light.svg\"\u003e\n        \u003cimg alt=\"Multiplex\" src=\"https://raw.githubusercontent.com/kolossal-io/laravel-multiplex/HEAD/.github/kolossal-log-light.svg\" width=\"138\" height=\"32\" style=\"max-width: 100%;\"\u003e\n    \u003c/picture\u003e\n    \u003c/a\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n\u003c/p\u003e\n\nCopyright © [kolossal](https://kolossal.io). Released under [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkolossal-io%2Flaravel-multiplex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkolossal-io%2Flaravel-multiplex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkolossal-io%2Flaravel-multiplex/lists"}