zen of coding

Improved form handling in CakePHP 1.3

Here is a typical, simple form done with cake’s form helpers:

[code language=”php”]
echo $this->Form->create(‘Article’, array(‘action’ => ‘test’));

echo $this->Form->input(‘Article.title’);
echo $this->Form->input(‘Article.body’);
echo $this->Form->input(‘Article.user_id’, array(‘type’ => ‘hidden’));

echo $this->Form->end(‘Add Aricle with Tags and Comment’);
[/cc]

Which outputs the following HTML:

[code language=”html”]




[/cc]

This is fine and all, but one thing worth noting is that default behavior is wrapping each element in a div, and in some cases this may not be desirable. Either a legacy CSS or a front-end developer preference, might require the form to be structured (wrapped) differently.

Let’s see how we can set some defaults for our form with CakePHP 1.3., while simplifying the code a little at the same time by using the inputs() method…

[code language=”php”]
echo $this->Form->create(‘Article’, array(‘action’ => ‘test’,
‘inputDefaults’ => array(
‘div’ => array(‘tag’ => ‘p’),
‘before’ => ‘– goes before the label –‘,
‘after’ => ‘– goes after the input –‘)));

echo $this->Form->inputs(array(‘Article.title’,
‘Article.body’,
‘Article.user_id’ => array(‘type’ => ‘hidden’)),
array(‘legend’ => ‘Article submit’));

echo $this->Form->end(‘Add Aricle’);
[/cc]

Which produces:

[code language=”php”]


New Article

— goes before the label —


— goes after the input —

— goes before the label —


— goes after the input —


[/cc]

Of course for a simple form this may not be a very significant improvement, but having the ability to set defaults for the entire form and relying on some automagic for the rest, certainly makes one’s life easier.

  • It’s great to hear this improvement. I used to set ‘div’ => false when dealing with it. It’s time to make the code cleaner. :)

  • This is awesome, especially for forms that are not just scaffolding. Thanks for the post.

  • Pingback: CakePHP : signets remarquables du 09/11/2009 au 18/11/2009 | Cherry on the...()

  • @all

    Glad you’ve found it helpful.
    Certainly beats doing ‘div’ => false in every input, etc.

  • I have not tried cake php yet, but this looks pretty cool. I will have to check it out sometime. I am a big fan of RoR but php has more support.

  • @Shawn Bird

    Coming from RoR should be easier, but it’s important to remember that even thought the ideas behind both frameworks are similar they are not the same.

  • Absolutely agree that this is a hugely welcome development – one of my first issues with Cake was exactly this – in my view it’s really not the role of a framework to default to adding extra mark up.

  • I found the new changes quite welcome as well. It’s nice to see people already sharing their discoveries of CakePHP 1.3 before it hits the shelves.

    FYI, I believe you have a mistake in your code in the way you set the ‘legend’ property. Instead of this:
    inputs(array(‘Controller.field_id’, array(‘legend’ => ‘Legend Label’));

    You should have:
    inputs(array(‘Controller.field_id’, ‘legend’ => ‘Legend Label’));

    In your example generated HTML you can even see that your custom legend label is not being applied.

    Oh, and while you’re updating your article, you might want to point out that you can tell cake whether to wrap the fields in a fieldset as well. The following disables both the legend and the fieldset tags for the current inputs:
    inputs(array(‘Controller.field_id’, ‘legend’ => false, ‘fieldset’ => false));

    Cheers!

  • simply awesome :D

    oh and thanks for all the great articles.. really helpful stuff in here.

  • @Ben Pesso

    Seems like something is different about the way inputs() works … note, it’s not the input() method.

    Also, on the last one, these settings should be applied form-wide within the ‘inputDefaults’ key.

    p.s. I’m sure you meant Model.field_id, rather than Controller.

    Cheers. And thanks for your comments.

  • @teknoid

    Good catch on the Model.field_id!

    I WAS referring to the inputs() method and not input(). Check your sample output HTML and you’ll see it is not outputting your custom legend. I’m using inputs() in the way I have specified and it works perfectly. I tried yours just to be safe, but it does not work. Perhaps the API was changed since the article was written?

    I disagree with you on the matter of setting ‘legend’ and ‘fieldset’ flags only in the ‘inputDefaults’ setting. There are quite a few valid situations where one might want a them for a certain group of fields and not for another. E.g. I might want tags around all my text input fields, but not around a group of check boxes or the ‘submit’ button. Both are valid use cases that allow the user to customize the look and feel of his form without breaking the validity of its HTML.

  • Nick

    Hi,

    I would like to know can we change form id. Does is have any effect on form submit.

    Thanks.

  • teknoid

    @Nick

    You can pass it with the rest of form attributes (options) array.
    Unless you are doing any sort of AJAX submit, where you’d need the form id explicitly, I don’t see why it would have any impact.

  • Radu

    Does anyone know how can i set Form input {‘error’ => false} for all forms in the application? But not the time consuming method of writing this in the view.
    I belive there has to be a way of passing that in the appController.

  • teknoid

    @Radu

    Create a simple helper where create() method already uses input defaults that you need, and piggy-back on the Form helper for the rest.

%d bloggers like this: