You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
5.4 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. # status-combination 融合状态
  2. ### Configuration
  3. ##### 添加文件: `StatusBehavior.php`
  4. ```php
  5. <?php
  6. namespace {yourApp}\behaviors;
  7. use yii\base\Behavior;
  8. use yii\db\ActiveRecord;
  9. use yii\db\Expression;
  10. class StatusBehavior extends Behavior
  11. {
  12. /**
  13. * [
  14. * 融合属性 => [
  15. * 状态位 => 状态名
  16. * ]
  17. * ...
  18. * ]
  19. * @var array[] $statusAttributes 融合状态表
  20. */
  21. public $statusAttributes = [];
  22. public function events()
  23. {
  24. return [
  25. ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave',
  26. ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate',
  27. ActiveRecord::EVENT_AFTER_FIND => 'afterFind',
  28. ];
  29. }
  30. public function beforeSave()
  31. {
  32. foreach ($this->statusAttributes as $field => $attributes) {
  33. $this->owner->$field = 0;
  34. $this->setStatusCombination($field, $attributes);
  35. }
  36. }
  37. public function beforeUpdate()
  38. {
  39. foreach ($this->statusAttributes as $field => $attributes) {
  40. $this->setStatusCombination($field, $attributes);
  41. }
  42. }
  43. public function afterFind()
  44. {
  45. $owner = $this->owner;
  46. foreach ($this->statusAttributes as $field => $attributes) {
  47. $status = $owner->$field;
  48. foreach ($attributes as $pos => $attribute) {
  49. $owner->$attribute = ($status & 1 << $pos) >> $pos;
  50. }
  51. }
  52. }
  53. /**
  54. * 设置融合字段
  55. * @param string $field 融合字段名
  56. * @param string[] $attributes 字段
  57. */
  58. public function setStatusCombination($field, $attributes)
  59. {
  60. $owner = $this->owner;
  61. foreach ($attributes as $pos => $attribute) {
  62. $status = $owner->$attribute;
  63. if ($status === null) {
  64. continue;
  65. }
  66. $owner->$field = $this->getUpdateStatusCombination($owner->$field, $pos, $status);
  67. }
  68. }
  69. /**
  70. * 获得更新后的融合状态
  71. * @param int $statusCombination 融合状态
  72. * @param int $pos 状态位置
  73. * @param bool|int $status 状态
  74. * @return int
  75. */
  76. public function getUpdateStatusCombination($statusCombination, $pos, $status)
  77. {
  78. if ($status) {
  79. $statusCombination = $statusCombination | 1 << $pos;
  80. } else {
  81. $statusCombination = $statusCombination & ~(1 << $pos);
  82. }
  83. return $statusCombination;
  84. }
  85. }
  86. ```
  87. ##### 在需要的`Model`里添加`Behavior`
  88. ```php
  89. <?php
  90. namespace {yourApp}\models;
  91. use {yourApp}\behaviors\StatusBehavior;
  92. class MyModel extends base\MyModel
  93. {
  94. /**
  95. * @var int 状态
  96. */
  97. public $s0;
  98. public $s1;
  99. public $s2;
  100. public $s3;
  101. public $s5;
  102. public $s6;
  103. public $s7;
  104. public $s8;
  105. /**
  106. * 融合状态表:
  107. * [
  108. * 融合属性 => [
  109. * 状态位 => 状态名
  110. * ]
  111. * ...
  112. * ]
  113. */
  114. const STATUS_ATTRIBUTES = [
  115. 'status' => [
  116. 's0',
  117. 's1',
  118. 's2',
  119. 's3',
  120. ],
  121. // 'flags' => [
  122. // 's5', 's6', 's7', 's8'
  123. // ]
  124. ];
  125. // 其他Model代码......
  126. public function behaviors()
  127. {
  128. return [
  129. // 其他Behavior
  130. 'statusBehavior' => [
  131. 'class' => StatusBehavior::class,
  132. 'statusAttributes' => self::STATUS_ATTRIBUTES,
  133. ],
  134. ];
  135. }
  136. /**
  137. * {@inheritdoc}
  138. * 重写find()返回自定义查询类
  139. */
  140. public static function find()
  141. {
  142. $config = ['statusAttributes' => self::STATUS_ATTRIBUTES];
  143. return new MyModelQuery(get_called_class(), $config);
  144. }
  145. }
  146. ```
  147. ##### 添加文件 `MyModelQuery`
  148. ```php
  149. <?php
  150. namespace {yourApp}\models;
  151. use yii\db\ActiveQuery;
  152. use yii\db\Expression;
  153. class MyModelQuery extends ActiveQuery
  154. {
  155. /**
  156. * [
  157. * 融合属性 => [
  158. * 状态位 => 状态名
  159. * ]
  160. * ...
  161. * ]
  162. * @var array[] $statusAttributes 融合状态表
  163. */
  164. public $statusAttributes;
  165. /**
  166. * @param string[] $queryParams
  167. * @return MyModelQuery
  168. */
  169. public function andWhereStatus($queryParams = [])
  170. {
  171. return $this->andWhere($this->getStatusCondition($queryParams));
  172. }
  173. /**
  174. * @param string[] $queryParams
  175. * @return MyModelQuery
  176. */
  177. public function orWhereStatus($queryParams = [])
  178. {
  179. return $this->orWhere($this->getStatusCondition($queryParams));
  180. }
  181. /**
  182. * @param array $queryParams
  183. * @return Expression
  184. */
  185. public function getStatusCondition($queryParams = [])
  186. {
  187. $queryAttributes = array_keys($queryParams);
  188. foreach ($this->statusAttributes as $field => $attributes) {
  189. $mask = $res = 0;
  190. foreach ($attributes as $pos => $attribute) {
  191. if (in_array($attribute, $queryAttributes)) {
  192. $mask += 1 << $pos;
  193. $res += $queryParams[$attribute] << $pos;
  194. }
  195. }
  196. if ($mask != 0) {
  197. $conditions[] = "$field & $mask = $res";
  198. }
  199. }
  200. return new Expression(implode('and', $conditions));
  201. }
  202. }
  203. ```
  204. ### Usage
  205. ##### Search
  206. ```php
  207. $myModels = MyModel::find()
  208. ->andWhereStatus(['s0' => 1, 's1' => 0])
  209. ->orWhereStatus(['s2' => 0, 's3' => 1])
  210. ->all();
  211. ```