Managing semi-static select options in Cake PHP using table-less models

|
In Cake PHP a model normally represents a database table. However there are times when it is not necessary to create a table to store data, in most cases this data would be a semi-static enumeration, as the size of an application increases the use of such semi-static lists increases.

For example options such as "Yes", "No", "Active", "Inactive" would simply be stored as tinyints in MySQL however they may need to be presented to the user as "Yes" or "No". For Cake PHP to automatically generate a drop down list with "Yes" and "No" a foreign key would need to be used instead, adding an unnecessary join to make select generation simpler.

The solution is to create a model that does not use a table at all. For most of my programs I call this model Staticselect as its main purpose is to give me quick access to commonly used drop down options that I can set in my controllers for the FormHelper to use in views. The model code is:


<?php
class Staticselect extends AppModel {
var $name = 'Staticselect';
var $useTable = false;

// Person titles
function titles() {
$titles = array('Mr.', 'Mrs.', 'Ms.', 'Miss.');
return $this->toOptions($titles);
}

// Convert array to key value options
function toOptions($a) {
$os = array();
foreach ($a as $v) $os[$v] = $v;
return $os;
}

// No/yes options with int values
function noYesInt() {
return array('0' => 'No', '1' => 'Yes');
}
}
?>

The above code shows a few sample functions. The most useful is probably toOptions, which will take an array and turn it into a hash where the keys and values are the same so that when generating selects the value selected by the user is also submitted with the form. The function noYesInt is a simple example of data I commonly store in such a model.

For those less familiar with the way Cake PHP works with options I will also show how the model can be used in a controller and view. The controller function where the static options are to be used should contain a line with:



$this->set('nyOptions', $this->Staticselect->noYesInt());


While the view would use the data in a form input using the code:



<?= $form->input('Settings.hideEmail', array('options' => $nyOptions)) ?>

6 comments:

Mingan said...

This is very handy technique, thank you for sharing!

Jimmy Bourassa said...

Indeed a very nice tip, but I'd be curious to see what kind of load time this "barebone" model requieres, since im assuming that it'll be loaded with the $uses var. Is it worth considering?

Ian said...

This is a very nice idea.

I've been using a component class to initialise these but your solution is much better :)

Thanks for sharing!

Paul Chiu said...

Thanks for the comment guys. To Jimmy: I have found loading time to not be affected at all. Since it does not refer to a table no extra SQL queries are executed and in PHP it simply creates a new AppModel child object in memory which does not cause significant memory load or slowdowns.

Yevgeny said...

It would simlier in php5
in model we define
public static function titles() {
$titles = array('Mr.', 'Mrs.', 'Ms.', 'Miss.');
return Staticselect::toOptions($titles);
}

and in view

$form->input('Settings.hideEmail', array('options' => Staticselect::titles()))

mercury said...

Did work for me directly.

It was failing with the error
Call to a member function noYesInt on a non-object.

However tried a different approach.

Added to function to my AppController.

And then in the Controller Method, simple call like this
$this->set('nyOptions', $this->noYesInt());

Finally use as described above the the view.

Post a Comment