Version

Documentation » Admin

20. Templates »

« 18. Field Types

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 :

<?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
    <!-- 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
    # 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

<?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:

// 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:

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:

protected $formOptions = array(
    'validation_groups' => array()
);

Found a typo? Something is wrong in this documentation? Just fork and edit it!