mscherer 9 年 前
コミット
e13ba61c88
1 ファイル変更85 行追加0 行削除
  1. 85 0
      docs/Behavior/Bitmasked.md

+ 85 - 0
docs/Behavior/Bitmasked.md

@@ -0,0 +1,85 @@
+# Bitmasked Behavior
+
+A CakePHP behavior to allow quick row-level filtering of models via bitmasks.
+
+## Introduction
+Basically it encodes the array of bit flags into a single bitmask on save and vice versa on find.
+I created it as an extension of my pretty well working Enum stuff. It can use this type of enum declaration for our bitmask, as well.
+It uses constants as this is the cleanest approach to define model based field values that need to be hardcoded in your application.
+
+### Technical limitation
+The theoretical limit for a 64-bit integer [SQL: BIGINT unsigned] would be 64 bits (2^64). 
+Don’t use bitmasks if you seem to need more than a hand full, though. 
+Then you obviously do something wrong and should better use a join table.
+I highly recommend using `tinyint(3) unsigned` which can hold up to 8 bits – more than enough. It still only needs 1 byte. 
+
+
+## Usage
+Attach it to your model's `Table` class in its `initialize()` method like so:
+```php
+$this->addBehavior('Tools.Bitmasked', $options);
+```
+
+If you want to alias the field for output:
+```php
+$this->addBehavior('Tools.Bitmasked', ['mappedField' => 'statuses', 'field' => 'status']);
+```
+
+The `mappedField` param is quite handy if you want more control over your bitmask. 
+It stores the array under this alias and does not override the bitmask key. 
+So in our case status will always contain the integer bitmask and statuses the verbose array of it.
+
+### Defining the selectable values
+We first define values and make sure they follow the bitmask scheme:
+```
+1, 2, 4, 8, 16, 32, 64, 128, ...
+```
+
+I recommend using a DRY [enum approach](http://www.dereuromark.de/2010/06/24/static-enums-or-semihardcoded-attributes/), using your entity: 
+```php
+// A bunch of bool values
+const STATUS_ACTIVE = 1;
+const STATUS_FEATURED = 2;
+const STATUS_APPROVED = 4;
+const STATUS_FLAGGED = 8;
+
+...
+
+public static function statuses($value = null) {
+	$options = [
+		self::STATUS_ACTIVE => __('Active'),
+		self::STATUS_FEATURED => __('Featured'),
+		self::STATUS_APPROVED => __('Approved'),
+		self::STATUS_FLAGGED => __('Flagged'),
+	];	
+	return parent::enum($value, $options);
+}
+```
+
+Please note that you need to define Entity::enum() by extending my Tools Entity base class or by putting it into your own base class manually. You don’t have to use the enum approach, though.
+
+Of course it only makes sense to use bitmasks, if those values can co-exist, if you can select multiple at once. Otherwise you would want to store them separately anyway.
+Obviously you could also just use four or more boolean fields to achieve the same thing.
+
+So now, in the add/edit form we can:
+```php
+echo $this->Form->input('statuses', ['options' => Comment::statuses(), 'multiple' => 'checkbox']);
+```
+
+Tip: Usually, you have passed down the current entity for the form building anyway, then you don't need static access:
+```php
+echo $this->Form->create($comment);
+echo $this->Form->input('statuses', ['options' => $comment->statuses(), 'multiple' => 'checkbox']);
+...
+```
+
+It will save the final bitmask to the database field `status` as integer. For example "active and approved" would become `9`.
+
+
+
+
+### Outview
+
+You can read more about how it began in [my blog post](http://www.dereuromark.de/2012/02/26/bitmasked-using-bitmasks-in-cakephp/).
+
+If you want to use a more DB or Config driven approach towards enums, you can also look into other plugins and CakePHP resources available, e.g. [this](https://github.com/CakeDC/Enum) implementation.