Some new crazy (Cake)PHP tricks

Crazy – because these tips are not used that often probably. But for some rare occasions they might come in handy.

Inserting some rows into an array

$array = array(
    'one',
    'two',
    'three'
);
$newValue = 'one-point-five';
//with 0 as 3rd arg we can actually add values at the position of arg 2
array_splice($array, 1, 0, array($newValue));

Note that the 4th argument must be an array for this to work.

Using the same value for multiple select options

With a simpel key/value list and select() you won’t get far. You cannot use the same key twice in an array. That is a common beginner mistake.
To overcome this you need a bit more verbose array here:

 $options = array(
 	...
 	array('name' => 'United states', 'value' => 'USA'),
    array('name' => 'USA', 'value' => 'USA'),
 );
 
 echo $this->Form->input('test', array('type'=>'select', 'options'=>$options));

This will then print

...
<option value="USA">United states</option>
<option value="USA">USA</option>

See the docs for more infos on select().

Setting additional attributes for some select options

You might want set some option elements to a specific class. The FormHelper::select() is powerful enough to support this:

// normal options
$options = array(1 => 'One', 2 => 'Two', 3 => 'Three');

// advanced (second elements has a class "extra")
$options = array(
    1 => 'One', 
    2 => array('name' => 'Two', 'value' => 2,  'class' => 'extra'), 
    3 => 'Three');

echo $this->Form->input('test', array('type' => 'select', 'options' => $options));

The result:

<div class="input select">
    <label for="ModelTest">Test</label>
    <select name="data[Model][test]" id="ModelTest">
        <option value="1">One</option>
        <option value="2" class="extra">Two</option>
        <option value="3">Three</option>
    </select>
</div>

You might want to check this site here if the styles you want to apply work in all browsers. Usually only some styles like background-color are apply-able cross-browser.

Autofocus

Not so much CakePHP as maybe HTML5 – but pretty useful for login forms:

echo $this->Form->input('login', array('autofocus'=>'autofocus'));

All new browsers support it out of the box. The user can start typing right away (no additional click necessary).

More HTML5 out-of-the-box

In general HTML5 is great, but still not fully supported by all browsers – or users just don’t update to a new version.
So we shouldn’t completely rely on those features. But where – as the above autofocus – the absence in unsupportive browsers doesn’t bother anyone we can easily apply those features for users with modern browsers.

Additionally, we can use fallback-js to "simulate" the behavior if not natively supported. I put together a well-working HTML5-fallback script for jquery. It checks if the browser supports a certain feature and if not it creates a JS workaround.

I bet there are lots of other similar implementations. The important part for those placeholders is that on submit the content needs to be cleared again. The placeholders must not be posted (otherwise your validation rules might not work as expected anymore). I used the $('form').live('submit', function() {} event to clear the forms in time.

echo $this->Form->input('url', array('placeholder'=>'http://'));

All these snippets work in all browsers. In those modern ones a little bit faster. But that’s about all. You can already use it without any worries. And some day you can just turn of the fallback.

Structure your controllers

UsersController is often one of the most bloated controllers having tons of actions and views.
At some point this might get very confusing with so much code in a single file.

You don’t have to put all 40ish actions that are related to the User model in a single UsersController. Divide them to keep things clean and clear. So for me this worked pretty well:

  • AccountController (login, logout, register, change_pw, edit, …): $uses = array('User')
  • MembersController (index, search, profile, mail, friend, …, admin backend actions): $uses = array('User')
  • OverviewController (index, admin index, … – specially routed): $uses = array('User')

As you can see they all use the user model but they separate the actions by category. This way the file stays kinda short and is better understandable in the long run. Imagine all those actions in a single controller. No way 🙂

But also bear in mind that you should not start dividing everything into tiny little pieces. Only do it where it makes sense.

Controllers without models

Until today you coudn’t just set $uses to false in Cake2. What used to work in 1.3 will fail hard in 2.x. It was a pretty annoying problem I reported right away (but it needed a second one to actually get things into motion). If you just used isset($this->Model) it would try to load a non-existent model and die. The current head now contains the new fixed version which works now the way one would expect it to work:

  • true Use the default inflected model name.
  • array() Use only models defined in the parent class.
  • false Use no models at all, do not merge with parent class either.
  • array('Post', 'Comment') Use only the Post and Comment models. Models will also be merged with the parent class.

The default value is true.

So basically, if we don’t want to use any models (or at least no default model):

class TestController extends AppController {
    public $uses = array();
}

Note: only use false if you are certain the extended controllers (the AppController usually) don’t rely on any models. Otherwise it will break this functionality. That is why array() usually suffices.

3.86 avg. rating (78% score) - 7 votes

7 Comments

  1. for me …

    class TestController extends AppController {
    public $uses = null;
    }

    works fine too, so what is better ?

    best wishes!

  2. The tip for having same value repeated across different options in a select really made my day.
    OTOH the part ‘Structure your controllers’ needs more details, I don’t really get to the point. Maybe a more detailed example ?

  3. I tried to apply your trick for ‘same value for multiple select options’ to a radio input but the structure you mention
    doesn’t work for radio buttons. Do you have any idea of how I could make it ?
    Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.