phplaraveleloquentlaravel-10laravel-collection

How to update Laravel Eloquent column cast as collection


I am using Laravel 10.

I am utilizing casting for a JSON column in the following manner:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
  protected $casts = [
    'meta' => 'collection', // here
  ];
}

When attempting to update a value within a collection directly, for instance:

$model->meta->put('test', 100);
$model->save();

Nothing occurs.

When I assign the variable as it is, it functions correctly.

$model->meta = ['test' => 100];
$model->save();

However what if I only need to update/add a single element?

I have discovered the following workaround, but is this the intended behavior?

$meta = $model->meta;
$meta->put('test', 100);
$model->meta = $meta;
$model->save();

It appears that only direct assignment works in such a case, and it seems that the cast collection does not support any of its write functionality.


Solution

  • Solution (Laravel 8.28 or higher)

    Need use Illuminate\Database\Eloquent\Casts\AsCollection instead of 'collection'.

    In the $casts array, you can define the types of individual keys. By specifying the classes of the types (where necessary), Laravel automatically handles the conversion. This is why the specific use of AsCollection::class is required.

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Casts\AsCollection;
    
    class Item extends Model
    {
      protected $casts = [
        'meta' => AsCollection::class, // automatically convert value of 'meta' to Collection::class
      ];
    }
    
    More information



    Solution (Laravel 7.x or lower)

    AsCollection is available by default in Laravel 8.x or higher versions. If you need the collection feature in an older version, you will need to create a custom cast yourself.

    Or alternately can use 'array' cast:

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Item extends Model
    {
      protected $casts = [
        'meta' => 'array', // automatically convert value of 'meta' to array
      ];
    }
    
    More information