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.2 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. # BitFlag 位标志
  2. ### Configuration
  3. ##### 添加文件: `BitFlagBehavior.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 BitFlagBehavior extends Behavior
  11. {
  12. /**
  13. * [
  14. * 位标志名 => [
  15. * 标志位 => 标志名
  16. * ]
  17. * ...
  18. * ]
  19. * @var array[] $bitFlags 位标志映射表
  20. */
  21. public $bitFlags = [];
  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->bitFlags as $bitFlag => $flags) {
  33. $this->owner->$bitFlag = 0;
  34. $this->setBitFlag($bitFlag, $flags);
  35. }
  36. }
  37. public function beforeUpdate()
  38. {
  39. foreach ($this->bitFlags as $bitFlag => $flags) {
  40. $this->setBitFlag($bitFlag, $flags);
  41. }
  42. }
  43. public function afterFind()
  44. {
  45. $owner = $this->owner;
  46. foreach ($this->bitFlags as $bitFlag => $flags) {
  47. $bitFlagValue = $owner->$bitFlag;
  48. foreach ($flags as $pos => $flag) {
  49. $owner->$flag = ($bitFlagValue & 1 << $pos) >> $pos;
  50. }
  51. }
  52. }
  53. /**
  54. * 设置位标志
  55. * @param string $bitFlag 位标志
  56. * @param string[] $flags 标志
  57. */
  58. public function setBitFlag($bitFlag, $flags)
  59. {
  60. $owner = $this->owner;
  61. foreach ($flags as $pos => $flag) {
  62. $flagValue = $owner->$flag;
  63. if ($flagValue === null) {
  64. continue;
  65. }
  66. $owner->$bitFlag = $this->getBitFlagUpdate($owner->$bitFlag, $pos, $flagValue);
  67. }
  68. }
  69. /**
  70. * 获得更新后的位标志值
  71. * @param int $bitFlagValue 位标志值
  72. * @param int $pos 状态位置
  73. * @param bool|int $flagValue 标志值
  74. * @return int
  75. */
  76. public function getBitFlagUpdate($bitFlagValue, $pos, $flagValue)
  77. {
  78. if ($flagValue) {
  79. $bitFlagValue = $bitFlagValue | 1 << $pos;
  80. } else {
  81. $bitFlagValue = $bitFlagValue & ~(1 << $pos);
  82. }
  83. return $bitFlagValue;
  84. }
  85. }
  86. ```
  87. ##### 在需要的`Model`里添加`Behavior`
  88. ```php
  89. <?php
  90. namespace {yourApp}\models;
  91. use {yourApp}\behaviors\BitFlagBehavior;
  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 BIT_FLAGS = [
  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. 'bitFlagBehavior' => [
  131. 'class' => BitFlagBehavior::class,
  132. 'bitFlags' => self::BIT_FLAGS,
  133. ],
  134. ];
  135. }
  136. /**
  137. * {@inheritdoc}
  138. * 重写find()返回自定义查询类
  139. */
  140. public static function find()
  141. {
  142. $config = ['bitFlags' => self::BIT_FLAGS];
  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[] $bitFlags 融合状态表
  163. */
  164. public $bitFlags;
  165. /**
  166. * @param string[] $conditions
  167. * @return MyModelQuery
  168. */
  169. public function andWhereBitFlags($conditions = [])
  170. {
  171. return $this->andWhere($this->getBitFlagsCondition($conditions));
  172. }
  173. /**
  174. * @param string[] $conditions
  175. * @return MyModelQuery
  176. */
  177. public function orWhereBitFlags($conditions = [])
  178. {
  179. return $this->orWhere($this->getBitFlagsCondition($conditions));
  180. }
  181. /**
  182. * @param array $conditions
  183. * @return Expression
  184. */
  185. public function getBitFlagsCondition($conditions = [])
  186. {
  187. $conditionsKeys = array_keys($conditions);
  188. foreach ($this->bitFlags as $bitFlag => $flags) {
  189. $mask = $res = 0;
  190. foreach ($flags as $pos => $flag) {
  191. if (in_array($flag, $conditionsKeys)) {
  192. $mask += 1 << $pos;
  193. $res += $conditions[$flag] << $pos;
  194. }
  195. }
  196. if ($mask != 0) {
  197. $bitFlagsConditions[] = "$bitFlag & $mask = $res";
  198. }
  199. }
  200. return new Expression(implode(' and ', $bitFlagsConditions));
  201. }
  202. }
  203. ```
  204. ### Usage
  205. ##### Search
  206. ```php
  207. $myModels = MyModel::find()
  208. ->andWhereBitFlags(['s0' => 1, 's1' => 0])
  209. ->orWhereBitFlags(['s2' => 0, 's3' => 1])
  210. ->all();
  211. ```