Skip to content

Instantly share code, notes, and snippets.

@dsamojlenko
Last active August 5, 2016 23:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsamojlenko/98963b20d644fea955d118366227e960 to your computer and use it in GitHub Desktop.
Save dsamojlenko/98963b20d644fea955d118366227e960 to your computer and use it in GitHub Desktop.
<?php
namespace App\Traits;
trait HasJsonFields
{
public function newFromBuilder($attributes = [], $connection = null)
{
$model = parent::newFromBuilder($attributes, $connection);
$model->addHintedAttributes();
return $model;
}
public function addHintedAttributes()
{
foreach($this->hintedAttributes as $col => $structure) {
$attrs = json_decode($this->attributes[$col]);
$obj = (object)$structure;
if(is_object($obj)) {
foreach($obj as $key => $value) {
if(!isset($attrs->$key)) {
$attrs->$key = $value;
}
}
$this->attributes[$col] = json_encode($attrs);
}
}
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasJsonFields;
class MyModel extends Model
{
use HasJsonFields;
public $jsonColumns = [
'user_details',
'details'
];
public $hintedAttributes = [
'user_details' => [
'first_name' => '',
'last_name' => '',
'email' => '',
'phone' => ''
],
'details' => [
'question' => '',
'answer' => ''
]
];
}
@patrickguevara
Copy link

patrickguevara commented Aug 5, 2016

I usually do

$casts = [
    'options' => 'array,
];

The $casts makes sure that when Eloquent pulls it from the DB it does json_decode() and then json_encode when it saves it.
And then have a function to set/unset options

public function setOption($key, $value)
{
    $options = $this->options;
    $options[$key] = $value;
    $this->options = $options;
    $this->save();
    return $this;
}

public function unsetOption($key)
{
    $options = $this->options;
    unset($options[$key]);
    $this->options = $options;
    $this->save();
    return $this;
}

Then if there's a special option I want, like the order of items, I'll add an accessor and append it to the model.

/**
 * Fetches the order, returns 1 if not set.
 */
public function getOrderAttribute() 
{
    return $this->options['order'] ?? 1;
}

$appends = [
    'order',
];

This is so I can grab the order by just doing $model->order instead of $model->options['order']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment