Data Types

You can attach a number of different kinds of values to a Metable model. The data types that are supported by Laravel-Mediable out of the box are the following.

Meta encoded with different data types support different query scopes for filtering by meta value. See querying_meta for more information on available query scopes.

Scalar Values

The following scalar values are supported.

Boolean

<?php
$metable->setMeta('accepted_promotion', true);

Integer

<?php
$metable->setMeta('likes', 9001);

Float

<?php
$metable->setMeta('precision', 0.755);

Null

<?php
$metable->setMeta('linked_model', null);

String

<?php
$metable->setMeta('attachment', '/var/www/html/public/attachment.pdf');

Composite Values

The following classes and interfaces are supported.

Eloquent Models

It is possible to attach another Eloquent model to a Metable model.

<?php
$page = App\Page::where(['title' => 'Welcome'])->first();
$metable->setMeta('linked_model', $page);

When $metable->getMeta() is called, the attached model will be reloaded from the database.

It is also possible to attach a Model instance that has not been saved to the database.

<?php
$metable->setMeta('related', new App\Page);

When $metable->getMeta() is called, a fresh instance of the class will be created (will not include any attributes).

Eloquent Collections

Similarly, it is possible to attach multiple models to a key by providing an instance of Illuminate\Database\Eloquent\Collection containing the models.

As with individual models, both existing and unsaved instances can be stored.

<?php
$users = App\User::where(['title' => 'developer'])->get();
$metable->setMeta('authorized', $users);

DateTime & Carbon

Any object implementing the DateTimeInterface. Object will be converted to a Carbon instance when unserialized.

<?php
$metable->setMeta('last_viewed', \Carbon\Carbon::now());

DateTimeImmutable & CarbonImmutable

Any object extending the DateTimeImmutable class. Object will be converted to a CarbonImmutable instance when unserialized.

<?php
$metable->setMeta('completed_at', \Carbon\CarbonImmutable::now());

Stringable

Strings wrapped in Laravel’s Illuminate\Support\Stringable fluent interface.

<?php
$metable->setMeta('address', Str::of('123 Somewhere St.'));

Enums

<?php
$metable->setMeta('status', Status::ACTIVE);

Objects and Arrays

Objects and arrays will be serialized using PHP’s serialize() function, to allow for the storage and retrieval of complex data structures.

<?php
$metable->setMeta('data', ['key' => 'value']);
$metable->setMeta('data', new MyValueObject(123));

The serialized value is cryptographically signed with an HMAC which is verified before the data is unserialized to prevent PHP object injection attacks. The application’s APP_KEY is used as the HMAC signing key. HMAC verification is generally sufficient for preventing PHP object injection attacks, but it possible to further restrict what can be unserialized by specifying an array or class name in the metable.SignedSerializeHandlerAllowedClasses config in the config/metable.php file.

Note

The Plank\Metable\DataType\SignedSerializeHandler class should generally be the last entry the config/metable.php datatypes array, as it will accept data of any type, causing any handlers below it to be ignored for serializing new meta values. Any handlers defined below it will still be used for unserializing existing meta values. This can be used to temporarily provide backwards compatibility for deprecated data types.

Deprecated

The following data types are deprecated and should not be used in new code. They are still supported for backwards compatibility, but will be removed in a future release.

Array

Warning

The ArrayHandler datatype is deprecated. The SignedSerializeHandler should be used for handling arrays.

Arrays of scalar values. Nested arrays are supported.

<?php
$metable->setMeta('information', [
    'address' => [
        'street' => '123 Somewhere Ave.',
        'city' => 'Somewhereville',
        'country' => 'Somewhereland',
        'postal' => '123456',
    ],
    'contact' => [
        'phone' => '555-555-5555',
        'email' => 'email@example.com'
    ]
]);

Warning

the ArrayHandler class uses json_encode() and json_decode() under the hood for array serialization. This will cause any objects nested within the array to be cast to an array. This is not a concern for the SignedSerializeHandler.

Serializable

Warning

The SerializableHandler datatype is deprecated. The SignedSerializeHandler should be used for handling all objects.

Any object implementing the PHP Serializable interface.

<?php
class Example implements \Serializable
{
    //...
}

$serializable = new Example;

$metable->setMeta('example', $serializable);

For security reasons, it is necessary to list any classes that can be unserialized in the metable.serializableHandlerAllowedClasses key in the config/metable.php file. This is to prevent PHP Object Injection vulnerabilities when unserializing untrusted data. This config can be set to true to allow all classes, but this is not recommended.

Plain Objects

Warning

The ObjectHandler datatype is deprecated. The SignedSerializeHandler should be used for handling all objects.

Any other objects will be converted to stdClass plain objects. You can control what properties are stored by implementing the JsonSerializable interface on the class of your stored object.

<?php
$metable->setMeta('weight', new Weight(10, 'kg'));
$weight = $metable->getMeta('weight') // stdClass($amount = 10; $unit => 'kg');

Warning

ObjectHandler class uses json_encode() and json_decode() under the hood for plain object serialization. This will cause any arrays within the object’s properties to be cast to a stdClass object. This is not a concern for the SignedSerializeHandler.

Adding Custom Data Types

You can add support for other data types by creating a new Handler for your class, which can take care of serialization. Only objects which can be converted to a string and then rebuilt from that string should be handled.

Define a class which implements the Plank\Metable\DataType\Handler interface and register it to the 'datatypes' array in config/metable.php. The order of the handlers in the array is important, as Laravel-Metable will iterate through them and use the first entry that returns true for the canHandleValue() method for a given value. Make sure more concrete classes come before more abstract ones.