Selaa lähdekoodia

[Form] Support for the HTML5 "pattern" attribute, see http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#the-pattern-attribute
If you use the MinLength validator with your entities, the ValidatorTypeGuesser gets the value, stored as "minlength". Then, the FormFactory generates a "pattern" attribute out of minlength and maxlength.
Modern browsers such as Chrome use this attribute to validate the form before submitting.
a "pattern" attribute is generated that validates the

Michel Weimerskirch 14 vuotta sitten
vanhempi
commit
476644a92c

+ 8 - 0
src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php

@@ -180,4 +180,12 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
             }
         }
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function guessMinLength($class, $property)
+    {
+        return;
+    }
 }

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php

@@ -5,4 +5,5 @@
     <?php if ($read_only): ?>disabled="disabled"<?php endif ?>
     <?php if ($required): ?>required="required"<?php endif ?>
     <?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
+    <?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
 />

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php

@@ -5,4 +5,5 @@
     <?php if ($read_only): ?>disabled="disabled"<?php endif ?>
     <?php if ($required): ?>required="required"<?php endif ?>
     <?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
+    <?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
 />

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/text_widget.html.php

@@ -5,4 +5,5 @@
     <?php if ($read_only): ?>disabled="disabled"<?php endif ?>
     <?php if ($required): ?>required="required"<?php endif ?>
     <?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
+    <?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
 />

+ 1 - 1
src/Symfony/Bundle/TwigBundle/Resources/views/Form/div_layout.html.twig

@@ -43,7 +43,7 @@
 
 {% block attributes %}
 {% spaceless %}
-    id="{{ id }}" name="{{ name }}"{% if read_only %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}
+    id="{{ id }}" name="{{ name }}"{% if read_only %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
     {% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %}
 {% endspaceless %}
 {% endblock attributes %}

+ 3 - 0
src/Symfony/Component/Form/Extension/Core/Type/FieldType.php

@@ -44,6 +44,7 @@ class FieldType extends AbstractType
             ->setAttribute('property_path', $options['property_path'])
             ->setAttribute('error_mapping', $options['error_mapping'])
             ->setAttribute('max_length', $options['max_length'])
+            ->setAttribute('pattern', $options['pattern'])
             ->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
             ->setData($options['data'])
             ->addValidator(new DefaultValidator());
@@ -73,6 +74,7 @@ class FieldType extends AbstractType
         $view->set('read_only', $form->isReadOnly());
         $view->set('required', $form->isRequired());
         $view->set('max_length', $form->getAttribute('max_length'));
+        $view->set('pattern', $form->getAttribute('pattern'));
         $view->set('size', null);
         $view->set('label', $form->getAttribute('label'));
         $view->set('multipart', false);
@@ -94,6 +96,7 @@ class FieldType extends AbstractType
             'required' => true,
             'read_only' => false,
             'max_length' => null,
+            'pattern' => null,
             'property_path' => null,
             'by_reference' => true,
             'error_bubbling' => false,

+ 34 - 0
src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php

@@ -63,6 +63,18 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
         });
     }
 
+    /**
+     * @inheritDoc
+     */
+    public function guessMinLength($class, $property)
+    {
+        $guesser = $this;
+
+        return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
+            return $guesser->guessMinLengthForConstraint($constraint);
+        });
+    }
+
     /**
      * Iterates over the constraints of a property, executes a constraints on
      * them and returns the best guess
@@ -297,4 +309,26 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
                 );
         }
     }
+
+    /**
+     * Guesses a field's minimum length based on the given constraint
+     *
+     * @param  Constraint $constraint  The constraint to guess for
+     * @return Guess       The guess for the minimum length
+     */
+    public function guessMinLengthForConstraint(Constraint $constraint)
+    {
+        switch (get_class($constraint)) {
+            case 'Symfony\Component\Validator\Constraints\MinLength':
+                return new ValueGuess(
+                    $constraint->limit,
+                    Guess::HIGH_CONFIDENCE
+                );
+            case 'Symfony\Component\Validator\Constraints\Min':
+                return new ValueGuess(
+                    strlen((string)$constraint->limit),
+                    Guess::HIGH_CONFIDENCE
+                );
+        }
+    }
 }

+ 9 - 0
src/Symfony/Component/Form/FormFactory.php

@@ -173,6 +173,7 @@ class FormFactory implements FormFactoryInterface
 
         $typeGuess = $this->guesser->guessType($class, $property);
         $maxLengthGuess = $this->guesser->guessMaxLength($class, $property);
+        $minLengthGuess = $this->guesser->guessMinLength($class, $property);
         $requiredGuess = $this->guesser->guessRequired($class, $property);
 
         $type = $typeGuess ? $typeGuess->getType() : 'text';
@@ -181,6 +182,14 @@ class FormFactory implements FormFactoryInterface
             $options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
         }
 
+        if ($minLengthGuess) {
+            if ($maxLengthGuess) {
+                $options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().','.$maxLengthGuess->getValue().'}'), $options);
+            } else {
+                $options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().',}'), $options);
+            }
+        }
+
         if ($requiredGuess) {
             $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
         }

+ 7 - 0
src/Symfony/Component/Form/FormTypeGuesserChain.php

@@ -53,6 +53,13 @@ class FormTypeGuesserChain implements FormTypeGuesserInterface
         });
     }
 
+    public function guessMinLength($class, $property)
+    {
+        return $this->guess(function ($guesser) use ($class, $property) {
+            return $guesser->guessMinLength($class, $property);
+        });
+    }
+
     /**
      * Executes a closure for each guesser and returns the best guess from the
      * return values

+ 10 - 0
src/Symfony/Component/Form/FormTypeGuesserInterface.php

@@ -39,4 +39,14 @@ interface FormTypeGuesserInterface
      * @return Guess  A guess for the field's maximum length
      */
     function guessMaxLength($class, $property);
+
+    /**
+     * Returns a guess about the field's minimum length
+     *
+     * @param  string $class      The fully qualified class name
+     * @param  string $property   The name of the property to guess for
+     * @return Guess  A guess for the field's minimum length
+     */
+    function guessMinLength($class, $property);
+
 }