Customizing a Symfony layout with property settings via slots

July 18th, 2008 | Tags: , ,

Ever wanted to have a layout in Symfony that allowed a template to pass it information about what to display in a more structured manner than slots allow? Well, here’s how to do it. You still need to use slots to avoid the caching issues described in http://trac.symfony-project.org/wiki/Symfony11LayoutUpgrade, but it is pretty easy to do once you know how.

For example, you have to basic page designs using the same layout, you just need to set a css class on the body element so your stylesheet knows which design to display. The default design is with no css class set and the alternate design is in effect when the css class is set to “alternate”.

You would normally do this with a simple slot in your layout:

<body class="<?php if(has_slot('bodyClass')) { include_slot('bodyClass'); } ?>">

Then, for any view that needs the alternate design, put this in its template:

< ?php slot('bodyClass') ?>alternate< ?php end_slot() ?>

Now, this will work well for a while—until you want to change the class name from alternate to something else and you realize that you now have 50 pages to go edit. Is there a way to avoid this maintenance horror?

Try the following change and see what you think. First, go back to the template and change it to:

< ?php slot('useAlternateDesign') ?>true< ?php end_slot() ?>

Then, in the layout:

</body><body <?php if(has_slot('useAlternateDesign') &amp;&amp; get_slot('useAlternateDesign') == 'true'): ?> class="alternate"< ?php endif; ?>></body>

Note that we were also able to cleanup the output in the default case. It will no longer output <body class="">, it will output simply <body> as it should.

Sometimes you may want to use the layout property more than once in the layout, but checking

has_slot('useAlternateDesign') &amp;&amp; get_slot('useAlternateDesign') == 'true'

each time is redundant and a code smell. Instead, assign it to a local variable at the top of the layout:

< ?php $useAlternateDesign = (has_slot('useAlternateDesign') &amp;&amp; get_slot('useAlternateDesign') == 'true'); ?>

Then, whenever you need to reference the property, it is as simple as

<body <?php if($useAlternateDesign): ?> class="alternate"< ?php endif; ?>>

or

< ?php if($useAlternateDesign): ?>
    <div id="crumbs">
        <a href="/">Home</a> &amp;raquo;
        < ?php if (has_slot('crumbs')): ?>
            < ?php include_slot('crumbs') ?>
        < ?php endif; ?>
    </div>
< ?php endif; ?>

Finally, there may be a circumstance where you want to set the layout property dynamically in the action. This is also possible:

$this->getResponse()->setSlot('useAlternateDesign', $myObject->isAltType);

Note: I believe the setSlot method is new with Symfony 1.1, but I have not confirmed it.

Update: I have recently learned that you can shorten:

< ?php slot('useAlternateDesign') ?>true< ?php end_slot() ?>

to:

< ?php slot('useAlternateDesign', true); ?>

No comments yet.

TOP