Hey folks,
for a current client project of ours we had to build an extensive ACL-like permission system. It had to support roles permissions and specific user permissions, possibly overriding the roles permissions. So, to create a user, you had to first define his "role" or "level" as I called it in a dropdown box in a form.
However, the field users.level is an enum type and can have the values 'guest', 'user', 'admin', 'superadmin' and 'root'. The problem is that it could be possible that new levels were added in the future. There was no need though to have a seperate user_levels table and a UserLevel model there, since the system should simply not be as generic to allow that and adding a new level in the future would require a complete other version of the software. So I went the easy way.
Besides, as we use uuids, the users.level field would contain them and after all we want our database to be readable in our favorite db management system.
So what I came up with is a very simple behavior that can extract the options for any ENUM field. It uses simple caching in order for the query to not be run all the time, so make sure to clear your cache as you update your enum field options in the db.
Here is the behavior:
<?php
/**
* Behavior with useful functionality around models containing an enum type field
*
* Copyright (c) Debuggable, http://debuggable.com
*
* @package default
* @access public
*/
class EnumerableBehavior extends ModelBehavior {
/**
* Fetches the enum type options for a specific field
*
* @param string $field
* @return void
* @access public
*/
function enumOptions($model, $field) {
$cacheKey = $model->alias . '_' . $field . '_enum_options';
$options = Cache::read($cacheKey);
if (!$options) {
$sql = "SHOW COLUMNS FROM `{$model->useTable}` LIKE '{$field}'";
$enumData = $model->query($sql);
$options = false;
if (!empty($enumData)) {
$patterns = array('enum(', ')', '\'');
$enumData = r($patterns, '', $enumData[0]['COLUMNS']['Type']);
$options = explode(',', $enumData);
}
Cache::write($cacheKey, $options);
}
return $options;
}
}
?>
To put that into the form I did in the controller:
$enumOptions = ClassRegistry::init('User')->enumOptions('level');
$this->set(compact('enumOptions'));
and then in the form:
echo $form->input('level', array('options' => $enumOptions, 'label' => 'Level:'));
Enjoy and please give feedback.
-- Tim Koschuetzki aka DarkAngelBGE