|
|
# status-combination 融合状态
### Configuration
##### 添加文件: `StatusBehavior.php`
```php <?php namespace {yourApp}\behaviors;
use yii\base\Behavior; use yii\db\ActiveRecord; use yii\db\Expression;
class StatusBehavior extends Behavior { /** * [ * 融合属性 => [ * 状态位 => 状态名 * ] * ... * ] * @var array[] $statusAttributes 融合状态表 */ public $statusAttributes = [];
public function events() { return [ ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave', ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate', ActiveRecord::EVENT_AFTER_FIND => 'afterFind', ]; }
public function beforeSave() { foreach ($this->statusAttributes as $field => $attributes) { $this->owner->$field = 0; $this->setStatusCombination($field, $attributes); } }
public function beforeUpdate() { foreach ($this->statusAttributes as $field => $attributes) { $this->setStatusCombination($field, $attributes); } }
public function afterFind() { $owner = $this->owner; foreach ($this->statusAttributes as $field => $attributes) { $status = $owner->$field; foreach ($attributes as $pos => $attribute) { $owner->$attribute = ($status & 1 << $pos) >> $pos; } } }
/** * 设置融合字段 * @param string $field 融合字段名 * @param string[] $attributes 字段 */ public function setStatusCombination($field, $attributes) { $owner = $this->owner; foreach ($attributes as $pos => $attribute) { $status = $owner->$attribute; if ($status === null) { continue; } $owner->$field = $this->getUpdateStatusCombination($owner->$field, $pos, $status); } }
/** * 获得更新后的融合状态 * @param int $statusCombination 融合状态 * @param int $pos 状态位置 * @param bool|int $status 状态 * @return int */ public function getUpdateStatusCombination($statusCombination, $pos, $status) { if ($status) { $statusCombination = $statusCombination | 1 << $pos; } else { $statusCombination = $statusCombination & ~(1 << $pos); } return $statusCombination; } } ```
##### 在需要的`Model`里添加`Behavior`
```php <?php
namespace {yourApp}\models;
use {yourApp}\behaviors\StatusBehavior; class MyModel extends base\MyModel { /** * @var int 状态 */ public $s0; public $s1; public $s2; public $s3; public $s5; public $s6; public $s7; public $s8;
/** * 融合状态表: * [ * 融合属性 => [ * 状态位 => 状态名 * ] * ... * ] */ const STATUS_ATTRIBUTES = [ 'status' => [ 's0', 's1', 's2', 's3', ], // 'flags' => [ // 's5', 's6', 's7', 's8' // ] ];
// 其他Model代码......
public function behaviors() { return [ // 其他Behavior
'statusBehavior' => [ 'class' => StatusBehavior::class, 'statusAttributes' => self::STATUS_ATTRIBUTES, ], ]; }
/** * {@inheritdoc} * 重写find()返回自定义查询类 */ public static function find() { $config = ['statusAttributes' => self::STATUS_ATTRIBUTES]; return new MyModelQuery(get_called_class(), $config); } } ```
##### 添加文件 `MyModelQuery`
```php <?php namespace {yourApp}\models;
use yii\db\ActiveQuery; use yii\db\Expression;
class MyModelQuery extends ActiveQuery { /** * [ * 融合属性 => [ * 状态位 => 状态名 * ] * ... * ] * @var array[] $statusAttributes 融合状态表 */ public $statusAttributes;
/** * @param string[] $queryParams * @return MyModelQuery */ public function andWhereStatus($queryParams = []) { return $this->andWhere($this->getStatusCondition($queryParams)); }
/** * @param string[] $queryParams * @return MyModelQuery */ public function orWhereStatus($queryParams = []) { return $this->orWhere($this->getStatusCondition($queryParams)); }
/** * @param array $queryParams * @return Expression */ public function getStatusCondition($queryParams = []) { $queryAttributes = array_keys($queryParams); foreach ($this->statusAttributes as $field => $attributes) { $mask = $res = 0; foreach ($attributes as $pos => $attribute) { if (in_array($attribute, $queryAttributes)) { $mask += 1 << $pos; $res += $queryParams[$attribute] << $pos; } } if ($mask != 0) { $conditions[] = "$field & $mask = $res"; } } return new Expression(implode('and', $conditions)); } } ```
### Usage
##### Search
```php $myModels = MyModel::find() ->andWhereStatus(['s0' => 1, 's1' => 0]) ->orWhereStatus(['s2' => 0, 's3' => 1]) ->all(); ```
|