I'm currently working on a Symfony2 project which uses Sonata.
Previous developers have made modifications inside the vendors directly which is obviously a huge mistake so I'm in the process of refactoring this. I'm currently stuck with some modifications that have been made to constraint mapping from the FOSUserBundle.
The file is: /vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Resources/config/validation/orm.xml
They actually disabled the UniqueEntity constraint on the class FOS\UserBundle\Model\User
based on the field usernameCanonical
, like this:
<?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="FOS\UserBundle\Model\User">
<!-- <constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">usernameCanonical</option>
<option name="errorPath">username</option>
<option name="message">fos_user.username.already_used</option>
<option name="groups">
<value>Registration</value>
<value>Profile</value>
</option>
</constraint> -->
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">emailCanonical</option>
<option name="errorPath">email</option>
<option name="message">fos_user.email.already_used</option>
<option name="groups">
<value>Registration</value>
<value>Profile</value>
</option>
</constraint>
</class>
</constraint-mapping>
How can I reproduce this change in the overriden FOSUserBundle, or the overriden SonataUserBundle ?
As much as the answer from @Nico pointed me to the right direction, here is the complete setup I've had to do in order to integrate it into the SonataUserBundle and have my custom validation groups taken into account.
As a matter of fact, it seemed that my custom orm.xml
file was not loaded. So after changing the validation groups, no more validation occurred at all.
orm.xml
In Application\Sonata\UserBundle\Resources\config\validation\
:
<?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="FOS\UserBundle\Model\User">
<!-- <constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">usernameCanonical</option>
<option name="errorPath">username</option>
<option name="message">fos_user.username.already_used</option>
<option name="groups">
<value>Registration</value>
<value>Profile</value>
</option>
</constraint> -->
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">emailCanonical</option>
<option name="errorPath">email</option>
<option name="message">fos_user.email.already_used</option>
<option name="groups">
<value>CustomRegistration</value>
<value>CustomProfile</value>
</option>
</constraint>
</class>
</constraint-mapping>
To use the custom validation groups (I've stripped down the non-relevant configuration lines):
app/config/fos/fos_user.yml:
fos_user:
registration:
form:
validation_groups:
- CustomRegistration
profile:
form:
validation_groups:
- CustomProfile
app/config/sonata/sonata_user.yml:
sonata_user:
profile:
form:
validation_groups:
- CustomProfile
Add Application\Sonata\UserBundle\DependencyInjection\Compiler\ValidationPass.php class. This is based on the original class from FOSUserBundle:
class ValidationPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter('fos_user.storage')) {
return;
}
$storage = $container->getParameter('fos_user.storage');
if ('custom' === $storage) {
return;
}
$validationFile = __DIR__ . '/../../Resources/config/validation/' . $storage . '.xml';
if ($container->hasDefinition('validator.builder')) {
// Symfony 2.5+
$container->getDefinition('validator.builder')
->addMethodCall('addXmlMapping', array($validationFile));
return;
}
}
}
Edit Application\Sonata\UserBundle\ApplicationSonataUserBundle:
class ApplicationSonataUserBundle extends Bundle
{
/**
* {@inheritdoc}
*/
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ValidationPass());
}
}
/**
* {@inheritdoc}
*/
public function getFormBuilder()
{
$this->formOptions['data_class'] = $this->getClass();
$options = $this->formOptions;
$options['validation_groups'] =
(!$this->getSubject() || is_null($this->getSubject()->getId())) ? 'CustomRegistration' : 'CustomProfile';
$formBuilder = $this->getFormContractor()->getFormBuilder( $this->getUniqid(), $options);
$this->defineFormBuilder($formBuilder);
return $formBuilder;
}
I don't know if there was a simpler way to achieve this. Nevertheless, it works for me.