Auto decode/encode attribute value in json, provide array access and json validator.
WARNING! From version 2.0.14 Yii has built-in DB JSON-type, and this behavior is no longer required.
Install via Composer:
composer require paulzi/yii2-json-behavior
or add
"paulzi/yii2-json-behavior" : "~1.0.0"
to the require
section of your composer.json
file.
Configure your model:
use paulzi\jsonBehavior\JsonBehavior;
class Item extends \yii\db\ActiveRecord
{
public function behaviors() {
return [
[
'class' => JsonBehavior::className(),
'attributes' => ['params'],
],
];
}
}
Now you can access to attribute as array:
$item = Item::findOne(1);
$item->params['one'] = 'two';
$item->params['two'] = [];
$item->params['two']['key'] = true;
$item->save();
$item = Item::findOne(1);
echo $item['two']['key']; // true
Set attribute via json string:
$item = new Item();
$item->params->set('[2, 4, 42]');
echo $item->params[2]; // 42
Set attribute via array:
$item = new Item();
$item->params->set(['test' => ['one' => 1]]);
echo $item->params['test']['one']; // 1
Convert to json string:
$item = new Item();
$item->params['test'] = ['one' => false, 'two' => [1, 2, 3]];
var_dump((string)$item->params); // {"one":false,"two":[1,2,3]}
Convert to array:
$item = new Item();
$item->params->set('{ "one": 1, "two": null, "three": false, "four": "four" }');
var_dump($item->params->toArray());
Check empty:
$item = new Item();
$item->params->set('{}');
var_dump($item->params->isEmpty()); // true
You can set emptyValue
option to define an empty JSON value (default null
). Can be '{}'
, '[]''
or null
.
Configure your model (see behavior config upper):
use paulzi\jsonBehavior\JsonValidator;
class Item extends \yii\db\ActiveRecord
{
public function rules() {
return [
[['params'], JsonValidator::className()],
];
}
}
Validate:
$item = new Item();
$item->attributes = ['params' => '{ test: }'];
var_dump($item->save()); // false
var_dump($item->errors); // ['params' => ['Value is not valid JSON or scalar']]
You can set merge = true
, in this case, instead of replacing all field data of the transmitted data, array_merge()
will be applied with old data in the field (which are taken from oldAttributes
of ActiveRecord). This option can be apply only with ActiveRecord:
use paulzi\jsonBehavior\JsonValidator;
class Item extends \yii\db\ActiveRecord
{
public function rules() {
return [
[['params'], JsonValidator::className(), 'merge' => true],
];
}
}
You can use JsonField
class for other models:
class Item
{
public $params;
public function __constructor()
{
$this->params = new JsonField();
}
}
// ...
$item = new Item();
$item->params['one'] = 1;
var_dump((string)$item->params); // {"one":1}
Yii2 does not provide the ability to inject code to check attribute dirty.
If you need to use methods isAttributeChanged()
or getDirtyAttributes()
, you can override them in model:
/**
* @inheritdoc
*/
public function isAttributeChanged($name, $identical = true)
{
if ($this->$name instanceof JsonField) {
return (string)$this->$name !== $this->getOldAttribute($name);
} else {
return parent::isAttributeChanged($name, $identical);
}
}
/**
* @inheritdoc
*/
public function getDirtyAttributes($names = null)
{
$result = [];
$data = parent::getDirtyAttributes($names);
foreach ($data as $name => $value) {
if ($value instanceof JsonField) {
if ((string)$value !== $this->getOldAttribute($name)) {
$result[$name] = $value;
}
} else {
$result[$name] = $value;
}
}
return $result;
}