faizansf/laravel-metafields

This package enhances Laravel Models by introducing Meta field functionality.

1.0.2 2024-01-31 19:00 UTC

This package is auto-updated.

Last update: 2024-10-31 00:33:15 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status

The Laravel Metafields package is a versatile and powerful tool designed for Laravel developers who need to extend their models with metafield functionality. This package enables you to effortlessly attach additional custom fields (metafields) to any Eloquent model in your Laravel application, providing a seamless way to enhance your models with extra data without altering your database schema.

Use Cases:

This package is ideal for projects that require additional data storage like CMS, e-commerce platforms, and custom CRM systems. It's particularly useful in scenarios where the database schema needs to remain unchanged while still allowing for data extension.

Installation

You can install the package via composer:

composer require faizansf/laravel-metafields

You can publish and run the migrations with:

php artisan vendor:publish --tag="metafields-migrations"
php artisan migrate

Note:
Before running the migrations make sure you have set the correct configuration

You can publish the config file with:

php artisan vendor:publish --tag="metafields-config"

Configuration

return [
    // The name of the database table to store metafields.
    'table' => 'metafields',

    // The name of the column in the 'meta_fields' table that references the model.
    'model_column_name' => 'model',

    // An array of classes that are allowed to be unserialized.
    'unserialize_allowed_class' => [],

    // The class responsible for serializing the values stored in metafields.
    'default_serializer' => \FaizanSf\LaravelMetafields\Support\ValueSerializers\StandardValueSerializer::class,

    // Flag to enable or disable caching of metafields.
    'cache_metafields' => true,

    // Time-to-live for cached meta fields. Null indicates caching forever.
    'cache_ttl' => null,

    // The prefix used for cache keys when storing individual metafield values.
    'cache_key_prefix' => 'LaravelMetafields',

    //Block keys from being used as metafield keys
    'not_allowed_keys' => [],
    
    //Cache key for all metafields collection
    'all_metafields_cache_key' => 'all-metafields'
];

Integrating in Model

Integrate the Metafiedable contract and the HasMetafields trait into your model

...
use FaizanSf\LaravelMetafields\Concerns\HasMetafields;
use FaizanSf\LaravelMetafields\Contracts\Metafieldable;

class Person extends Model implements Metafieldable
{
    use HasMetafields;
     
    ...
}

Usage

To set a metafield, use string or string backed enum key and value as below:

$person = Person::find(1);

//using HasMetafields trait
$person->setMetafield('some-key', 'value')

To get metafield value use:

//using HasMetafields trait
$person->getMetafield('some-key');
$person->getAllMetafields();

You can also provide a default value when getting a metafield

//using HasMetafields trait
$person->getMetafield('some-key', 'default value');

Note:
A default value is not persisted in the database and is just returned whenever the actual value is null

Similarly, metafields can be deleted as follows:

//using HasMetafields trait
$person->deleteMetafield('some-key');
$person->deleteAllMetaField('some-key');

Cache

Caching is enabled by default, but can be disabled in your metafields.php configuration file. To control caching behavior in your model class, add the $shouldCacheMetafields property. Setting this property in your model will override the default caching configuration. Additionally, you can specify a custom time-to-live (TTL) for the cache by adding the $ttl property to your model, allowing for fine-tuned cache duration control.


In the metafields.php config file

[
    ...
    // Flag to enable or disable caching of metafields.
    'cache_metafields' => true,
    ...
]

Or in your model class

...
class Person extends Model implements Metafieldable
{
    use HasMetafields;
    
    protected $shouldCacheMetafields = true;
    protected $ttl = 600
}

You can retrieve a non-cached version of the data by using the withoutCache() method. This method provides a straightforward way to bypass caching for a single call, ensuring you get the most up-to-date data.

//using HasMetafields trait
$person->withoutCache()->getMetafield('some-key');
$person->withoutCache()->getAllMetafields();

Serialization

The package includes StandardValueSerializer, DirectValueSerializer and JsonValueSerializer classes. You can choose a default serializer for all fields in the metafields.php configuration file. Additionally, you can define a $metafieldSerializers array inside your model, or you can implement a protected registerSerializers() method in your model to override the default serialization behavior. The registerSerializers() method will then use mapSerializer() method provided by HasMetafields trait to register the serializers. Any custom serializer class you add must implement the FaizanSf\LaravelMetafields\Contracts\ValueSerializer interface.


namespace App\ValueSerializers;

use FaizanSf\LaravelMetafields\Contracts\ValueSerializer;
use Illuminate\Support\Arr;

class CustomSerializer implements ValueSerializer
{
    public function unserialize($serialized): mixed
    {
        //Do some custom logic here
    }

    public function serialize($value): string
    {
        //Do some custom logic here
    }
}

And then in your model

...
class Person extends Model implements Metafieldable
{
    use HasMetafields;
    
    protected function registerSerializers(){
        $this
            ->mapSerializer('some-key', CustomSerializer::class)
            ->mapSerializer(PersonMetafieldsEnum::Name, CustomSerializer::class)
    }
}

Alternatively, you can also define $metafieldSerializers property directly into your model

...
class Person extends Model implements Metafieldable
{
    use HasMetafields;
    
    protected array $metafieldSerializers  = [
         'my-custom-metafield' => CustomSerializer::class,
         ExampleMetafieldsEnum::ExampleField->value => CustomSerializer::class
    ];
}

Note:
Due to PHP's restriction where enums can't be used as array keys, we need to utilize the enum values for mapping serializers.


In situations where you already possess a string value that doesn't require serialization, the DirectValueSerializer can be used. This allows you to bypass the usual serialization process, streamlining the handling of such pre-formatted or non-serializable values.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

License

The MIT License (MIT). Please see License File for more information.