Forms - advanced
Sometimes you might have more complex requirements for your Forms. You might already be aware that Mautic builds upon the Symfony framework, so there’s lots of Form-related features available to you. You can read more about this here: Symfony 4 form classes. This section highlights a few complex but common use cases:
Custom Form Types that deviate from Symfony’s wide array of standard Form types, like text fields, choice fields, etc.
Data sanitizing
Dynamic Form modification
Data validation
Custom Form types
As stated in Symfony’s documentation as referenced in the preceding section, Form type classes are the best way to go. Mautic makes it easy to register Form type services through the bundle’s config file. Refer to the Service config items section.
Data sanitizing
Form data isn’t automatically sanitized. Mautic provides a Form event subscriber to handle this.
In your Form type class, register the Mautic\CoreBundle\Form\EventListener\CleanFormSubscriber
event subscriber.
The array provided to CleanFormSubscriber
should contain the names of the Form Fields as keys and the values the masks to use to sanitize the data. Any unspecified Form Field uses the clean
mask by default.
<?php
// plugins/HelloWorldBundle/Form/Type/WorldType.php
declare(strict_types=1);
namespace MauticPlugin\HelloWorldBundle\Form\Type;
use Mautic\CoreBundle\Form\EventListener\CleanFormSubscriber;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class WorldType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber(
new CleanFormSubscriber(
[
'content' => 'html',
'customHtml' => 'html'
]
)
);
}
}
Dynamic Form modification
If you need to manipulate a Form based on submitted data, use a Form event listener. This is useful in cases like changing defined fields, adjust constraints, or changing select choices based on submitted values. Refer to Symfony’s documentation on this: Symfony 4 dynamic form modification
Data validation
Review Symfony’s Form validation documentation for a general overview: Symfony 4 form validation
There are two common means of validating Form data.
Using entity static callback
If the underlying data of a Form is an Entity object you can define a static method loadValidatorMetadata
in the Entity class.
This automatically gets called when Symfony is processing Form data.
A Form can also use validation_groups to change the order of data to validate or only validate if certain criteria is true. For example, only validate a password confirmation field if the first password field passes validation. When registering a validation group in the Form type class, you can use a static callback to determine what validation groups Symfony should use.
<?php
// plugins/HelloWorldBundle/Form/Type/WorldType.php
declare(strict_types=1);
namespace MauticPlugin\HelloWorldBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Mapping\ClassMetadata;
class WorldType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MauticPlugin\HelloWorld\Entity\World',
'validation_groups' => array(
'MauticPlugin\HelloWorld\Entity\World',
'determineValidationGroups',
)
));
}
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
$metadata->addPropertyConstraint(
'name',
new NotBlank(
array(
'message' => 'mautic.core.name.required'
)
)
);
$metadata->addPropertyConstraint(
'population',
new NotBlank(
array(
'message' => 'mautic.core.value.required',
'groups' => array('VisitedWorld')
)
)
);
}
public static function determineValidationGroups(Form $form)
{
$data = $form->getData();
$groups = array('AllWorlds');
if (!$data->getId() || ($data->getId() && $data->getVisitCount() > 0)) {
$groups[] = 'VisitedWorld';
}
return $groups;
}
}
Using constraints
A Form type service can also register Constraints when defining the Form Fields.
<?php
// plugins/HelloWorldBundle/Form/Type/WorldType.php
declare(strict_types=1);
namespace MauticPlugin\HelloWorldBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
class WorldType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'name',
'text',
array(
'label' => 'mautic.core.name',
'label_attr' => array('class' => 'control-label'),
'attr' => array(
'class' => 'form-control'
),
'constraints' => array(
new NotBlank(
array(
'message' => 'mautic.core.value.required'
)
)
)
)
);
}
}