Enum support via trait and enum() method.
There are many cases where an additional model + table + relation would be total overhead. Like those little "status", "level", "type", "color", "category" attributes. Often those attributes are implemented as "enums" in SQL - but cake doesn't support them natively. And it should not IMO. You might also want to read this ;)
If there are only a few values to choose from and if they don't change very often, you might want to consider the following approach. It is very efficient and easily expandable on code level.
Further advantages
Add tinyint(2) unsigned field called for example "status" (singular). "tinyint(2) unsigned" covers 0...127 / 0...255 - which should always be enough for enums. if you need more, you SHOULD make an extra relation as real table.
Do not use tinyint(1) as CakePHP interprets this as a (boolean) toggle field, which we don't want!
Add the trait to your entity:
use Tools\Model\Entity\EnumTrait;
class MyEntity extends Entity {
use EnumTrait;
Then add your enums like so:
/**
* @param int|array|null $value
*
* @return array|string
*/
public static function statuses($value = null) {
$options = [
static::STATUS_PENDING => __('Pending'),
static::STATUS_SUCCESS => __('Success'),
static::STATUS_FAILURE => __('Failure'),
];
return parent::enum($value, $options);
}
public const STATUS_PENDING = 0;
public const STATUS_SUCCESS = 1;
public const STATUS_FAILURE = 2;
You can now use it in the forms in your templates:
<?= $this->Form->create($entity) ?>
...
<?= $this->Form->control('status', ['options' => $entity::statuses()]) ?>
And in your index or view:
echo $entity::statuses($entity->status);
Make sure the property is not null (or it would return an array). Best to check for it before or combine
it with Shim plugin GetTrait and $entity->getStatusOrFail():
// Allowed to be empty
echo $entity->status !== null ? $entity::statuses($entity->status) : $default;
// Required or throw exception
echo $entity::statuses($entity->getStatusOrFail());
You can also use it anywhere else for filtering, or comparison:
use App\Model\Entity\Notification;
$unreadNotifications = $this->Notifications->find()
->where(['user_id' => $uid, 'status' => Notification::STATUS_UNREAD)])
->all();
You can reorder the choices per form by passing a list of keys in the order you want. With this, you can also filter the options you want to allow:
<?= $this->Form->control('status', [
'options' => $entity::statuses([$entity::STATUS_FAILURE, $entity::STATUS_SUCCESS]),
]) ?>
Use the Setup plugin (--theme Setup) to
get auto-support for your templates based on the existing enums you added.
The above form controls would be auto-added by this.
See Static Enums.
If you are looking for combining several booleans into a single database field check out my Bitmasked Behavior.