spatie/laravel-schemaless-attributes

repository·main·Indexed 22 days ago

https://github.com/spatie/laravel-schemaless-attributes

A Laravel package that allows storing arbitrary, schemaless data in a single JSON column of an Eloquent model. It provides a NoSQL-like experience within a relational database, featuring a custom Eloquent cast, a Blueprint migration macro, and a modelScope for querying JSON keys using dot notation and custom operators.

Tokens
2K
Snippets
9
Records
11
Agent score
76%

What's inside laravel-schemaless-attributes

  1. Prepare an Eloquent model for schemaless attributes

    main

    To enable schemaless attributes on a model, you must add a custom cast to the $casts array using Spatie\SchemalessAttributes\Casts\SchemalessAttributes.

    Single Column Setup

    If you only have one schemaless column, add the cast directly to the model.

    Multiple Column Setup

    If you need to support multiple schemaless columns, use the SchemalessAttributesTrait and define the columns in a protected $schemalessAttributes array.

    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Builder;
    use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
    use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
    
    class TestModel extends Model
    {
        // For a single column:
        public $casts = [
            'extra_attributes' => SchemalessAttributes::class,
        ];
    
        // OR for multiple columns:
        use SchemalessAttributesTrait;
    
        protected $schemalessAttributes = [
            'extra_attributes',
            'other_extra_attributes',
        ];
    
        // Recommended: Add a scope to use the modelScope functionality
        public function scopeWithExtraAttributes(Builder $query):
        {
            return $this->extra_attributes->modelScope();
        }
    }
  2. Add a schemaless attributes column via migration

    main

    To store schemaless attributes, add a JSON column to your table using the schemalessAttributes method on the Blueprint object. You can name the column anything (e.g., extra_attributes).

    Schema::table('your_models', function (Blueprint $table) {
        $table->schemalessAttributes('extra_attributes');
    });
  3. Retrieve models using schemaless attribute scopes

    main

    Use the modelScope() provided by the attribute object to build queries. This is typically exposed via a custom model scope.

    Querying by multiple attributes

    Returns models that match all provided key-value pairs:

    $model->withExtraAttributes(['name' => 'value', 'name2' => 'value2'])->get();

    Querying a single attribute

    // Exact match
    $model->withExtraAttributes('name', 'value')->get();
    
    // Using a custom operator (e.g., LIKE)
    $model->withExtraAttributes('name', 'LIKE', 'value%')->get();

    Querying nested attributes

    Use dot notation within the scope to query nested JSON keys:

    $model->withExtraAttributes('han->side', 'light')->get();
  4. Get and set schemaless attributes

    main

    You can interact with schemaless attributes using object notation, array notation, or the get() and set() methods. The get() and set() methods support dot notation for nested attributes.

    Object and Array Notation

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

    Replacing all attributes

    Assigning an array to the column replaces all existing attributes:

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

    Using get() and set() with dot notation

    // Set a nested value
    $model->extra_attributes->set('rey.side', 'dark');
    
    // Get a nested value
    $model->extra_attributes->get('rey.side');
    
    // Get with a default value
    $model->extra_attributes->get('non_existing', 'default');
    
    // Delete a key
    $model->extra_attributes->forget('key');
  5. Filter models using modelScope()

    main

    The modelScope() method returns an Eloquent Builder instance configured to filter models based on their schemaless attributes. This allows you to perform queries against JSON keys using standard Eloquent syntax.

    It supports several argument patterns:

    1. modelScope($builder): Returns the builder as is.
    2. modelScope($builder, $attributes): Filters by an array of attributes.
    3. modelScope($builder, $name, $value): Filters by a specific key and value (defaults to = operator).
    4. modelScope($builder, $name, $operator, $value): Filters by a specific key, operator, and value.
    // Example: Filtering a query by a schemaless attribute
    $query = User::query();
    $schemaless = SchemalessAttributes::createForModel($user, 'settings');
    
    // Using the scope to add where clauses
    $users = $schemaless->modelScope($query, 'theme', '=', 'dark')
        ->get();
  6. Enable schemaless attributes on an Eloquent model

    main

    To use schemaless attributes on a model, you must cast a specific database column to the Spatie\SchemalessAttributes\Casts\SchemalessAttributes class. This class acts as an Eloquent cast that returns a Spatie\SchemalessAttributes\SchemalessAttributes object, allowing you to interact with the JSON column as a collection of dynamic attributes.

    use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
    
    class YourModel extends Model
    {
        protected $casts = [
            'custom_attributes' => SchemalessAttributes::class,
        ];
    }
  7. Convert SchemalessAttributes to array or JSON

    main

    The SchemalessAttributes object implements Arrayable, Jsonable, and JsonSerializable, allowing it to be easily converted for API responses or debugging.

    • toArray(): Returns the underlying attributes as an associative array.
    • toJson(): Returns the JSON string representation.
    $array = $schemalessAttributes->toArray();
    $json = $schemalessAttributes->toJson();
  8. Add a schemaless attributes column to migrations

    main

    The package provides a Blueprint macro to simplify adding the required JSON column for schemaless attributes in your Laravel migrations. You can use the schemalessAttributes method on a Blueprint instance. By default, it creates a nullable JSON column named schemaless_attributes.

    $table->schemalessAttributes(); // Creates a nullable JSON column named 'schemaless_attributes'
    
    // Or specify a custom column name:
    $table->schemalessAttributes('custom_attributes_column');