Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dany68's avatar
Level 15

Best way to flatten a json column on the model

Hi everyone,

I'm trying to find the most "clean" recommended way to flatten a json column for accessors and mutators. I'm not very satisfied with the solutions i've found/write so far. I have a model that contains a json column "details". I want that when I retrieve the record all the json keys of the field "details" keys are accessible as $model->key. Also when I save the model I would like to set $model->key = $newVal and actually store it in the details field as json in the db.

The details column can contains lot of keys, so making an Attribute (get, set) for each is really redundant. What would be the best approach ?

Thank you for your help :)

0 likes
9 replies
LaryAI's avatar
Level 58

One possible solution to flatten a JSON column on a model is to use accessors and mutators. Here's an example implementation:

class YourModel extends Model
{
    protected $casts = [
        'details' => 'array',
    ];

    public function getAttribute($key)
    {
        if (array_key_exists($key, $this->details)) {
            return $this->details[$key];
        }

        return parent::getAttribute($key);
    }

    public function setAttribute($key, $value)
    {
        if (array_key_exists($key, $this->details)) {
            $this->details[$key] = $value;
        } else {
            parent::setAttribute($key, $value);
        }
    }

    public function save(array $options = [])
    {
        $this->attributes['details'] = $this->details;

        return parent::save($options);
    }
}

In this solution, we define the details column as an array in the $casts property of the model. This ensures that Laravel will automatically serialize and deserialize the column as JSON.

We override the getAttribute and setAttribute methods to handle accessing and setting the flattened keys. If the key exists in the details array, we return or set the value accordingly. Otherwise, we fall back to the parent implementation.

In the save method, we update the details attribute with the modified array before saving the model.

With this implementation, you can access and set the flattened keys directly on the model instance, like $model->key. The changes will be reflected in the details column when saving the model.

dany68's avatar
Level 15

Thank you for your recommendation. I do still want to stick with a json column though. I never need to query on those keys, just to display the content. I might add lot of keys in the future or change a bit the architecture. Lot of them might be null. I don’t want to run migration each time. It’s somewhere clause to a settings/preferences field on a user model.

dany68's avatar
Level 15

@Tray2 Thank you it's a good article. I have few reasons specific to the app that make me want to stick with json. The question is really related on the way to define accessors and mutators for a json field. For instance doing something like this doesn't work for the setter. I tried several variants, with json_encode/decode and other alternatives but nothing seems to work.

protected $casts = [
        'details' => 'array',
];

protected $appends = [
		'description'
];

protected function description(): Attribute {
        return new Attribute(
            get: fn() => $this->details['description'] ?? null,
            set: function($v) {
            	$this->attributes['details'] = array_merge(
               			$this->attributes['details'] ?? [],
                	   ['description' => $v]
                );
            }
        );
  }

Ideally i would also like to do it in a magic getter/setter in order to avoid to repeat the same function for each field. Inside the magic getter/setter I would define a variable $fields = ["description", "link_url"....] that represent all the fields that it need to catch and set in the "details" attribute. When I retrieve the model those fields need to be flatten at the root of the model.

In any case thank you for your help and time :)

dany68's avatar
Level 15

@jlrdw Thank you for the link. The problem is more regarding the setters, not so about how to flatten a field. There is more details in my reply above. I would like to be able to do the following and still set correctly the json attributes in the details column.

$model->fill($request->validated())
$model->save()

In order to avoid something like:

$model->name = $request->input('name');
$model->details['description'] = $request->input('description');
// List of other fields...
$model->save();
krisi_gjika's avatar

what happens when a json key shadows another field, relation or attribute on your model? Say you have a user relation but the json also has a user key, what would $model->user give?

1 like
dany68's avatar
Level 15

@krisi_gjika I have a variable that is a safe list of json keys. So only the ones allowed can be stored in the model.

Please or to participate in this conversation.