Last active
March 8, 2020 20:12
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 ?