Cover of the book Symfony 5: The Fast Track

Symfony 5: The Fast Track is the best book to learn modern Symfony development, from zero to production. +300 pages showcasing Symfony with Docker, APIs, queues & async tasks, Webpack, SPAs, etc.

WARNING: You are browsing the documentation for version 2.x which is not maintained anymore. If some of your projects are still using this version, consider upgrading.

19. Inline Validation

2.x version
Maintained Unmaintained
2.x

19. Inline Validation

The inline validation is about delegating model validation to a dedicated service. The current validation implementation built in the Symfony2 framework is very powerful as it allows to declare validation on a : class, field and getter. However these declarations can take a while to code for complex rules. As rules must be a set of a Constraint and a Validator instances.

The inline validation tries to provide a nice solution by introducing an ErrorElement object. The object can be used to check assertions against the model :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
$errorElement
    ->with('settings.url')
        ->assertNotNull(array())
        ->assertNotBlank()
    ->end()
    ->with('settings.title')
        ->assertNotNull(array())
        ->assertNotBlank()
        // for minimum length constraint
        ->assertLength(array('min' => 50))
        // for maximum length constraint
        ->assertLength(array('max' => 100))
        ->addViolation('ho yeah!')
    ->end();

if (/* complex rules */) {
    $errorElement->with('value')->addViolation('Fail to check the complex rules')->end()
}

/* conditional validation */
if ($this->getSubject()->getState() == Post::STATUS_ONLINE) {
    $errorElement
        ->with('enabled')
            ->assertNotNull()
            ->assertTrue()
        ->end();
}

Note

This solution relies on the validator component so validation defined through the validator component will be used.

Tip

You can also use $errorElement->addConstraint(new \Symfony\Component\Validator\Constraints\NotBlank()) instead of calling assertNotBlank().

You can also use $errorElement->addConstraint(new \Symfony\Component\Validator\Constraints\Length(array('min'=>5, 'max'=>100)) instead of calling assertLength().

19.1. Using this validator

Add the InlineConstraint class constraint to your bundle’s validation configuration, for example:

  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- src/Application/Sonata/PageBundle/Resources/config/validation.xml -->
    <?xml version="1.0" ?>
    <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
    
        <class name="Application\Sonata\PageBundle\Entity\Block">
            <constraint name="Sonata\AdminBundle\Validator\Constraints\InlineConstraint">
                <option name="service">sonata.page.cms.page</option>
                <option name="method">validateBlock</option>
            </constraint>
        </class>
    </constraint-mapping>
    
  • YAML
    1
    2
    3
    4
    5
    6
    # src/Application/Sonata/PageBundle/Resources/config/validation.yml
    Application\Sonata\PageBundle\Entity\Block:
        constraints:
            - Sonata\AdminBundle\Validator\Constraints\InlineConstraint:
                service: sonata.page.cms.page
                method: validateBlock
    

There are two important options:

  • service: the service where the validation method is defined
  • method: the service’s method to call

The method must accept two arguments:

  • ErrorElement: the instance where assertion can be checked
  • value: the object instance

19.2. Example from the SonataPageBundle

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
namespace Sonata\PageBundle\Block;

use Sonata\PageBundle\Model\PageInterface;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\BlockBundle\Block\BaseBlockService;
use Sonata\BlockBundle\Model\BlockInterface;

class RssBlockService extends BaseBlockService
{
    // ... code removed for simplification

    public function validateBlock(ErrorElement $errorElement, BlockInterface $block)
    {
        $errorElement
            ->with('settings.url')
                ->assertNotNull(array())
                ->assertNotBlank()
            ->end()
            ->with('settings.title')
                ->assertNotNull(array())
                ->assertNotBlank()
                // for minimum length constraint
                ->assertLength(array('min' => 50))
                // for maximum length constraint
                ->assertLength(array('max' => 100))
                ->addViolation('ho yeah!')
            ->end();
    }
}

19.3. Using the Admin class

This feature is deprecated and will be removed on the 2.2 branch.

The above examples show how to delegate validation to a service. For completeness, it’s worth remembering that the Admin class itself contains an empty validate method. This is automatically called, so you can override it in your own admin class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// add this to your existing use statements
use Sonata\AdminBundle\Validator\ErrorElement;

class MyAdmin extends Admin
{
    // add this method
    public function validate(ErrorElement $errorElement, $object)
    {
        $errorElement
            ->with('name')
                ->assertLength(array('max' => 32))
            ->end()
        ;
    }

19.4. Troubleshooting

Make sure your validator method is being called. If in doubt, try throwing an exception:

1
2
3
4
public function validate(ErrorElement $errorElement, $object)
{
    throw new \Exception(__METHOD__);
}

There should not be any validation_groups defined for the form. If you have code like the example below in your Admin class, remove the ‘validation_groups’ entry, the whole $formOptions property or set validation_groups to an empty array:

1
2
3
protected $formOptions = array(
    'validation_groups' => array()
);

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.