PeteBatin's avatar

Eloquent encrypted cast error on empty table

Hi,

I want to store some data in a column that's encrypted in the database.

I found this tutorial on the subject, seemed simple enough https://laraveldaily.com/post/laravel-encrypt-models-data-with-casts

In my model I have...

class Secrets extends Model
{
    use HasFactory;

    protected $casts;

    protected function casts(): array
    {
        return [
            'secret' => 'encrypted',
        ];
    }
}

So far the table is empty, when I query it I get the following error.

array_merge(): Argument #1 must be of type array, null given

Which points to this method in \vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php

protected function initializeHasAttributes()
    {
        $this->casts = $this->ensureCastsAreStringValues(
            array_merge($this->casts, $this->casts()),
        );
    }

Any ideas where I'm going wrong?

0 likes
6 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

You're running into this error because of how you're defining the $casts property in your model.

Problem:

protected $casts;

This line declares the property, but does not initialize it as an array. By default, it's null, which causes array_merge() to fail when Laravel tries to merge it with the result of your casts() method.

Solution: Initialize $casts as an empty array:

protected $casts = [];

Full Example:

class Secrets extends Model
{
    use HasFactory;

    protected $casts = [];

    protected function casts(): array
    {
        return [
            'secret' => 'encrypted',
        ];
    }
}

Summary:
Always initialize the $casts property as an array, even if you plan to define your casts using the casts() method. This will prevent the array_merge() error when your table is empty or when no casts are defined in the property itself.

1 like
Sergiu17's avatar

@PeteBatin, a better way is to remove $casts property from your model

class Secrets extends Model
{
    use HasFactory;

    protected function casts(): array
    {
        return [
            'secret' => 'encrypted',
        ];
    }
}
1 like
PeteBatin's avatar

@Sergiu17 Thanks, I've removed it and it still works. I'll remember this for next time!

1 like
PeteBatin's avatar

@Sergiu17 To muddy the waters even further, I've just had another question answered by Lary AI where the casts where being ignored completely. It recommends

protected $casts = [
        'secret' => 'encrypted',
    ];

And it fixed my issue. I didn't realise one of the sites I was working on is 11 and the other is 10 but both sharing the same casts and models. Method option works in 11 but not 10 (even though Lary AI says the property option is only supported prior 9.21 https://laracasts.com/discuss/channels/eloquent/eloquent-model-ignoring-casts.

1 like
Sergiu17's avatar

@PeteBatin here's the answer from Lary AI when I ask what's the latest Laravel version:

As of my latest knowledge update in June 2024, the latest stable version of Laravel is Laravel 10, which was released in February 2023. Laravel 10 is the current long-term support (LTS) version with new features and improvements. For the most up-to-date version, you can always check the official Laravel website or the Laravel GitHub repository.

So, official documentation is the best bet

1 like

Please or to participate in this conversation.