Skip to content
Browse files

Dispatch events before and after processing constraints of a form + M…

…anage validation groups with an event listener + Manage repeated field
  • Loading branch information...
1 parent 29aae63 commit 36d531791feb802a6948085ee2d47a5c9d6023e8 @Abhoryo committed Dec 5, 2011
View
11 ChangeLog.md
@@ -0,0 +1,11 @@
+#2011-12-05
+- Dispatch events before and after processing constraints of a form
+- Manage validation groups with an event listener
+- Manage repeated field
+
+#2011-12-01
+- New assets warmer system. Now, define routes in configuraiton instead of a list of parameters
+- fix isIPv6_no_res function in IpValidator
+
+#2011-11-29
+- Search for the first parent form
View
2 Contributors.md
@@ -0,0 +1,2 @@
+Abhoryo (Abhoryo)
+guillaumepotier (Guillaume Potier)
View
6 Form/Extension/FieldTypeExtension.php → Form/Extension/FormTypeExtension.php
@@ -15,18 +15,18 @@
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
-class FieldTypeExtension extends AbstractTypeExtension
+class FormTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
- return 'field';
+ return 'form';
}
public function buildView(FormView $view, FormInterface $form)
{
// Add validation groups to the view
if ($form->hasAttribute('validation_groups')) {
- $view->set('validation_groups' , $form->getAttribute('validation_groups'));
+ $view->set('validation_groups', $form->getAttribute('validation_groups'));
}
}
}
View
30 Form/Extension/RepeatedTypeExtension.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Form\Extension;
+
+use Symfony\Component\Form\AbstractTypeExtension;
+use Symfony\Component\Form\FormInterface;
+use Symfony\Component\Form\FormView;
+
+class RepeatedTypeExtension extends AbstractTypeExtension
+{
+ public function getExtendedType()
+ {
+ return 'repeated';
+ }
+
+ public function buildView(FormView $view, FormInterface $form)
+ {
+ $view->set('invalid_message', $form->getAttribute('invalid_message'));
+ $view->set('invalid_message_parameters', $form->getAttribute('invalid_message_parameters'));
+ }
+}
View
55 Generator/FieldsConstraints.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Generator;
+
+class FieldsConstraints {
+ public $constraints;
+ public $libraries;
+
+ public function getFieldsConstraints() {
+ return $this->constraints;
+ }
+
+ public function hasFieldConstraints($fieldName) {
+ return isset($this->constraints[$fieldName]) && !empty($this->constraints[$fieldName]);
+ }
+
+ public function getFieldConstraints($fieldName) {
+ return $this->constraints[$fieldName];
+ }
+
+ public function setFieldConstraints($fieldName, $constraints) {
+ $this->constraints[$fieldName] = $constraints;
+
+ return $this;
+ }
+
+ public function addFieldConstraint($fieldName, $constraint) {
+ $this->constraints[$fieldName][] = $constraint;
+
+ return $this;
+ }
+
+ public function getLibraries() {
+ return $this->libraries;
+ }
+
+ public function addLibrary($contraintName, $libraryScript) {
+ $this->libraries[$contraintName] = $libraryScript;
+
+ return $this;
+ }
+
+ public function hasLibrary($contraintName) {
+ return isset($this->libraries[$contraintName]) && !empty($this->libraries[$contraintName]);
+ }
+}
View
115 Generator/FormValidationScriptGenerator.php
@@ -11,13 +11,14 @@
namespace APY\JsFormValidationBundle\Generator;
+use APY\JsFormValidationBundle\JsfvEvents;
+
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\FormView;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
-use Symfony\Component\Validator\Constraints;
use Assetic\AssetWriter;
use Assetic\AssetManager;
@@ -36,94 +37,82 @@ public function __construct(ContainerInterface $container)
public function generate(FormView $formView, $overwrite = false)
{
- // retrieve parameters from the form
- $entityName = get_class($formView->get('value'));
- $formName = $formView->get('name');
- $formValidationGroups = $formView->get('validation_groups', array('Default'));
- $formFields = array_keys($formView->getChildren());
-
// Prepare output file
$scriptPath = $this->container->getParameter('apy_js_form_validation.script_directory');
$scriptRealPath = $this->container->getParameter('assetic.write_to').$scriptPath;
-
- if ( ! is_dir($scriptRealPath) ) {
- mkdir($scriptRealPath, 0777, true);
- }
-
- $route = $this->container->get('request')->get('_route');
- $scriptFile = strtolower($route).".js";
+ $scriptFile = strtolower($this->container->get('request')->get('_route')).".js";
if ( $overwrite || false === file_exists($scriptRealPath.$scriptFile) ) {
-
+ // Retrieve entityName from the form
+ $entityName = get_class($formView->get('value'));
+
+ // Load metadata
$metadata = new ClassMetadata($entityName);
- // annotations constraints
+ // from annotations
$annotationloader = new AnnotationLoader(new AnnotationReader());
$annotationloader->loadClassMetadata($metadata);
- // php constraints
+ // from php
// $entity = new $entityName();
// $entity->loadValidatorMetadata($metadata);
- // yml constraints
+ // from yml
+
+ // from xml
- // xml constraints
+ // Dispatch JsfvEvents::preProcess event
+ $dispatcher = $this->container->get('event_dispatcher');
+ $preProcessEvent = new PreProcessEvent($formView, $metadata);
+ $dispatcher->dispatch(JsfvEvents::preProcess, $preProcessEvent);
- $librairyCalls = array();
- $javascriptCalls = array();
- $constraints = array();
+ $fieldsConstraints = new FieldsConstraints();
// we look through each field of the form
- foreach ($formFields as $fieldName) {
+ foreach ($formView->getChildren() as $formField) {
// we look for constraints for the field
- if (in_array($fieldName, array_keys($metadata->properties))) {
+ if (isset($metadata->properties[$formField->get('name')])) {
// we look through each field constraint
- foreach ($metadata->properties[$fieldName]->getConstraints() as $contraint) {
+ foreach ($metadata->properties[$formField->get('name')]->getConstraints() as $contraint) {
$contraintName = end((explode(chr(92), get_class($contraint))));
- $contraintParameters = get_object_vars($contraint);
-
- // Check validation groups
- foreach ($contraintParameters['groups'] as $validationGroup) {
- if (in_array($validationGroup, $formValidationGroups)) {
- // Groups are no longer needed
- unset($contraintParameters['groups']);
+ $contraintProperties = get_object_vars($contraint);
- $librairies = "APYJsFormValidationBundle:Constraints:{$contraintName}Validator.js.twig";
+ // Groups are no longer needed
+ unset($contraintProperties['groups']);
- if (!isset($librairyCalls[$contraintName])) {
- $librairyCalls[$contraintName] = $librairies;
- }
+ if (!$fieldsConstraints->hasLibrary($contraintName)) {
+ $librairy = "APYJsFormValidationBundle:Constraints:{$contraintName}Validator.js.twig";
+ $fieldsConstraints->addLibrary($contraintName, $librairy);
+ }
- $javascriptConstraintParameters = array();
- foreach ($contraintParameters as $variable => $value) {
- if (is_array($value)) {
- $value = json_encode($value);
- }
- else {
- // regex
- if (stristr('pattern', $variable) === false) {
- $value = "'".$value."'";
- }
- }
-
- $javascriptConstraintParameters[] = "$variable:$value";
+ $constraintParameters = array();
+ foreach ($contraintProperties as $variable => $value) {
+ if (is_array($value)) {
+ $value = json_encode($value);
+ }
+ else {
+ // regex
+ if (stristr('pattern', $variable) === false) {
+ $value = "'".$value."'";
}
-
- $javascriptConstraintParameters = '{'.join(', ',$javascriptConstraintParameters).'}';
-
- $constraints[$formName."_".$fieldName][] = array(
- 'name' => $contraintName,
- 'parameters' => $javascriptConstraintParameters
- );
-
- break;
}
+
+ $constraintParameters[] = "$variable:$value";
}
+
+ $fieldsConstraints->addFieldConstraint($formField->get('id'), array(
+ 'name' => $contraintName,
+ 'parameters' => '{'.join(', ',$constraintParameters).'}'
+ ));
}
}
}
+ // Dispatch JsfvEvents::postProcess event
+ $postProcessEvent = new PostProcessEvent($formView, $fieldsConstraints);
+ $dispatcher->dispatch(JsfvEvents::postProcess, $postProcessEvent);
+
// Retrieve validation mode from configuration
$check_modes = array('submit' => false, 'blur' => false);
switch($this->container->getParameter('apy_js_form_validation.check_mode')) {
@@ -143,9 +132,9 @@ public function generate(FormView $formView, $overwrite = false)
$validation_bundle = $this->container->getParameter('apy_js_form_validation.validation_bundle');
$template = $this->container->get('templating')->render($validation_bundle.'::JsFormValidation.js.twig',
array(
- 'formName'=>$formName,
- 'fieldConstraints'=>$constraints,
- 'librairyCalls'=>$librairyCalls,
+ 'formName'=>$formView->get('name'),
+ 'fieldConstraints'=>$fieldsConstraints->getFieldsConstraints(),
+ 'librairyCalls'=>$fieldsConstraints->getLibraries(),
'check_modes'=>$check_modes
)
);
@@ -161,6 +150,10 @@ public function generate(FormView $formView, $overwrite = false)
$yui->filterDump($asset);
}
+ if ( ! is_dir($scriptRealPath) ) {
+ mkdir($scriptRealPath, 0777, true);
+ }
+
if (false === @file_put_contents($asset->getTargetPath(), $asset->getContent())) {
throw new \RuntimeException('Unable to write file '.$asset->getTargetPath());
}
View
43 Generator/PostProcessEvent.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Generator;
+
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\Form\FormView;
+
+class PostProcessEvent extends Event
+{
+ private $formView;
+ private $fieldsConstraints;
+
+ public function __construct(FormView $formView, FieldsConstraints $fieldsConstraints)
+ {
+ $this->formView = $formView;
+ $this->fieldsConstraints = $fieldsConstraints;
+ }
+
+ /**
+ * @return FormView
+ */
+ public function getFormView()
+ {
+ return $this->formView;
+ }
+
+ /**
+ * @return FieldsConstraints
+ */
+ public function getFieldsConstraints()
+ {
+ return $this->fieldsConstraints;
+ }
+}
View
44 Generator/PreProcessEvent.php
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Generator;
+
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\Form\FormView;
+use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+class PreProcessEvent extends Event
+{
+ private $formView;
+ private $metadata;
+
+ public function __construct(FormView $formView, ClassMetadata $metadata)
+ {
+ $this->formView = $formView;
+ $this->metadata = $metadata;
+ }
+
+ /**
+ * @return FormView
+ */
+ public function getFormView()
+ {
+ return $this->formView;
+ }
+
+ /**
+ * @return ClassMetadata
+ */
+ public function getMetaData()
+ {
+ return $this->metadata;
+ }
+}
View
35 JsfvEvents.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle;
+
+final class JsfvEvents
+{
+ /**
+ * The jsfv.pre_process event is thrown before creating constraints
+ * from metadata of a from's fields.
+ * The event listener receives an
+ * APY\JsFormValidationBundle\Generator\PreProcessEvent instance.
+ *
+ * @var string
+ */
+ const preProcess = 'jsfv.pre_process';
+
+ /**
+ * The jsfv.post_process event is thrown after creating constraints
+ * from metadata of a from's fields.
+ * The event listener receives an
+ * APY\JsFormValidationBundle\Generator\PostProcessEvent instance.
+ *
+ * @var string
+ */
+ const postProcess = 'jsfv.post_process';
+}
View
58 Listener/RepeatedFieldListener.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Listener;
+
+use APY\JsFormValidationBundle\Generator\PostProcessEvent;
+use Symfony\Component\Form\FormView;
+
+class RepeatedFieldListener
+{
+ public function onJsfvPostProcess(PostProcessEvent $event)
+ {
+ $formFields = $event->getFormView()->getChildren();
+ $fieldsConstraints = $event->getFieldsConstraints();
+
+ foreach ($formFields as $formField) {
+ if (in_array('repeated', $formField->get('types'))) {
+ $formFieldId = $formField->get('id');
+
+ // Get the real fields name of the repeated type form
+ $repeatedNames = array_keys($formField->get('value'));
+ $formFieldId_first = $formFieldId.'_'.$repeatedNames[0];
+ $formFieldId_second = $formFieldId.'_'.$repeatedNames[1];
+
+ // Rename the original field constraints
+ if ($fieldsConstraints->hasFieldConstraints($formFieldId)) {
+ $fieldsConstraints->setFieldConstraints($formFieldId_first, $fieldsConstraints->getFieldConstraints($formFieldId));
+ unset($fieldsConstraints->constraints[$formFieldId]);
+ }
+
+ // Add a special Repeat constraint for repeated field
+ if (!$fieldsConstraints->hasLibrary('Repeated')) {
+ $fieldsConstraints->addLibrary('Repeated', "APYJsFormValidationBundle:Constraints:RepeatedValidator.js.twig");
+ }
+
+ // Get invalid message from the form
+ $invalid_message = $formField->get('invalid_message');
+ foreach ($formField->get('invalid_message_parameters') as $invalid_message_parameter => $value){
+ $invalid_message = str_replace($invalid_message_parameter,'{{ '.$invalid_message_parameter.' }}',$invalid_message);
+ }
+ $invalid_message_parameters = json_encode($formField->get('invalid_message_parameters'));
+
+ $fieldsConstraints->addFieldConstraint($formFieldId_second, array(
+ 'name' => 'Repeated',
+ 'parameters' => "{first_name: '$formFieldId_first', second_name: '$formFieldId_second', invalid_message: '$invalid_message', invalid_message_parameters: $invalid_message_parameters}"
+ ));
+ }
+ }
+ }
+}
View
46 Listener/ValidationGroupsListener.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the JsFormValidationBundle.
+ *
+ * (c) Abhoryo <abhoryo@free.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace APY\JsFormValidationBundle\Listener;
+
+use APY\JsFormValidationBundle\Generator\PreProcessEvent;
+use Symfony\Component\Form\FormView;
+use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+class ValidationGroupsListener
+{
+ public function onJsfvPreProcess(PreProcessEvent $event)
+ {
+ $formView = $event->getFormView();
+ $formValidationGroups = $formView->get('validation_groups', array('Default'));
+
+ $formFields = array_keys($formView->getChildren());
+ $metadata = $event->getMetaData();
+
+ foreach ($formFields as $fieldName) {
+ if (isset($metadata->properties[$fieldName])) {
+ foreach ($metadata->properties[$fieldName]->constraints as $key => $contraint) {
+ $contraintParameters = get_object_vars($contraint);
+
+ // Check validation groups for each contraint of each property
+ foreach ($contraintParameters['groups'] as $validationGroup) {
+ if (in_array($validationGroup, $formValidationGroups)) {
+ continue 2;
+ }
+ }
+
+ // Unset constraint which is not in the validation groups
+ unset($metadata->properties[$fieldName]->constraints[$key]);
+ }
+ }
+ }
+ }
+}
View
27 Resources/config/services.yml
@@ -3,17 +3,30 @@ services:
class: APY\JsFormValidationBundle\Twig\Extension\JsFormValidationTwigExtension
tags:
- { name: twig.extension }
- arguments:
- - @service_container
-
+ arguments: [ @service_container ]
+
kernel.cache_warmer.jsformvalidation:
class: APY\JsFormValidationBundle\CacheWarmer\JsFormValidationCacheWarmer
tags:
- { name: kernel.cache_warmer }
- arguments:
- - @service_container
+ arguments: [ @service_container ]
form.type_extension.validation_groups:
- class: APY\JsFormValidationBundle\Form\Extension\FieldTypeExtension
+ class: APY\JsFormValidationBundle\Form\Extension\FormTypeExtension
+ tags:
+ - { name: form.type_extension, alias: form }
+
+ form.type_extension.repeated_parameters:
+ class: APY\JsFormValidationBundle\Form\Extension\RepeatedTypeExtension
+ tags:
+ - { name: form.type_extension, alias: repeated }
+
+ jsfv.validation_groups_listener:
+ class: APY\JsFormValidationBundle\Listener\ValidationGroupsListener
+ tags:
+ - { name: kernel.event_listener, event: jsfv.pre_process, method: onJsfvPreProcess }
+
+ jsfv.repeated_field_listener:
+ class: APY\JsFormValidationBundle\Listener\RepeatedFieldListener
tags:
- - { name: form.type_extension, alias: field }
+ - { name: kernel.event_listener, event: jsfv.post_process, method: onJsfvPostProcess }
View
11 Resources/views/Constraints/RepeatedValidator.js.twig
@@ -0,0 +1,11 @@
+function Repeated(value, params)
+{
+ first = document.getElementById(params.first_name).value;
+ second = document.getElementById(params.second_name).value;
+
+ if (first !== second) {
+ return getComputeMessage(params.invalid_message, params.invalid_message_parameters);
+ }
+
+ return true;
+}

0 comments on commit 36d5317

Please sign in to comment.
Something went wrong with that request. Please try again.