Steven Brown

PHP

Symfony 2 Bootstrap CSS Form Templates

by on Aug.26, 2011, under CSS, PHP, Symfony

I have been playing around a bit with the Twitter Bootstrap CSS toolkit and I wanted to style the forms in a Symfony 2 project accordingly. On its own this is not a difficult task, you can do the following:

<form>
    <div class="clearfix">
        {{ form_label(form.email, 'Email Address') }}
        <div class="input">
            {{ form_widget(form.email) }}
            <span class="help-inline">{{ form_errors(form.email) }}</span>
        </div>
    </div>
    {{ form_rest(form) }}
    <input type="submit" />
</form>

This is fine enough, but it would be great to be able to do all of this using {{ form_row(form.email) }} instead of having to copy and paste the code for every field in every form.

As it turns out, creating your own templates for this stuff is pretty easy. One thing to note is if we want to mark the row as an “error” we need to add that class to the main div as well as the field itself. I also wanted to get rid of the bullet list, though you could probably achieve something similar with CSS modifications. The end result was:

{% extends 'form_div_layout.html.twig' %}
 
{% block field_errors %}
{% spaceless %}
    <span class="help-inline">
        {% if errors|length > 0 %}
            {% for error in errors %}
                {{ error.messageTemplate|trans(error.messageParameters, 'validators') }}<br />
            {% endfor %}
        {% endif %}
    </span>
{% endspaceless %}
{% endblock field_errors %}
 
{% block field_row %}
    <div class="clearfix {% if errors|length > 0 %}error{% endif %}">
        {{ form_label(form, label) }}
        <div class="input">
            {% set class = '' %}
            {% if errors|length > 0 %}
                {% set class = 'error' %}
            {% endif %}
            {{ form_widget(form, { 'attr': { 'class': class } }) }}
            {{ form_errors(form) }}
        </div>
    </div>
{% endblock field_row %}

One additional trick I added here is to be able to specify the field label in the form_row() call, something that doesn’t seem to be possible by default. Now you can add a Bootstrap ready form field row with:

{% form_theme form 'BootstrapCssBundle:Form:fields.html.twig' %}
<form>
    {{ form_row(form.email, { 'label': 'Email Address' }) }}
    {{ form_rest(form) }}
    <input type="submit" />
</form>

That’s all you need! You can put the form theme command before your form and do {{ form_widget(form) }} if you want to output the entire form in one go, as usual.

I actually broke out the styles into a few files in my Github repository.

4 Comments :, , , , , , , more...

Symfony 2 Field Comparison Validator

by on Aug.25, 2011, under PHP, Symfony

Symfony 2 comes with a range of predefined validators you can use to validate your forms, however I recently came across the need to validate that one field is equal to another. This is actually quite common since most registration forms will require you to enter your email and/or password twice.

You could easily embed a custom validator within the form itself:

use Symfony\Component\Validator\Constraints as Assert;
 
class User
{
    public $password;
 
    public $confirmationPassword;
 
    /**
     * @Assert\True(message = "The password and confirmation password do not match")
     */
    public function isPasswordEqualToConfirmationPassword()
    {
        return ($this->password === $this->confirmationPassword);
    }
}

I don’t really like that the error is added to the form rather than the individual field, and since this comparison is used often it would be much easier if it could be easily added via annotation.

In order to do this, we need two classes. The first defines the validator annotation, also known as a constraint:

use Symfony\Component\Validator\Constraint;
 
/**
* @Annotation
*/
class EqualsField extends Constraint
{
    public $message = 'This value does not equal the {{ field }} field';
    public $field;
 
    /**
     * {@inheritDoc}
     */
    public function getDefaultOption()
    {
        return 'field';
    }
 
    /**
     * {@inheritDoc}
     */
    public function getRequiredOptions()
    {
        return array('field');
    }
}

There is only one option for this constraint, that’s the name of the field we want to compare the current field against. In order to accept this field, we want to make it required and make it the default option, which means it will be populated with the first argument in the annotation (I think).

Notice how when we set the message we can use Twig style tokens, in this case {{ field }} will hold the name of the field we are comparing against.

Next, we add the validator itself, which accepts the form value and the constraint above, performs the comparison and returns whether or not it is valid:

use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Constraint;
 
class EqualsFieldValidator extends ConstraintValidator
{
    /**
     * Checks if the passed value is valid.
     *
     * @param mixed      $value      The value that should be validated
     * @param Constraint $constraint The constrain for the validation
     *
     * @return Boolean Whether or not the value is valid
     */
    public function isValid($value, Constraint $constraint)
    {
        if ($value !== $this->context->getRoot()->get($constraint->field)->getData()) {
 
            $this->setMessage($constraint->message, array(
                '{{ field }}' => $constraint->field,
            ));
 
            return false;
        }
 
        return true;
    }
}

Things are a bit tricky here, we don’t receive the comparison field or even the form to work with. Instead we get the form from the execution context ($this->context->getRoot()), from this we can get the field ($constraint->field from the constraint class we just created), then we get the data from it.

If the two values are not equal, we set the message with the field name and return false, essentially saying it’s invalid.

Now you can easily implement the validator with annotations:

use Skjb\Component\Validator\Constraint\EqualsField;
 
class User
{
    public $password;
 
    /**
     * @EqualsField('password', message = "The password and confirmation password do not match")
     */
    public $confirmationPassword;
}

Notice how we can still make our own nice message, we could actually use the {{ field }} token here if we wanted to.

I imagine you could easily create similar validators for less than, greater than, multiple of, or any other situation where a field is validated against another field.

You can find the code for this post at https://github.com/skjb/symfony2

Leave a Comment :, , , , , , more...

An Easier Way to Instantiate Models in Zend Framework Controllers

by on May.24, 2010, under PHP, Zend Framework

I get sick of having to type this:

$someTable = new Some_Table();
$someTable->someMethod();

Since PHP can’t chain on instantiation this gets very annoying.

I added this to my base controller (which all of my controllers extend):

public function __get($name)
{
    if (substr($name, -5) == 'Table') {
        $tableName = ucwords(substr($name, 0, -5)) . '_Table';
        return new $tableName();
    }
 
    return parent::__get($name);
}

Now in my actions I can use a table like this:

$this->someTable->someMethod();

Easy!

If you want to make it more efficient you can store the objects and return them if they are used multiple times:

private $_tables = array();
 
public function __get($name)
{
    if (substr($name, -5) == 'Table') {
        if (!isset($this->_tables[$name])) {
            $tableName = ucwords(substr($name, 0, -5)) . '_Table';
            $this->_tables[$name] = new $tableName();
        }
 
        return $this->_tables[$name];
    }
 
    return parent::__get($name);
}
1 Comment : more...

Installing ZFDebug

by on May.24, 2010, under PHP, Zend Framework

Installing ZFDebug is pretty simple, first of all you’ll want to download it or do a checkout from the ZFDebug Subversion repository.

Personally I added an external to my existing Subversion project, add the following to your svn:externals property in the library folder:

ZFDebug http://zfdebug.googlecode.com/svn/tags/release-1.5/library/ZFDebug

You only want ZFDebug in a development environment, you don’t want it appearing on a live site, so you’ll want to create a configuration option:

zfdebug.active = true

Then you simply register the plugin with your front controller, I do this in my bootstrap:

if (isset($this->_config->zfdebug) && $this->_config->zfdebug->active) {
    Zend_Controller_Front::getInstance()->registerPlugin(new ZFDebug_Controller_Plugin_Debug(array(
        'jquery_path' => 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js',
        'plugins' => array(
            'Variables', 
            'Html', 
            'Database', 
            'File', 
            'Memory', 
            'Time', 
            'Registry', 
            'Exception',
        ),
    )));
}

Read the ZFDebug documentation for more information on adding filters to the various plugins, and to add custom timers and custom memory usage points to your code.

Leave a Comment :, more...

MutateMe

by on May.22, 2010, under PHP

Check out this cool utility created by Pádraic Brady for hardcore unit testers, it can automatically mutate your data in order to check if your unit tests are thorough enough.

MutateMe

I’ll have to get it working so I can post a tutorial.

Leave a Comment :, , more...

ZFDebug

by on May.22, 2010, under PHP, Zend Framework

Thanks for Darby Felton for putting me on to this cool Zend Framework debugging utility:

ZFDebug

A tutorial should be coming this way once I’ve had time to get it figured out.

Leave a Comment :, , more...

Q&A – Something’s wrong with my output buffering!

by on Jul.14, 2009, under PHP, Zend Framework

Question:
Something’s wrong with my output buffering! I have a Zend Framework project with a long script and I’m trying to output stuff in the controller during the process but it doesn’t appear until the end. I tried using flush() and moving the code to the view but it made no difference. What is going on?

Answer:
First of all Apache on Windows doesn’t respond to flush(), it will always wait until the end of the request to output the result.

For other system though what you should know is that by default the Zend Framework front controller will buffer all output. This is normally fine and actually is quite useful, however there are some situations where you will want to bypass output buffering. In order to do this you should place the following in your bootstrap:

$frontController->setParam('disableOutputBuffering', true);

Now I like to do this only if a certain $_GET variable is sent so that I can apply it to any URL at will, however you might like to use a plugin to permanently disable output buffering for URLs that require it.

2 Comments more...

Zend Framework Performance Architecture Part 3: Denormalising Data

by on Jun.12, 2009, under Performance, PHP, Zend Framework

If you’re not already indexing your databases, head on over to http://hackmysql.com/documents and read everything there.

If you’re really looking to squeeze every last drop of performance out of your database then you can denormalise your data where otherwise you would need a join. (continue reading…)

Leave a Comment more...

Zend Framework Performance Architecture Part 2: Multiple Row Caching

by on Jun.10, 2009, under Performance, PHP, Zend Framework

In the last article I covered how to precache individual rows from a database in order to improve the performance of your application. While this is certainly useful for instances where we need just a single row, a lot of our queries are to retrieve multiple rows from the database. One of the problems with caching results from these queries is that if a single row’s details change, we need to scrap the entire cache and start again, otherwise we might display outdated information. This applies not only to the fields we are using in the query, but also fields we display to the user. (continue reading…)

Leave a Comment more...

Zend Framework Performance Architecture Part 1: Row Precaching

by on Jun.09, 2009, under Performance, PHP, Zend Framework

One quick and easy way to take a chunk out of your database usage is to precache data. When this is done effectively you can actually serve up many requests without even connecting to the database at all. One of the simplest implementations I have found involves precaching rows when they are created or updated. Essentially when the data changes you store the changed data in cache so when it is requested it can be loaded from a file instead of the database. We do this because database access is very slow compared to file access. (continue reading…)

Leave a Comment more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!