Skip to content

Instantly share code, notes, and snippets.

@ternavsky
Last active March 8, 2020 20:12
Show Gist options
  • Save ternavsky/1156d32e64eaed55f190 to your computer and use it in GitHub Desktop.
Save ternavsky/1156d32e64eaed55f190 to your computer and use it in GitHub Desktop.
OctoberCMS Model behavior that allows to store some model's attributes in json format in grouping fields in db.
<?php namespace Path\To\Behaviors;
use System\Classes\ModelBehavior;
/**
* Model behavior that allows to store some model's attributes
* in json format in grouping fields in db.
*
* USAGE: In your model add
*
* public $implement = ['Path.To.Behaviors.SerializableModel'];
*
* And define property "serializable":
*
* $serializable = [
* 'my_settings' => [
* 'rows_count',
* 'cols_count',
* 'some_another_attribute'
* ],
* 'another_json_group_field' => [
* 'attribute3',
* 'attribute4'
* ]
* ];
*/
class SerializableModel extends ModelBehavior
{
protected $requiredProperties = ['serializable'];
protected $serializableKeys = []; //fieds that store serializable key=>values
protected $additionalFields = []; //temp help array
public function __construct($model)
{
parent::__construct($model);
//Take already setted jsonable model's fields
$jsonable = $this->model->getJsonable();
// Add serializable fields
foreach ($this->model->serializable as $json_field => $serializable_fields) {
array_push($jsonable, $json_field);
array_push($this->serializableKeys, $json_field);
}
// Remeber all jsonable
//$this->model->jsonable = $jsonable;
$this->model->jsonable($jsonable);
$this->model->bindEvent('model.afterFetch', [$this, 'afterModelFetch']);
$this->model->bindEvent('model.saveInternal', [$this, 'saveModelInternal']);
$this->model->bindEvent('model.beforeSave', [$this, 'beforeModelSave']);
$this->model->bindEvent('model.afterSave', [$this, 'afterModelSave']);
}
/**
* Populate the field values from the database record.
*/
public function afterModelFetch()
{
// After model fetch from db add serializable fields to model's attributes
foreach ($this->serializableKeys as $json_field) {
// Get additional fields from db (auto converted from json)
$this->additionalFields[$json_field] = $this->model->$json_field ?: [];
// Add additional fields to model's regular attributes
if (is_array($this->additionalFields[$json_field])) {
$this->model->attributes = array_merge($this->additionalFields[$json_field], $this->model->attributes);
}
}
}
/**
* Internal save method for the model
* @return void
*/
public function saveModelInternal()
{
foreach ($this->serializableKeys as $json_field) {
$serializableKeys = array_flip($this->model->serializable[$json_field]);
// Purge the field values from the attributes
$attributes = array_diff_key($this->model->attributes, $serializableKeys);
$this->additionalFields[$json_field] = array_intersect_key($this->model->attributes, $serializableKeys);
$this->model->attributes = $attributes;
}
}
/**
* Before the model is saved, ensure the record code is set
* and the jsonable field values
*/
public function beforeModelSave()
{
// Before save: store additional field to model's jsonable field
foreach ($this->serializableKeys as $json_field) {
if ($this->additionalFields[$json_field]) {
$this->model->$json_field = $this->additionalFields[$json_field];
}
}
}
public function afterModelSave()
{
$this->afterModelFetch();
}
}
@chrisvidal
Copy link

awesome code ! thanks !
line 3ç need to be changed to $jsonable = $this->model->getJsonable();

it does not seems to work entirely with a pivot model.
the data are well saved but there are not fetched back up, the event afterFetch is never trigered in the pivot model. Any idea why ?

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