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.

250 lines
5.5 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 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\helpers\ArrayHelper;
  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. ActiveRecord::EVENT_AFTER_REFRESH => 'afterFind',
  29. ];
  30. }
  31. public function beforeSave()
  32. {
  33. foreach ($this->bitFlags as $bitFlag => $flags) {
  34. $this->owner->$bitFlag = 0;
  35. $this->setBitFlag($bitFlag, $flags);
  36. }
  37. }
  38. public function beforeUpdate()
  39. {
  40. foreach ($this->bitFlags as $bitFlag => $flags) {
  41. $this->setBitFlag($bitFlag, $flags);
  42. }
  43. }
  44. public function afterFind()
  45. {
  46. $owner = $this->owner;
  47. foreach ($this->bitFlags as $bitFlag => $flags) {
  48. $bitFlagValue = $owner->$bitFlag;
  49. foreach ($flags as $pos => $flag) {
  50. $owner->$flag = ($bitFlagValue & 1 << $pos) >> $pos;
  51. }
  52. }
  53. }
  54. /**
  55. * 设置位标志
  56. * @param string $bitFlag 位标志
  57. * @param string[] $flags 标志
  58. */
  59. public function setBitFlag($bitFlag, $flags)
  60. {
  61. $owner = $this->owner;
  62. foreach ($flags as $pos => $flag) {
  63. $flagValue = $owner->$flag;
  64. if ($flagValue === null) {
  65. continue;
  66. }
  67. $owner->$bitFlag = $this->getBitFlagUpdate($owner->$bitFlag, $pos, $flagValue);
  68. }
  69. }
  70. /**
  71. * 获得更新后的位标志值
  72. * @param int $bitFlagValue 位标志值
  73. * @param int $pos 状态位置
  74. * @param bool|int $flagValue 标志值
  75. * @return int
  76. */
  77. public function getBitFlagUpdate($bitFlagValue, $pos, $flagValue)
  78. {
  79. if ($flagValue) {
  80. $bitFlagValue = $bitFlagValue | 1 << $pos;
  81. } else {
  82. $bitFlagValue = $bitFlagValue & ~(1 << $pos);
  83. }
  84. return $bitFlagValue;
  85. }
  86. }
  87. ```
  88. ##### 在需要的`Model`里添加`Behavior`
  89. ```php
  90. <?php
  91. namespace {yourApp}\models;
  92. use {yourApp}\behaviors\BitFlagBehavior;
  93. class MyModel extends base\MyModel
  94. {
  95. /**
  96. * @var int 状态
  97. */
  98. public $s0;
  99. public $s1;
  100. public $s2;
  101. public $s3;
  102. public $s5;
  103. public $s6;
  104. public $s7;
  105. public $s8;
  106. /**
  107. * 位标志映射表:
  108. * [
  109. * 位标志名 => [
  110. * 标志位 => 标志名
  111. * ]
  112. * ...
  113. * ]
  114. */
  115. const BIT_FLAGS = [
  116. 'status' => [
  117. 's0',
  118. 's1',
  119. 's2',
  120. 's3',
  121. ],
  122. // 'flags' => [
  123. // 's5', 's6', 's7', 's8'
  124. // ]
  125. ];
  126. public function fields()
  127. {
  128. $fields = [];
  129. foreach (self::BIT_FLAGS as $bitFlag) {
  130. $fields = ArrayHelper::merge($fields, array_combine($bitFlag, $bitFlag));
  131. }
  132. return ArrayHelper::merge(parent::fields(), $fields);
  133. }
  134. public function behaviors()
  135. {
  136. return [
  137. // 其他Behavior
  138. 'bitFlagBehavior' => [
  139. 'class' => BitFlagBehavior::class,
  140. 'bitFlags' => self::BIT_FLAGS,
  141. ],
  142. ];
  143. }
  144. /**
  145. * {@inheritdoc}
  146. * 重写find()返回自定义查询类
  147. */
  148. public static function find()
  149. {
  150. $config = ['bitFlags' => self::BIT_FLAGS];
  151. return new MyModelQuery(get_called_class(), $config);
  152. }
  153. // 其他Model代码......
  154. }
  155. ```
  156. ##### 添加文件 `MyModelQuery`
  157. ```php
  158. <?php
  159. namespace {yourApp}\models;
  160. use yii\db\ActiveQuery;
  161. use yii\db\Expression;
  162. class MyModelQuery extends ActiveQuery
  163. {
  164. /**
  165. * [
  166. * 位标志名 => [
  167. * 标志位 => 标志名
  168. * ]
  169. * ...
  170. * ]
  171. * @var array[] $bitFlags 融合状态表
  172. */
  173. public $bitFlags;
  174. /**
  175. * @param string[] $conditions
  176. * @return MyModelQuery
  177. */
  178. public function andWhereBitFlags($conditions = [])
  179. {
  180. return $this->andWhere($this->getBitFlagsCondition($conditions));
  181. }
  182. /**
  183. * @param string[] $conditions
  184. * @return MyModelQuery
  185. */
  186. public function orWhereBitFlags($conditions = [])
  187. {
  188. return $this->orWhere($this->getBitFlagsCondition($conditions));
  189. }
  190. /**
  191. * @param array $conditions
  192. * @return Expression
  193. */
  194. public function getBitFlagsCondition($conditions = [])
  195. {
  196. $conditionsKeys = array_keys($conditions);
  197. foreach ($this->bitFlags as $bitFlag => $flags) {
  198. $mask = $res = 0;
  199. foreach ($flags as $pos => $flag) {
  200. if (in_array($flag, $conditionsKeys)) {
  201. $mask += 1 << $pos;
  202. $res += $conditions[$flag] << $pos;
  203. }
  204. }
  205. if ($mask != 0) {
  206. $bitFlagsConditions[] = "$bitFlag & $mask = $res";
  207. }
  208. }
  209. return new Expression(implode(' and ', $bitFlagsConditions));
  210. }
  211. }
  212. ```
  213. ### Usage
  214. ##### Search
  215. ```php
  216. $myModels = MyModel::find()
  217. ->andWhereBitFlags(['s0' => 1, 's1' => 0])
  218. ->orWhereBitFlags(['s2' => 0, 's3' => 1])
  219. ->all();
  220. ```