CakePHP: Auto populating foreign key dropdown fields
One of the neet features of CakePHP's scaffolding is that it automatically populates your foreign key (belongsTo, hasAndBelongsToMany) fields in your forms.
Lets take a look at a simple example to illustrate this:
app/models/article.php:
class Article extends AppModel { var $hasAndBelongsToMany = array( "Tag" ); }
app/models/tag.php:
class Tag extends AppModel { var $hasAndBelongsToMany = array( "Article" ); }
app/controllers/article_controller.php:
class ArticleController extends AppController { var $scaffold; }
app/controllers/tags_controller.php:
class TagController extends AppController { var $scaffold; }
Now, when you visit http://webroot/articles/add you'll see that CakePHP has helpfully changed the foreign key field for Tags to a multi-select list of all the Tags:

Once you switch off scaffolding and start creating your own add/edit methods you'll loose this handy feature. You have to manually add the following to the add/edit actions to re-enable this feature:
function add() { // usual add code // populate the foreign key lookups $this->set("Tags", $this->Article->Tag->find("list"); }
That can be a bit of a bind to remember to do that for each foreign key and for each view that needs this functionality.
Here's an automatic method for retaining this feature in your own hand built methods.
Add the following code to your AppController (so the functionality is inherited for all your controllers):
/** * Populates the view with variables required for foreign key fields * * @param $models array list of models to fetch lookups for * if empty, the list automatically populated with the associated models * * @return none view vars are set for each associated model */ function _populateLookups($models = array()) { if (empty($models)) { // build a list of all associated models: // create a reference to the Controllers root model // this is the first item in the controllers $uses array // or the default if $uses is empty $rootModel = $this->{$this->modelClass}; // build list of belongsTo Models foreach($rootModel->belongsTo as $model=>$attr) { $models[] = $model; } // build list of hasAndBelongsToMany Models foreach($rootModel->hasAndBelongsToMany as $model=>$attr) { $models[] = $model; } } // populate the view vars with the lookup lists for each associated model foreach($models as $model) { // calculate the name of the variable to populate based on the model name $name = Inflector::variable(Inflector::pluralize($model)); // populate the view var $this->set($name, $rootModel->{$model}->find("list")); } }
What this does is to automate the process off populating those foreign key view vars. If you don't pass in a list of models it will dig out the associated models automatically.
Now we need to run this function every time we display an add or edit form. Add the following code to your AppController. If you already have a beforeRender() function you can append this code to end.
/** * Runs before the view is rendered * @see cake/libs/controller/Controller#beforeRender() */ function beforeRender() { switch($this->action) { case "add": case "edit": $this->_populateLookups(); break; } }
What this does is to check which action we are performing and then calls _populateLookups() if its an add or edit action.
- Richard@Home:


Comments
Source code markup
I've just noticed the source code markup is being double escaped.
Lines such as:
$this->set("Tags", $this->Article->Tag->find("list");
Should read:
$this->set("Tags", $this->Article->Tag->find("list");
I'm working on a fix for this :-)
Issue is fixed
Added the following three lines to sites/all/modules/geshifilter/geshi/geshi.php:
as recommended in the comments here: http://drupal.org/node/269937
Post new comment