New in Symfony 2.4: A better Callback constraint

Contributed by
Bernhard Schussek
in #9133.

Sometimes, we make things more complex than they should be; the Callback constraint was such an example, and using it in Symfony 2.4 is much simpler, feels more natural, and is more powerful at the same time.

The Callback constraint is a great way to define custom validation rules without the need to create custom constraints and validator classes. You just need to create one or more methods that does the validation and generates some violations. But before 2.4, the constraint needs to be attached to the class itself instead of the validation method(s), leading to some verbose configuration (in all configuration formats):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Symfony\Component\Validator\ExecutionContextInterface;

/**
 * @Assert\Callback(methods={
 *     { "Acme\BlogBundle\MyStaticValidatorClass", "isAuthorValid"}
 * })
 */
class Author
{
    // ...

    public function isAuthorValid(ExecutionContextInterface $context)
    {
        // somehow you have an array of "fake names"
        $fakeNames = array();

        // check if the name is actually a fake name
        if (in_array($this->getFirstName(), $fakeNames)) {
            $context->addViolationAt('firstname', 'This name sounds totally fake!', array(), null);
        }
    }
}

As of Symfony 2.4, you can just annotate the method itself (the XML or YAML configuration formats are also much simpler to write):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
use Symfony\Component\Validator\ExecutionContextInterface;

class Author
{
    // ...

    /**
     * @Assert\Callback
     */
    public function isAuthorValid(ExecutionContextInterface $context)
    {
        // somehow you have an array of "fake names"
        $fakeNames = array();

        // check if the name is actually a fake name
        if (in_array($this->getFirstName(), $fakeNames)) {
            $context->addViolationAt('firstname', 'This name sounds totally fake!', array(), null);
        }
    }
}

You can now also use an external method to validate your object, in which case, the callback will get the object to validate as a first argument:

1
2
3
4
5
6
7
8
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @Assert\Callback({"Vendor\Package\Validator", "validate"})
 */
class Author
{
}

The Callback constraint documentation page gives you all the information you need to upgrade your existing code and to take advantage of the new features.

Of course, the old way still works to keep backward compatibility, but who would not want to upgrade to the new way?

Comments

could you please make it clear by turning the isAuthorValid to validate as you are changing from that to those two values? it gets confusing.

if you can annotate the method it should be just called `validate`

on the last part it should be more clear if

Vendor\Package\Validator is turned into
Acme\BlogBundle\MyStaticValidatorClass

since you introduced it early on

just some help to clarify it, as it seems it is not clear as it is right now

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.