Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Login with Facebook

Sign In Apply for Membership

In this Discussion

2011-08-10 Playing with forms in Symfony 1.4
  • SiegfriedSiegfried August 2011
    let's see
  • renoirbrenoirb August 2011
    J'ai écrit un commentaire sur la solution que j'ai trouvé sur Stack Overflow:

    http://stackoverflow.com/questions/2922599/adding-classes-to-all-form-widgets-in-symfony/
  • renoirbrenoirb August 2011
    Pour des raisons de postérité, j'ai copié ce que j'ai écrit sur StackOverflow

    http://stackoverflow.com/questions/2922599/adding-classes-to-all-form-widgets-in-symfony/#answer-7060491

    Je traduirai probablement un article plus détaillé plus tard en français sur mon blogue:


    ----

    I am having the same issue.

    Situation We have come to think that the separation between CSS and symfony's widget generation is a big learning curve for the integrators and we think there must be a way to leave the integrators more independent from the developers.

    Client always want to have custom styled forms... and yet, custom handmade !DRY code is done. What I mean is that, Graphic designers do not design forms with only input text and label, they find all creative ways and our reality is to make it work in the framework to look the same as they design.

    That's why we thought of using a sfWidgetFormSchemaFormatter, but form controllers are all different, and we wanted to be able to inject styling FROM the views... because it's an integration matter, not application matter. per se.

    Solution path My team-lead and I came up to a solution. Mostly using partials and looping through them. A form view could look like what follows.

    Our solution is not perfect because we'd like to say by the call in the view which controller could get which class names. But it's better than to use CSS's input[type=text] because our client still uses IE8 and less. But at least,

    So we thought of Why not mapping field id's with a className that could have a different behavior (different from label+input (and of course +helper+error if needs be)).

    What we do is that we inject control style for those special controllers (e.g.: label+select+select+select+helper+error) let's say this Widget has id some_field_id and we need it to the parent li.

    We could do it like this:


    $node_classes_map => array('some_field_id'=>'date-selector')


    So... now's time for some code:

    First, we need to use the 'list' widgetFormatter:



    // lib/form/SomeForm.php
    class SomeForm extends BaseSomeForm
    {
    public function configure()
    {
    $this->widgetSchema->setFormFormatterName('list');
    }
    }

    Or, you could use qais answer to have ALL forms as lists (at last!! I didn't knew before now).

    The view:


    // apps/appName/modules/moduleName/templates/someviewSuccess.php
    $node_classes_map = array(
    'some_field_id'=>'date-selector'
    // .date-selector would have many select side by side.
    // (no CSS for that in this example)
    );
    include_partial('global/patterns/formParent',
    array(
    'form'=>$form,
    'form_classes'=>'labels-on-left',
    'node_classes_map' => $node_classes_map
    )
    );

    formParent looks like:


    // apps/appName/templates/_patterns/formParent.php
    $form_classes_attr = (isset($form_classes))?' class="'.$form_classes.'"':'';
    $form_list_node_partial = 'global/patterns/listFormDefaultNode';
    $model_name_lowercase = strtolower($form->getModelName());
    $node_classes_map = (isset($node_classes_map))?$node_classes_map:array();
    ?>
    <?php use_stylesheets_for_form($form) ?>
    <?php use_javascripts_for_form($form); ?>
    <form action="<?php
    echo url_for($model_name_lowercase.'/'.($form->getObject()->isNew() ? 'create' : 'update').(!$form->getObject()->isNew() ? '?id='.$form->getObject()->getId() : ''))
    ?>"<?php echo $form_classes_attr;
    ?> method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" '?>>
    <h2><?php echo __(($form->getObject()->isNew()?'new.':'edit.').$model_name_lowercase.'.form.title'); ?></h2>
    <fieldset>
    <ol>
    <?php
    foreach($form as $item){
    $node_classes = (isset($node_classes_map[$item->renderId()]))?$node_classes_map[$item->renderId()]:'';
    include_partial($form_list_node_partial,
    array(
    'item'=>$item,
    'node_classes' => $node_classes
    )
    );
    }
    ?>
    <ol>
    </fieldset>
    <?php echo $form->renderHiddenFields() ?>
    <?php echo $form->renderGlobalErrors() ?>
    <?php echo (!$form->getObject()->isNew())? '<input type="hidden" name="sf_method" value="put" />':''; ?>
    </form>

    Each form element gets rendered by either a custom one or listFormDefaultNode.

    From there, you could come up with a different partial to render a controller differently from a mainstream label+input+helper+errors to something more complex like label+select+select+select+helper+erros.

    This is my default form *Node


    // apps/appName/templates/_patterns/listFormDefaultNode.php
    /**
    * Manual: http://www.symfony-project.org/forms/1_4/en/A-Widgets
    */
    if(!$item->isHidden()){ ?>
    <li class="<?php echo $item->renderId().((is_string($node_classes))?' '.$node_classes:''); ?>">
    <?php echo $item->renderLabel(); ?>
    <?php echo $item; ?>
    <?php echo (!!$item->renderHelp())?'<span class="helpers">'.$item->renderHelp().'</span>':''; // I did not find any hasHelper(), so switching to bool ?>
    <?php echo ($item->hasError())?'<span class="alertify error">'.$item->renderError().'</span>':''; ?>
    </li>
    <? }

    Lastly, here is a start from my CSS:

    Please note, here is a part of a project CSS and this uses part of concepts i'm developping with Snippies. Go there to get more ideas how I am structuring my CSS.