Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed bug. UniqueEntity identifier value should not be persisted in c…

…ache.
  • Loading branch information...
commit 72eab3d85f0c0ce5f4deb8a2980626005dbce8c5 1 parent 932aa07
@recipe recipe authored
View
1  Controller/Controller.php
@@ -72,6 +72,7 @@ public function uniqueEntityAction()
$value = $request->request->get('value');
$target = $request->request->get('target');
$ignore = $request->request->get('ignore');
+ $ignore = empty($ignore) ? null : json_decode($ignore, true);
$a = new \stdClass();
try {
if (!empty($target) && !empty($entity) && $this->hasUniqueEntityConstraint($entity, $target)) {
View
2  DependencyInjection/APYJsFormValidationExtension.php
@@ -32,6 +32,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('apy_js_form_validation.validation_bundle', $config['validation_bundle']);
$container->setParameter('apy_js_form_validation.javascript_framework', $config['javascript_framework']);
$container->setParameter('apy_js_form_validation.warmer_routes', $config['warmer_routes']);
+ $container->setParameter('apy_js_form_validation.identifier_field', $config['identifier_field']);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
@@ -60,6 +61,7 @@ private function getConfigTree()
->canBeUnset()
->prototype('scalar')->end()
->end()
+ ->scalarNode('identifier_field')->defaultValue('jsfv_identifier')->end()
->end()
->end()
->buildTree();
View
90 EventListener/AddIdentifierSubscriber.php
@@ -0,0 +1,90 @@
+<?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\EventListener;
+
+use APY\JsFormValidationBundle\Generator\FormValidationScriptGenerator;
+use APY\JsFormValidationBundle\Generator\PostProcessEvent;
+use Symfony\Component\Form\Event\DataEvent;
+use Symfony\Component\Form\FormFactoryInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Form\FormEvents;
+
+/**
+ * APY\JsFormValidationBundle\EventListener\AddIdentifierSubscriber
+ *
+ * @author Vitaliy Demidov <zend@i.ua>
+ * @since 05 Aug 2012
+ */
+class AddIdentifierSubscriber implements EventSubscriberInterface
+{
+
+ /**
+ * @var FormFactoryInterface
+ */
+ protected $factory;
+
+ /**
+ * @var FormValidationScriptGenerator
+ */
+ protected $jsfv;
+
+ /**
+ * Constructor
+ * @param FormFactoryInterface $factory
+ */
+ public function __construct(FormFactoryInterface $factory, FormValidationScriptGenerator $jsfv)
+ {
+ $this->factory = $factory;
+ $this->jsfv = $jsfv;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents()
+ {
+ return array(FormEvents::PRE_SET_DATA => 'preSetData');
+ }
+
+ /**
+ * Insert entity identifier hidden field into form.
+ *
+ * This field is required in order to UniqueEntity constraint worked
+ * properly on client side with update operation.
+ *
+ * @param DataEvent $event
+ */
+ public function preSetData(DataEvent $event)
+ {
+ $data = $event->getData();
+ $form = $event->getForm();
+
+ // This if statement let's us skip right over the null condition.
+ if (null === $data || !is_object($data)) {
+ return;
+ }
+
+ if ($form->getConfig()->getOption('compound') && $this->jsfv->hasUniqueEntityConstraint(get_class($data))) {
+ //When entity is updated UniqueEntity constraint should ignore
+ //entity with the same primary key id
+ $identifierField = $this->jsfv->getParameter('identifier_field');
+ $form->add($this->factory->createNamed(
+ $identifierField,
+ 'hidden',
+ json_encode($this->jsfv->getEntityIdentifierValue($data)),
+ array(
+ 'property_path' => false,
+ )
+ ));
+ }
+ }
+}
View
41 Form/Extension/FormTypeExtension.php
@@ -1,6 +1,6 @@
<?php
-/*
+/**
* This file is part of the JsFormValidationBundle.
*
* (c) Abhoryo <abhoryo@free.fr>
@@ -11,6 +11,9 @@
namespace APY\JsFormValidationBundle\Form\Extension;
+use APY\JsFormValidationBundle\Generator\FormValidationScriptGenerator;
+use APY\JsFormValidationBundle\EventListener\AddIdentifierSubscriber;
+use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
@@ -18,6 +21,31 @@
class FormTypeExtension extends AbstractTypeExtension
{
/**
+ * @var FormValidationScriptGenerator
+ */
+ protected $jsfv;
+
+ /**
+ * Sets javascript form validation script generator service.
+ *
+ * @param FormValidationScriptGenerator $jsfv
+ */
+ public function setJsfv(FormValidationScriptGenerator $jsfv)
+ {
+ $this->jsfv = $jsfv;
+ }
+
+ /**
+ * Gets javascript form validation script generator service.
+ *
+ * @return FormValidationScriptGenerator Returns javascript form validation script generator service
+ */
+ public function getJsfv()
+ {
+ return $this->jsfv;
+ }
+
+ /**
* {@inheritdoc}
*
* @see Symfony\Component\Form.FormTypeExtensionInterface::getExtendedType()
@@ -30,6 +58,17 @@ public function getExtendedType()
/**
* {@inheritdoc}
*
+ * @see Symfony\Component\Form.AbstractTypeExtension::buildForm()
+ */
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $subscriber = new AddIdentifierSubscriber($builder->getFormFactory(), $this->getJsfv());
+ $builder->addEventSubscriber($subscriber);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
* @see Symfony\Component\Form.AbstractTypeExtension::buildView()
*/
public function buildView(FormView $view, FormInterface $form, array $options)
View
116 Generator/FormValidationScriptGenerator.php
@@ -22,12 +22,7 @@
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
-use Assetic\AssetWriter;
-use Assetic\AssetManager;
-use Assetic\Factory\AssetFactory;
-use Assetic\Factory\LazyAssetManager;
use Assetic\Filter\Yui\JsCompressorFilter;
-use Assetic\FilterManager;
use Assetic\Asset\AssetCollection;
class FormValidationScriptGenerator
@@ -60,6 +55,16 @@ public function __construct(ContainerInterface $container)
}
/**
+ * Gets Entity Manager
+ *
+ * @return \Doctrine\ORM\EntityManager Returns Entity Manager
+ */
+ public function getEntityManager()
+ {
+ return $this->em;
+ }
+
+ /**
* Retrieves validation bundle name.
*
* Validation Bundle can be overridden in app/config/config.yml
@@ -72,7 +77,19 @@ public function __construct(ContainerInterface $container)
*/
public function getValidationBundle()
{
- return $this->container->getParameter('apy_js_form_validation.validation_bundle');
+ return $this->getParameter('validation_bundle');
+ }
+
+ /**
+ * Gets parameter value from apy_js_form_validation namespace
+ *
+ * @param string $parameter Parameter name
+ * @return mixed|null Returns parameter value, or NULL if it does not exist
+ */
+ public function getParameter($parameter)
+ {
+ return $this->container->hasParameter('apy_js_form_validation.' . $parameter) ?
+ $this->container->getParameter('apy_js_form_validation.' . $parameter) : null;
}
/**
@@ -102,10 +119,68 @@ public function getClassMetadata ($entityName)
}
/**
- * Generates
- * @param FormView $formView
- * @param unknown_type $overwrite
- * @throws \RuntimeException
+ * Checks, whether the entity has UiqueEntity Constraint
+ *
+ * @param string $entityName Entity Name
+ * @return boolean Returns TRUE if desired entity has UniqueEntity constraint
+ */
+ public function hasUniqueEntityConstraint ($entityName)
+ {
+ $ret = false;
+ $metadata = $this->getClassMetadata($entityName);
+ if (!empty($metadata->constraints)) {
+ foreach ($metadata->constraints as $constraint) {
+ if (preg_match("/\\\\UniqueEntity$/", get_class($constraint))) {
+ $ret = true;
+ break;
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Gets entity identifier value.
+ *
+ * When entity is updated UniqueEntity constraint should ignore
+ * entity with the same primary key id
+ *
+ * @param object $entity Entity object which is applied to the form
+ * @return array|null Returns array that contains values of the fields that form
+ * primary key of entity
+ * @throws \RuntimeException
+ */
+ public function getEntityIdentifierValue ($entity)
+ {
+ if (empty($entity) || !is_object($entity)) {
+ throw new \RuntimeException("Invalid parameter. Entity should be provided.");
+ }
+ $entityMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
+ $identifier = $entityMetadata->getIdentifier();
+ $ignore = array();
+ if (!empty($identifier)) {
+ foreach ($identifier as $prop) {
+ $propGetter = 'get' . ucfirst($prop);
+ if (method_exists($entity, $propGetter)) {
+ $ignore[] = $entity->$propGetter();
+ } elseif (isset($entity->$prop)) {
+ $ignore[] = $entity->$prop;
+ } else {
+ throw new \RuntimeException('Could not access value for the field: ' . $prop);
+ }
+ }
+ }
+ if (empty($ignore)) $ignore = null;
+
+ return $ignore;
+ }
+
+ /**
+ * Generates client-side javascript that validates form
+ *
+ * @param FormView $formView
+ * @param boolean $overwrite
+ * @throws \RuntimeException
*/
public function generate(FormView $formView, $overwrite = false)
{
@@ -233,27 +308,10 @@ public function generate(FormView $formView, $overwrite = false)
//We need to know entity class for the field which is applied by UniqueEntity constraint
if ($constraintName == 'UniqueEntity' && !empty($formField->parent)) {
$entity = $formField->parent->get('value');
- $entityMetadata = $this->em->getClassMetadata(get_class($entity));
- $identifier = $entityMetadata->getIdentifier();
- //When entity is updated UniqueEntity constraint should ignore
- //entity with the same primary key id
- $ignore = array();
- if (!empty($identifier)) {
- foreach ($identifier as $prop) {
- $propGetter = 'get' . ucfirst($prop);
- if (method_exists($entity, $propGetter)) {
- $ignore[] = $entity->$propGetter();
- } elseif (isset($entity->$prop)) {
- $ignore[] = $entity->$prop;
- } else {
- throw new \RuntimeException('Could not access value for the field: ' . $prop);
- }
- }
- }
- if (empty($ignore)) $ignore = null;
$constraintParameters += array(
'entity:' . json_encode(get_class($entity)),
- 'ignore:' . json_encode($ignore),
+ 'identifier_field_id:'.
+ json_encode($formView->children[$this->getParameter('identifier_field')]->get('id')),
);
}
foreach ($constraintProperties as $variable => $value) {
View
3  Resources/config/services.xml
@@ -32,6 +32,9 @@
<service id="form.type_extension.validation_groups" class="%form.type_extension.validation_groups.class%">
<tag name="form.type_extension" alias="form" />
+ <call method="setJsfv">
+ <argument type="service" id="jsfv.generator" />
+ </call>
</service>
<service id="form.type_extension.repeated_field_parameters" class="%form.type_extension.repeated_field_parameters.class%">
View
5 Resources/doc/configuration.md
@@ -12,6 +12,7 @@ apy_js_form_validation:
validation_bundle: APYJsFormValidationBundle
script_directory: bundles/jsformvalidation/js/
warmer_routes: [route1,route2]
+ identifier_field: jsfv_identifier
```
* `enabled` is optional (Default: `true`). Set to `false` disable all javascript form validations if you use the Twig function.
@@ -38,3 +39,7 @@ Here is a framework template of a the common script for validation.
* `script_directory` is optional (Default: `bundles/jsformvalidation/js/`). Define where scripts will be generated.
* `warmer_routes` is optional (Default: `~`). See [Assets warmer](assets_warmer.md)
+
+* `identifier_field` is optional (Default: `jsfv_identifier`).
+Defines the name of the hidden field which serves to convey the primary identifier value for UniqueEntity constraint request.
+This value will be ignored when entity is updated.
View
2  Resources/views/Constraints/UniqueEntityValidator.js.twig
@@ -20,7 +20,7 @@ function UniqueEntity(field, params)
'entity': params.entity,
'target': params.fields,
'value': value,
- 'ignore': params.ignore ? params.ignore : ''
+ 'ignore': params.identifier_field_id ? jsfv.id(params.identifier_field_id).value : ''
},
success: function(data, textStatus) {
{% block check_uniquity_handler %}
Please sign in to comment.
Something went wrong with that request. Please try again.