ParsleyBundle
, (*1)
Convert Symfony constraints into data-attributes for client-side validation with Parsley., (*2)
Installation
Install the bundle with composer:, (*3)
composer require j-ben87/parsley-bundle
Install Parsley library: http://parsleyjs.org/doc/index.html#installation, (*4)
Configuration
The bundle exposes a basic configuration:, (*5)
jben87_parsley:
enabled: true # enable/disable Parsley validation globally (can be enabled on FormType or Constraint level)
trigger_event: 'blur' # the JavaScript event for which the validation is to be triggered (relative to the selected input)
Usage
Create a FormType
., (*6)
Any supported constraints you have defined on your form will automatically be turned into Parsley data-attributes., (*7)
Yes, it's that simple!, (*8)
<?php
declare(strict_types=1);
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
final class CustomType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title', TextType::class, [
'constraints' => [
new Assert\NotBlank(),
new Assert\Length(30),
],
])
->add('content', TextareaType::class, [
'constraints' => [
new Assert\NotBlank(),
],
])
;
}
}
Results in:, (*9)
<input type="text" id="title" name="title" required="required" data-parsley-trigger="blur" data-parsley-required="true" data-parsley-required-message="This value should not be blank." data-parsley-length="[30, 30]" data-parsley-length-message="This value should have exactly 30 characters.">
<textarea id="content" name="content" required="required" data-parsley-trigger="blur" data-parsley-required="true" data-parsley-required-message="This value should not be blank."></textarea>
data-class
constraints
Create a FormType
and configure its data-class
option., (*10)
Any supported constraint you have defined on your class will automatically be turned into Parsley data-attributes., (*11)
Here again, it's incredibly simple!, (*12)
<?php
declare(strict_types=1);
namespace App\Model;
use Symfony\Component\Validator\Constraints as Assert;
final class User
{
/**
* @Assert\NotBlank()
* @Assert\Length(max=255)
*/
private ?string $username = null;
/**
* @Assert\NotBlank()
* @Assert\Length(max=255)
* @Assert\Email()
*/
private ?string $email = null;
}
And, (*13)
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\Model\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('username')
->add('email')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefault('data_class', User::class);
}
}
Results in:, (*14)
{% {{ form_widget(form.username) }} %}
<input type="text" id="username" name="username" required="required" maxlength="255" data-parsley-trigger="blur" data-parsley-required="true" data-parsley-required-message="This value should not be blank." data-parsley-maxlength="255" data-parsley-maxlength-message="This value is too long. It should have 255 characters or less.">
{% {{ form_widget(form.email }} %}
<input type="email" id="email" name="email" required="required" maxlength="255" data-parsley-trigger="blur" data-parsley-required="true" data-parsley-required-message="This value should not be blank." data-parsley-maxlength="255" data-parsley-maxlength-message="This value is too long. It should have 255 characters or less." data-parsley-type="email" data-parsley-type-message="This value is not a valid email address.">
Notice: if you define the same constraint on both the FormType
and the configured data-class
, the FormType
constraint will override the one configured on the data-class
., (*15)
Internals
The ParsleyTypeExtension
is where all the magic happens., (*16)
It gathers all Symfony constraints thanks to registered readers and turn them into Parsley constraints through factories., (*17)
It uses the special ChainFactory
to automatically find the first factory that supports the given Symfony constraint., (*18)
Finally it normalizes the Parsley constraint into data-attributes and merge them with the FormView
attributes., (*19)
Extending the bundle
You can easily add more constraints by:, (*20)
- creating a constraint that extends the abstract class
JBen87\ParsleyBundle\Constraint\Constraint
- creating a factory that implements the interface
JBen87\ParsleyBundle\Constraint\Factory\FactoryInterface
Your factory will be automatically registered to be used by the ChainFactory
service., (*21)
<?php
declare(strict_types=1);
namespace App\Constraint\Constraints;
use JBen87\ParsleyBundle\Constraint\Constraint;
final class Valid extends Constraint
{
protected function getAttribute(): string
{
return 'data-parsley-valid';
}
protected function getValue(): string
{
return 'true';
}
}
<?php
declare(strict_types=1);
namespace App\Constraint\Factory;
use App\Constraint\Constraints as ParsleyAssert;
use JBen87\ParsleyBundle\Constraint\Constraint;
use JBen87\ParsleyBundle\Constraint\Factory\FactoryTrait;
use JBen87\ParsleyBundle\Constraint\Factory\TranslatableFactoryInterface;
use Symfony\Component\Validator\Constraint as SymfonyConstraint;
use Symfony\Component\Validator\Constraints as Assert;
final class ValidFactory implements TranslatableFactoryInterface
{
use FactoryTrait;
public function create(SymfonyConstraint $constraint): Constraint
{
/** @var Assert\Valid $constraint */
return new ParsleyAssert\Valid([
'message' => $this->trans($constraint->message),
]);
}
public function supports(SymfonyConstraint $constraint): bool
{
return $constraint instanceof Assert\Valid;
}
}
Supported constraints
The following Symfony constraints are currently supported:, (*22)
- Symfony\Component\Validator\Constraints\Date
- Symfony\Component\Validator\Constraints\DateTime
- Symfony\Component\Validator\Constraints\Email
- Symfony\Component\Validator\Constraints\GreaterThan
- Symfony\Component\Validator\Constraints\GreaterThanOrEqual
- Symfony\Component\Validator\Constraints\Length
- Symfony\Component\Validator\Constraints\LessThan
- Symfony\Component\Validator\Constraints\LessThanOrEqual
- Symfony\Component\Validator\Constraints\NotBlank
- Symfony\Component\Validator\Constraints\Range
- Symfony\Component\Validator\Constraints\Time
- Symfony\Component\Validator\Constraints\Type
- Symfony\Component\Validator\Constraints\Url
What's next
- Support more constraints
- Support group validation