Stop ACTA

Creating a select box for a related model

Posted in CakePHP on 26.06.2008.

Since this question has been asked many times, here it is in a form of short tutorial. Hopefully someone will find it useful.

The question of creating a select box with CakePHP has come up many times. Actually, it's very simple, although not bleeding obvious. ;-)

This example is for CakePHP 1.2

Let's assume you have two models, Article and Category. The relations are set up like this:

  • Article -belongsTo-> Category
  • Category -hasMany-> Article

So you need to show a list of categories when you want to add or edit and article.

First of all, you controller will look like this:

class ArticlesController extends AppController
{
    var $name = 'Articles';
    var $uses = array('Article');
}

Now, in your controller, to keep it DRY, we define a private function which will setup the categories for our view.

class ArticlesController extends AppController
{
    // snip...

    function _setCategories()
    {
        $categories = $this->Article->Category->find
            (
                'list',
                array
                (
                    'fields' => array('id', 'name'),
                    'order' => 'Category.name ASC',
                    'recursive' => -1
                )
            );

        $this->set(compact('categories'));
    } 

    // snip...
}

The important thing to note here, is the parameter "list" instead of "all". When you do a find('list', ...) CakePHP will automagically generate a list of options ready to use with the FormHelper. But, let's see that one by example.

In your add() and/or edit() action of the controller, you have this:

class ArticlesController extends AppController
{
    // snip...
    function add($slug = null)
    {
        $this->_setCategories();

        // your other stuff here
    }

    function edit($slug = null)
    {
        $this->_setCategories();

        // your other stuff here
    }

    // snip...
}

Now comes the fun part. All you have to do in your view now is the following:

// this would go in your ~/app/views/articles/add.ctp (and/or edit.ctp)
<?php
echo $form->select
    (
        'Article.category_id', // name of the field in Article model
        $categories, // the var we've set in _setCategories()
        null,
        array(),
        false
    );
?>

This should give you a nice select box with your categories listed alphabetically. Pretty damn neat, right?

Alternatively, if you don't want to lose the cake magic by using $form->select, you can still use $form->input like this:

<?php
echo $form->input
    (
        'Article.category_id',
        array
        (
            'options' => $categories
        )
    );
?>

CakePHP does all the magic for you. Still, if you need different options than those described here, take a look at the API reference for Model::find()[1], FormHelper::select()[2] and FormHelper::input()[3]. Please note that I've typed all this from my memory, so if you find any typos let me know ;-)

Happy baking!

  1. Model::find() API reference
  2. FormHelper::select() API reference
  3. FormHelper::input() API reference

Article comments — View · Add


Page 1 of 3
1 · 2 · 3

Daniel Hofstetter :: 26.06.2008 03:52:59
Just a detail, but the var $uses statement in the ArticlesController is not needed as Cake automatically loads the Article model.
lecterror :: 26.06.2008 04:43:13
Yes, but I figured it can't hurt either ;-)

Also, I remember the time when I didn't know that I can access the related model via $this->Article->Category, so what I used to do was:

var $uses = array('Article', 'Category');

I was so wrong... :-/

(In fact, I think this code is still running my site)
rafaelbandeira3 :: 03.09.2008 17:24:14
Actually you don't need to manually set your input options if you follow the var you passed to the view has the name equal to

Inflector::varName(Inflector::pluralize(preg_replace('/_id$/', '', $fieldName)))

wich means that, for Post.category_id you should have a "categories" var passed to the view, and for Employee.soccer_team_id you should have a "soccerTeams"

as shown in FormHelper's source line 607: http://api.cakephp.org/form_8php-source.html#l00607

BTW, I didn't like the fact that I can't post a comment while seeing other people comments, I can't cite them or use as reference... but that's my opinion of course...
lecterror :: 05.09.2008 09:24:12
Hi rafaelbandeira3,

thanks for the tip, that's a good one.

We'll see about the comments, it will probably be done in a future (but unspecified!:)) release of Neutrino.
kevin_smith :: 07.12.2008 17:57:43
Would you post this into the bakery? The only example I could find there is for 1.x and I wasted have a day before stumbling upon this.

Oh, and thanks.