Skip to content

Commit

Permalink
添加jsonModel相关的处理方法
Browse files Browse the repository at this point in the history
  • Loading branch information
buptlsp committed Jan 21, 2025
1 parent 7425597 commit 50172f0
Show file tree
Hide file tree
Showing 9 changed files with 584 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/behaviors/DictBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace ethercap\common\behaviors;

use ethercap\common\helpers\ArrayHelper;
use ethercap\common\helpers\RuleHelper;

/**
* 主要是与DictValidator配合使用
* 提供getter方法,可以通过 $model->{attribute}_desc获取值的描述
* 提供setter方法,可以通过 $model->{attribute}_desc = $value
*
* 用法:
* 在model的behaviors中加入如下行:
* [
* 'class' => DictBehavior,
* 'attributes' => ['status', 'type'],
* ],
*
* //同时,请确保你在rules中加入了DictValidator, 如下为示例:
* [
* ['status', DictValidator::class, 'list'=> self::$statusArr],
* // ...
* ]
*
* // 然后你就可以很方便的访问值了.
* echo $model->status_desc;
*/
class DictBehavior extends PropertyBehavior
{
public $ending = '_desc';
public $validatorClass = \ethercap\common\validators\DictValidator::class;

protected function getValueByName($name)
{
is_null($this->defaultValue) && $this->defaultValue = $this->owner->$name;
$validator = RuleHelper::getAttributeValidator($this->owner, $name, $this->validatorClass);
if ($validator) {
return $this->getValueByValidator($validator, $name);
}
return $this->defaultValue;
}

protected function getValueByValidator($validator, $name)
{
$value = $this->owner->$name;
is_null($this->defaultValue) && $this->defaultValue = $value;
if ($validator) {
if (is_array($value)) {
$ret = [];
foreach ($value as $val) {
$ret[] = ArrayHelper::getValue($validator->list, $val, $this->defaultValue);
}
return $ret;
} else {
return ArrayHelper::getValue($validator->list, $value, $this->defaultValue);
}
} else {
throw new \Exception("{$name} 不存在 {$this->validatorClass}");
}
return $value;
}

public function setValueByName($name, $value)
{
$validator = RuleHelper::getAttributeValidator($this->owner, $name, $this->validatorClass);
if ($validator) {
$list = $validator->list;
foreach ($validator->list as $key => $val) {
if ($val === $value) {
$this->owner->$name = $key;
return;
}
}
} else {
throw new \Exception("{$name} 不存在 {$this->validatorClass}");
}
}
}
60 changes: 60 additions & 0 deletions src/behaviors/JsonModelBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace ethercap\common\behaviors;

use Closure;

/**
* 提供jsonModel的便利使用
* [
* 'class' => JsonModelBehavior::class,
* 'attributes' => ['attr'],
* 'modelClass' => xxModel::class, // 也可以传入匿名函数 function($val) {return xxModelClass; }
* ]
*
* //访问attr的model
* $model->attr_jmodel
* $model->attr_jmodel = new xxxModel();
* $model->attr_jmodel->attribute = "hello world";
* // save时会将model的数据自动存入数据库中
* $model->save()
*/
class JsonModelBehavior extends SerializeBehavior
{
public $ending = '_jmodel';
public $defaultValue = '{}';
public $modelClass = null;

//通过数组获取Model
public function getModelByValue($arr)
{
$modelClass = $this->modelClass;
if ($modelClass instanceof Closure || (is_array($modelClass) && is_callable($modelClass))) {
$modelClass = call_user_func($modelClass, $arr);
}
empty($modelClass) && $modelClass = \yii\base\DynamicModel::class;
$model = new $modelClass();
if (!($model instanceof \yii\base\Model)) {
throw new \Exception("modelClass 必须是\yii\base\Model类");
}
if ($model instanceof \yii\base\DynamicModel) {
foreach ($arr as $key => $val) {
$model->defineAttribute($key, $val);
}
} else {
$model->load($arr, '');
}
return $model;
}

protected function serializeValue($value)
{
return parent::serializeValue($value->toArray());
}

protected function unSerializeValue($value)
{
$arr = parent::unSerializeValue($value);
return $this->getModelByValue($arr);
}
}
68 changes: 68 additions & 0 deletions src/behaviors/JsonModelsBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace ethercap\common\behaviors;

use Closure;

/**
* 提供jsonModel的便利使用
* [
* 'class' => JsonModelBehavior::class,
* 'attributes' => ['attr'],
* 'modelClass' => xxModel::class, // 也可以传入匿名函数 function($val) {return xxModelClass; }
* ]
*
* //访问attr的model
* $model->attr_jmodels
* $model->attr_jmodels =[ new xxxModel()];
* $model->attr_jmodels[0]->attribute = "hello world";
* // save时会将model的数据自动存入数据库中
* $model->save()
*/
class JsonModelsBehavior extends SerializeBehavior
{
public $ending = '_jmodels';
public $defaultValue = '[]';
public $modelClass = null;

//通过数组获取Model
public function getModelByValue($arr)
{
$modelClass = $this->modelClass;
if ($modelClass instanceof Closure || (is_array($modelClass) && is_callable($modelClass))) {
$modelClass = call_user_func($modelClass, $arr);
}
empty($modelClass) && $modelClass = \yii\base\DynamicModel::class;
$model = new $modelClass();
if (!($model instanceof \yii\base\Model)) {
throw new \Exception("modelClass 必须是\yii\base\Model类");
}
if ($model instanceof \yii\base\DynamicModel) {
foreach ($arr as $key => $val) {
$model->defineAttribute($key, $val);
}
} else {
$model->load($arr, '');
}
return $model;
}

protected function serializeValue($value)
{
$list = [];
foreach ($value as $key => $val) {
$list[$key] = $val->toArray();
}
return parent::serializeValue($list);
}

protected function unSerializeValue($value)
{
$arr = parent::unSerializeValue($value);
$models = [];
foreach ($arr as $key => $val) {
$models[$key] = $this->getModelByValue($val);
}
return $models;
}
}
72 changes: 72 additions & 0 deletions src/behaviors/PropertyBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace ethercap\common\behaviors;

use yii\helpers\StringHelper;

/**
* 提供getter/setter方法,可以通过 $model->attribute{ending}获取/改变值
*/
abstract class PropertyBehavior extends \yii\base\Behavior
{
public $ending = '_desc';
public $defaultValue = null;
public $attributes = [];

public $canSet = true;
public $canGet = true;

public function init()
{
parent::init();
}

public function __get($name)
{
if ($name = $this->getAttributeByStr($name)) {
return $this->getValueByName($name);
}
return parent::__get($name);
}

public function __set($name, $value)
{
if ($name = $this->getAttributeByStr($name)) {
return $this->setValueByName($name, $value);
}
return parent::__set($name, $value);
}

abstract protected function getValueByName($name);

abstract protected function setValueByName($name, $value);

protected function getAttributeByStr($name, $ending = null)
{
empty($ending) && $ending = $this->ending;
if (StringHelper::endsWith($name, $ending)) {
$name = substr($name, 0, -1 * strlen($ending));
if (in_array($name, $this->attributes)) {
return $name;
}
}
return null;
}

public function canGetProperty($name, $checkVars = true)
{
$name = $this->getAttributeByStr($name);
if ($name) {
return $this->canGet;
}
return parent::canGetProperty($name, $checkVars);
}

public function canSetProperty($name, $checkVars = true)
{
if ($name = $this->getAttributeByStr($name)) {
return $this->canSet;
}
return parent::canSetProperty($name, $checkVars);
}
}
107 changes: 107 additions & 0 deletions src/behaviors/SerializeBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

namespace ethercap\common\behaviors;

use Closure;
use yii\db\ActiveRecord;

/**
* 支持将model上的某个值以其它格式保存和使用
* // 如下为一个示例,假设 $price存的为分, 我们可以通过如下配置, 然后$model->price_money 获取对应的元
* [
* 'class' => SerializeBehavior::class,
* 'ending' => '_money';
* 'attributes' => ['price'],
* 'unSerializeFunc' => function($val) {
* return number_format($val / 100, 2);
* },
* 'serializeFunc' => function($val) {
* return intval($val * 100);
* }
* ]
*/
class SerializeBehavior extends PropertyBehavior
{
public $ending = '_unser';
public $defaultValue = null;

// 如何将数据从原来的格式转为你希望为的格式
public $unSerializeFunc = [self::class, 'jsonDecode'];
// 如何将数据从你希望为的格式转为原来的格式
public $serializeFunc = [self::class, 'jsonEncode'];

private $_buffer = [];

public function init()
{
parent::init();

if (!($this->unSerializeFunc instanceof Closure || (is_array($this->unSerializeFunc) && is_callable($this->unSerializeFunc)))) {
throw new \Exception('unSerializeFunc 必须是一个可以被调用的函数');
}
if (!($this->serializeFunc instanceof Closure || (is_array($this->serializeFunc) && is_callable($this->serializeFunc)))) {
throw new \Exception('serializeFunc 必须是一个可以被调用的函数');
}
}

public static function returnOrigin($val)
{
return $val;
}

public function events()
{
return [
ActiveRecord::EVENT_BEFORE_INSERT => 'syncToOrigin',
ActiveRecord::EVENT_BEFORE_UPDATE => 'syncToOrigin',
];
}

public static function jsonDecode($value)
{
$arr = @json_decode($value, true);
empty($arr) && $arr = [];
return $arr;
}

public static function jsonEncode($value)
{
return json_encode($value);
}

protected function unSerializeValue($value)
{
return call_user_func($this->unSerializeFunc, $value);
}

protected function serializeValue($value)
{
return call_user_func($this->serializeFunc, $value);
}

public function getValueByName($name)
{
if (isset($this->_buffer[$name])) {
return $this->_buffer[$name];
}

$value = $this->owner->$name;
$result = $this->unSerializeValue($value);
$this->_buffer[$name] = $result;
return $result;
}

public function setValueByName($name, $value)
{
$this->_buffer[$name] = $value;
}

// 在更改数据之前,将数据置回
public function syncToOrigin()
{
foreach ($this->_buffer as $key => $value) {
$this->owner->$key = $this->serializeValue($value);
}
$this->_buffer = [];
}
}
Loading

0 comments on commit 50172f0

Please sign in to comment.