Blog Detail

13

Dec
Add schemaless attributes to Eloquent models in Laravel cover image

arrow_back Add schemaless attributes to Eloquent models in Laravel

Laravel Schemaless Attributes is the package by Saptie that adds schemaless attributes to Eloquent models in Laravel. Wouldn’t it be cool if you could have a bit of the spirit of NoSQL available in Eloquent? This package does just that. It provides a trait that when applied to a model, allows you to store arbitrary values in a single JSON column. This package requires a database with support for json columns like MySQL 5.7 or higher.

Here are a few examples. We’re using the extra_attributes column here, but you can name it whatever you want.

Installation

For Laravel versions 6 & 7 or PHP 7, use version 1.x of this package.

You can install the package via composer by running this command:

composer require spatie/laravel-schemaless-attributes

The schemaless attributes will be stored in a json column on the table of your model. Let’s add that column and prepare the model.

Adding the column where the schemaless attributes will be stored

Add a migration for all models where you want to add schemaless attributes to. You should use schemalessAttributes method on Blueprint to add a column. The argument you give to schemalessAttributes is the column name that will be added. You can use any name you’d like. You’re also free to add as many schemaless attribute columns to your table as you want. In all examples of this readme, we’ll use a single column named extra_attributes.

Schema::table('your_models', function (Blueprint $table) {
    $table->schemalessAttributes('extra_attributes');
});

Preparing the model

In order to work with the schemaless attributes, you’ll need to add a custom cast and a scope to your model. Here is an example of what you need to add if you’ve chosen extra_attributes as your column name.

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;

class TestModel extends Model
{
    // ...

    public $casts = [
        'extra_attributes' => SchemalessAttributes::class,
    ];

    public function scopeWithExtraAttributes(): Builder
    {
        return $this->extra_attributes->modelScope();
    }

    // ...
}

Usage

Getting and setting schemaless attributes

This is the easiest way to get and set schemaless attributes:

$yourModel->extra_attributes->name = 'value';

$yourModel->extra_attributes->name; // Returns 'value'

Alternatively you can use an array approach:

$yourModel->extra_attributes['name'] = 'value';

$yourModel->extra_attributes['name']; // Returns 'value'

You can replace all existing schemaless attributes by assigning an array to it.

// All existing schemaless attributes will be replaced
$yourModel->extra_attributes = ['name' => 'value'];
$yourModel->extra_attributes->all(); // Returns ['name' => 'value']

You can also opt to use get and set. The methods have support for dot notation.

$yourModel->extra_attributes = [
   'rey' => ['side' => 'light'],
   'snoke' => ['side' => 'dark'],
];
$yourModel->extra_attributes->set('rey.side', 'dark');

$yourModel->extra_attributes->get('rey.side'); // Returns 'dark

You can also pass a default value to the get method.

$yourModel->extra_attributes->get('non_existing', 'default'); // Returns 'default'

Persisting schemaless attributes

To persist schemaless attributes you should, just like you do for normal attributes, call save() on the model.

$yourModel->save(); // Persists both normal and schemaless attributes

Retrieving models with specific schemaless attributes

Here’s how you can use the provided modelScope.

// Returns all models that have all the given schemaless attributes
$yourModel->withExtraAttributes(['name' => 'value', 'name2' => 'value2'])->get();

If you only want to search on a single custom attribute, you can use the modelScope like this

// returns all models that have a schemaless attribute `name` set to `value`
$yourModel->withExtraAttributes('name', 'value')->get();

Also, if you only want to search on a single custom attribute with a custom operator, you can use the modelScope like this

// returns all models that have a schemaless attribute `name` starting with `value`
$yourModel->withExtraAttributes('name', 'LIKE', 'value%')->get();

If you only want to search on a nested custom attribute, you can use the modelScope like this

// returns all models that have a schemaless nested attribute `han.side` set to `light`
$yourModel->withExtraAttributes('han->side', 'light')->get();

For more details, You can visit its documentation & source code on Github.

Published at : 13-12-2021

Author : Rizwan Aslam
AUTHOR
Rizwan Aslam

I am a highly results-driven professional with 12+ years of collective experience in the grounds of web application development especially in laravel, native android application development in java, and desktop application development in the dot net framework. Now managing a team of expert developers at Codebrisk.

Launch your project

Launch project