LIERLIER
1 year ago
commit
9aad868b46
1 changed files with 241 additions and 0 deletions
-
241readme.md
@ -0,0 +1,241 @@ |
|||||
|
# 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 GoodQuery extends ActiveQuery |
||||
|
{ |
||||
|
/** |
||||
|
* [ |
||||
|
* 融合属性 => [ |
||||
|
* 状态位 => 状态名 |
||||
|
* ] |
||||
|
* ... |
||||
|
* ] |
||||
|
* @var array[] $statusAttributes 融合状态表 |
||||
|
*/ |
||||
|
public $statusAttributes; |
||||
|
|
||||
|
/** |
||||
|
* @param string[] $queryParams |
||||
|
* @return GoodQuery |
||||
|
*/ |
||||
|
public function andWhereStatus($queryParams = []) |
||||
|
{ |
||||
|
return $this->andWhere($this->getStatusCondition($queryParams)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param string[] $queryParams |
||||
|
* @return GoodQuery |
||||
|
*/ |
||||
|
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(); |
||||
|
``` |
Write
Preview
Loading…
Cancel
Save
Reference in new issue