From 9ca92148efc908b905a1954607020c1634d92949 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 14 Dec 2013 11:01:40 +0100 Subject: [PATCH 01/20] [Form] Add min and max attributes to integer type Fixes #6732 --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 18 +++ .../Bridge/Propel1/Form/PropelTypeGuesser.php | 18 +++ .../Validator/ValidatorTypeGuesser.php | 64 +++++++++++ src/Symfony/Component/Form/FormFactory.php | 35 ++++++ .../Component/Form/FormTypeGuesserChain.php | 20 ++++ .../Form/FormTypeGuesserInterface.php | 20 ++++ .../Form/Tests/AbstractLayoutTest.php | 15 +++ .../Validator/ValidatorTypeGuesserTest.php | 41 ++++++- .../Component/Form/Tests/FormFactoryTest.php | 103 ++++++++++++++++++ 9 files changed, 332 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 9a7a1f8774538..09602b053b774 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -138,6 +138,24 @@ public function guessMaxLength($class, $property) } } + /** + * {@inheritDoc} + */ + public function guessMinValue($class, $property) + { + // Unfortunately we can't guess anything from database + return null; + } + + /** + * {@inheritDoc} + */ + public function guessMaxValue($class, $property) + { + // Unfortunately we can't guess anything from database + return null; + } + /** * {@inheritDoc} */ diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index 35382d89c3d2c..762465a847f14 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -136,6 +136,24 @@ public function guessMaxLength($class, $property) } } + /** + * {@inheritDoc} + */ + public function guessMinValue($class, $property) + { + // Unfortunately we can't guess anything from database + return null; + } + + /** + * {@inheritDoc} + */ + public function guessMaxValue($class, $property) + { + // Unfortunately we can't guess anything from database + return null; + } + /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 5cd02daa91bec..2fe0e46bcbd29 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -65,6 +65,30 @@ public function guessMaxLength($class, $property) }); } + /** + * {@inheritDoc} + */ + public function guessMaxValue($class, $property) + { + $guesser = $this; + + return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) { + return $guesser->guessMaxValueForConstraint($constraint); + }); + } + + /** + * {@inheritDoc} + */ + public function guessMinValue($class, $property) + { + $guesser = $this; + + return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) { + return $guesser->guessMinValueForConstraint($constraint); + }); + } + /** * {@inheritDoc} */ @@ -214,6 +238,46 @@ public function guessMaxLengthForConstraint(Constraint $constraint) return null; } + /** + * Guesses a field's maximum value based on the given constraint + * + * @param Constraint $constraint The constraint to guess for + * + * @return ValueGuess|null The guess for the maximum value + */ + public function guessMaxValueForConstraint(Constraint $constraint) + { + switch (get_class($constraint)) { + case 'Symfony\Component\Validator\Constraints\Range': + if (is_numeric($constraint->max)) { + return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE); + } + break; + } + + return null; + } + + /** + * Guesses a field's minimum value based on the given constraint + * + * @param Constraint $constraint The constraint to guess for + * + * @return ValueGuess|null The guess for the minimum value + */ + public function guessMinValueForConstraint(Constraint $constraint) + { + switch (get_class($constraint)) { + case 'Symfony\Component\Validator\Constraints\Range': + if (is_numeric($constraint->min)) { + return new ValueGuess($constraint->min, Guess::HIGH_CONFIDENCE); + } + break; + } + + return null; + } + /** * Guesses a field's pattern based on the given constraint * diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 63b2fe442c1f8..70ebd9f3c78e1 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -104,12 +104,16 @@ public function createBuilderForProperty($class, $property, $data = null, array $typeGuess = $guesser->guessType($class, $property); $maxLengthGuess = $guesser->guessMaxLength($class, $property); + $minValueGuess = $guesser->guessMinValue($class, $property); + $maxValueGuess = $guesser->guessMaxValue($class, $property); $requiredGuess = $guesser->guessRequired($class, $property); $patternGuess = $guesser->guessPattern($class, $property); $type = $typeGuess ? $typeGuess->getType() : 'text'; $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null; + $minValue = $minValueGuess ? $minValueGuess->getValue() : null; + $maxValue = $maxValueGuess ? $maxValueGuess->getValue() : null; $pattern = $patternGuess ? $patternGuess->getValue() : null; if (null !== $pattern) { @@ -120,6 +124,13 @@ public function createBuilderForProperty($class, $property, $data = null, array $options = array_merge(array('attr' => array('maxlength' => $maxLength)), $options); } + // Should we add number type? + // At the moment number types are rendered as text (@see form_div_layout.html.twig#163) + if (in_array($type, array('integer'))) { + $options = $this->addAttrValue($options, 'min', $minValue); + $options = $this->addAttrValue($options, 'max', $maxValue); + } + if ($requiredGuess) { $options = array_merge(array('required' => $requiredGuess->getValue()), $options); } @@ -132,6 +143,30 @@ public function createBuilderForProperty($class, $property, $data = null, array return $this->createNamedBuilder($property, $type, $data, $options); } + /** + * Add attribute value to attr option + * + * @param array $options The options + * @param string $key The key of the array + * @param string $value The value of the attribute + * + * @return array $options The options + */ + protected function addAttrValue(array $options, $key, $value = null) + { + if (null === $value) { + return $options; + } + + if (false === isset($options['attr'])) { + $options['attr'] = array(); + } + + $options['attr'] = array_merge(array($key => $value), $options['attr']); + + return $options; + } + /** * Wraps a type into a ResolvedFormTypeInterface implementation and connects * it with its parent type. diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index 6e858ddffef39..c9b577c18d820 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -70,6 +70,26 @@ public function guessMaxLength($class, $property) }); } + /** + * {@inheritDoc} + */ + public function guessMinValue($class, $property) + { + return $this->guess(function ($guesser) use ($class, $property) { + return $guesser->guessMinValue($class, $property); + }); + } + + /** + * {@inheritDoc} + */ + public function guessMaxValue($class, $property) + { + return $this->guess(function ($guesser) use ($class, $property) { + return $guesser->guessMaxValue($class, $property); + }); + } + /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index 7cd384a798129..a81357b466708 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -46,6 +46,26 @@ public function guessRequired($class, $property); */ public function guessMaxLength($class, $property); + /** + * Returns a guess about the field's maximum value + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's maximum value + */ + public function guessMaxValue($class, $property); + + /** + * Returns a guess about the field's minimum value + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's minimum value + */ + public function guessMinValue($class, $property); + /** * Returns a guess about the field's pattern * diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 532dc41be75f5..dfd38fdc1be4d 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -1334,6 +1334,21 @@ public function testInteger() ); } + public function testIntegerWithMinAndMax() + { + $form = $this->factory->createNamed('name', 'integer', 123, array('attr' => array('min' => -276, 'max' => 100))); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/input + [@type="number"] + [@name="name"] + [@value="123"] + [@min="-276"] + [@max="100"] +' + ); + } + public function testLanguage() { $form = $this->factory->createNamed('name', 'language', 'de'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index f42003d214c40..9980d8bfbd5bd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Constraints\Range; use Symfony\Component\Validator\Constraints\Type; /** @@ -53,8 +54,8 @@ public function testGuessMaxLengthForConstraintWithMinValue() } /** -* @dataProvider dataProviderTestGuessMaxLengthForConstraintWithType -*/ + * @dataProvider dataProviderTestGuessMaxLengthForConstraintWithType + */ public function testGuessMaxLengthForConstraintWithType($type) { $constraint = new Type($type); @@ -74,4 +75,40 @@ public static function dataProviderTestGuessMaxLengthForConstraintWithType() array('real') ); } + + public function testGuessMinValueForConstraintWithMinValue() + { + $constraint = new Range(array('min' => '2')); + + $result = $this->typeGuesser->guessMinValueForConstraint($constraint); + $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); + $this->assertEquals(2, $result->getValue()); + $this->assertEquals(Guess::HIGH_CONFIDENCE, $result->getConfidence()); + } + + public function testGuessMinValueForConstraintWithMaxValue() + { + $constraint = new Range(array('max' => '2')); + + $result = $this->typeGuesser->guessMinValueForConstraint($constraint); + $this->assertNull($result); + } + + public function testGuessMaxValueForConstraintWithMaxValue() + { + $constraint = new Range(array('max' => '2')); + + $result = $this->typeGuesser->guessMaxValueForConstraint($constraint); + $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); + $this->assertEquals(2, $result->getValue()); + $this->assertEquals(Guess::HIGH_CONFIDENCE, $result->getConfidence()); + } + + public function testGuessMaxValueForConstraintWithMinValue() + { + $constraint = new Range(array('min' => '2')); + + $result = $this->typeGuesser->guessMaxValueForConstraint($constraint); + $this->assertNull($result); + } } diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index a06b49876e1ca..781d7ced0c4ac 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -504,6 +504,109 @@ public function testCreateBuilderUsesMaxLengthIfFound() $this->assertEquals('builderInstance', $this->builder); } + public function testCreateBuilderUsesMinAndMaxValueIfFound() + { + $this->guesser1->expects($this->once()) + ->method('guessType') + ->will($this->returnValue(new TypeGuess( + 'integer', + array(), + Guess::HIGH_CONFIDENCE + ))); + + $this->guesser1->expects($this->once()) + ->method('guessMinValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); + + $this->guesser2->expects($this->once()) + ->method('guessMaxValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + 100, + Guess::HIGH_CONFIDENCE + ))); + + $factory = $this->getMockFactory(array('createNamedBuilder')); + + $factory->expects($this->once()) + ->method('createNamedBuilder') + ->with('degrees', 'integer', null, array('attr' => array('min' => -276, 'max' => 100))) + ->will($this->returnValue('builderInstance')); + + $this->builder = $factory->createBuilderForProperty( + 'Application\Temperature', + 'degrees' + ); + + $this->assertEquals('builderInstance', $this->builder); + } + + public function testMinAndMaxAttributesCanBeOverridden() + { + $this->guesser1->expects($this->once()) + ->method('guessType') + ->will($this->returnValue(new TypeGuess( + 'integer', + array(), + Guess::HIGH_CONFIDENCE + ))); + + $this->guesser1->expects($this->once()) + ->method('guessMinValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); + + $factory = $this->getMockFactory(array('createNamedBuilder')); + + $factory->expects($this->once()) + ->method('createNamedBuilder') + ->with('degrees', 'integer', null, array('attr' => array('min' => 50))) + ->will($this->returnValue('builderInstance')); + + $this->builder = $factory->createBuilderForProperty( + 'Application\Temperature', + 'degrees', + null, + array('attr' => array('min' => 50)) + ); + + $this->assertEquals('builderInstance', $this->builder); + } + + public function testMinAndMaxAttributesAreNotAddedToTextType() + { + $this->guesser1->expects($this->once()) + ->method('guessMinValue') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); + + $factory = $this->getMockFactory(array('createNamedBuilder')); + + $factory->expects($this->once()) + ->method('createNamedBuilder') + ->with('firstName', 'text', null) + ->will($this->returnValue('builderInstance')); + + $this->builder = $factory->createBuilderForProperty( + 'Application\Author', + 'firstName', + null, + array('attr' => array('min' => 50)) + ); + + $this->assertEquals('builderInstance', $this->builder); + } + public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() { $this->guesser1->expects($this->once()) From 82caf3705945227994bec7a2e2dbc978723b7dd9 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 14 Dec 2013 14:00:18 +0100 Subject: [PATCH 02/20] [Form] Fixed CS for FormFactoryTest --- .../Component/Form/Tests/FormFactoryTest.php | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 781d7ced0c4ac..1b12880ccb20c 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -474,20 +474,20 @@ public function testOptionsCanBeOverridden() public function testCreateBuilderUsesMaxLengthIfFound() { $this->guesser1->expects($this->once()) - ->method('guessMaxLength') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - 15, - Guess::MEDIUM_CONFIDENCE - ))); + ->method('guessMaxLength') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + 15, + Guess::MEDIUM_CONFIDENCE + ))); $this->guesser2->expects($this->once()) - ->method('guessMaxLength') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - 20, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessMaxLength') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + 20, + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -509,26 +509,26 @@ public function testCreateBuilderUsesMinAndMaxValueIfFound() $this->guesser1->expects($this->once()) ->method('guessType') ->will($this->returnValue(new TypeGuess( - 'integer', - array(), - Guess::HIGH_CONFIDENCE - ))); + 'integer', + array(), + Guess::HIGH_CONFIDENCE + ))); $this->guesser1->expects($this->once()) - ->method('guessMinValue') - ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( - -276, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessMinValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); $this->guesser2->expects($this->once()) - ->method('guessMaxValue') - ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( - 100, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessMaxValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + 100, + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -550,18 +550,18 @@ public function testMinAndMaxAttributesCanBeOverridden() $this->guesser1->expects($this->once()) ->method('guessType') ->will($this->returnValue(new TypeGuess( - 'integer', - array(), - Guess::HIGH_CONFIDENCE - ))); + 'integer', + array(), + Guess::HIGH_CONFIDENCE + ))); $this->guesser1->expects($this->once()) - ->method('guessMinValue') - ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( - -276, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessMinValue') + ->with('Application\Temperature', 'degrees') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -583,12 +583,12 @@ public function testMinAndMaxAttributesCanBeOverridden() public function testMinAndMaxAttributesAreNotAddedToTextType() { $this->guesser1->expects($this->once()) - ->method('guessMinValue') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - -276, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessMinValue') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + -276, + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -610,20 +610,20 @@ public function testMinAndMaxAttributesAreNotAddedToTextType() public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() { $this->guesser1->expects($this->once()) - ->method('guessRequired') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - true, - Guess::MEDIUM_CONFIDENCE - ))); + ->method('guessRequired') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + true, + Guess::MEDIUM_CONFIDENCE + ))); $this->guesser2->expects($this->once()) - ->method('guessRequired') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - false, - Guess::HIGH_CONFIDENCE - ))); + ->method('guessRequired') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + false, + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -643,20 +643,20 @@ public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() public function testCreateBuilderUsesPatternIfFound() { $this->guesser1->expects($this->once()) - ->method('guessPattern') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - '[a-z]', - Guess::MEDIUM_CONFIDENCE - ))); + ->method('guessPattern') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + '[a-z]', + Guess::MEDIUM_CONFIDENCE + ))); $this->guesser2->expects($this->once()) - ->method('guessPattern') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( - '[a-zA-Z]', - Guess::HIGH_CONFIDENCE - ))); + ->method('guessPattern') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new ValueGuess( + '[a-zA-Z]', + Guess::HIGH_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); From 6ca221029cdf649c912c3e7f6c09d91eeec05bdf Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 22 Dec 2013 22:15:49 +0100 Subject: [PATCH 03/20] [Form][PoC] Work on guesses --- .../Validator/ValidatorTypeGuesser.php | 22 +++++- .../Form/FormTypeGuesserInterface.php | 53 ++------------- .../Validator/ValidatorTypeGuesserTest.php | 68 ++++++++++--------- 3 files changed, 61 insertions(+), 82 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 2fe0e46bcbd29..b9e93921fd6b8 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -39,6 +39,24 @@ public function guessType($class, $property) }); } + /** + * {@inheritDoc} + */ + public function guessOptions($class, $property, $type) + { + $options = array(); + + switch ($type) { + case 'text': + if (($guess = $this->guessMaxLength($class, $property)) && null !== $guess->getValue()) { + $options = array_merge(array('max_length' => $guess->getValue()), $options); + } + break; + } + + return $options; + } + /** * {@inheritDoc} */ @@ -56,7 +74,7 @@ public function guessRequired($class, $property) /** * {@inheritDoc} */ - public function guessMaxLength($class, $property) + protected function guessMaxLength($class, $property) { $guesser = $this; @@ -213,7 +231,7 @@ public function guessRequiredForConstraint(Constraint $constraint) * * @return ValueGuess|null The guess for the maximum length */ - public function guessMaxLengthForConstraint(Constraint $constraint) + protected function guessMaxLengthForConstraint(Constraint $constraint) { switch (get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\Length': diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index a81357b466708..b03acca881558 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -27,58 +27,13 @@ interface FormTypeGuesserInterface public function guessType($class, $property); /** - * Returns a guess whether a property of a class is required + * Returns an array of guessed options * * @param string $class The fully qualified class name * @param string $property The name of the property to guess for + * @param string $type Boh. * - * @return Guess\ValueGuess A guess for the field's required setting + * @return array An array of guesses for the field's option */ - public function guessRequired($class, $property); - - /** - * Returns a guess about the field's maximum length - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's maximum length - */ - public function guessMaxLength($class, $property); - - /** - * Returns a guess about the field's maximum value - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's maximum value - */ - public function guessMaxValue($class, $property); - - /** - * Returns a guess about the field's minimum value - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's minimum value - */ - public function guessMinValue($class, $property); - - /** - * Returns a guess about the field's pattern - * - * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below - * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. - * Example: - * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) - * @link https://github.com/symfony/symfony/pull/3927 - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's required pattern - */ - public function guessPattern($class, $property); + public function guessOptions($class, $property, $type); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 9980d8bfbd5bd..37b41f9cfb4cc 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -30,50 +30,31 @@ public function setUp() $this->markTestSkipped('The "Validator" component is not available'); } - $metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); + $this->metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); - $this->typeGuesser = new ValidatorTypeGuesser($metadataFactory); + $this->typeGuesser = new ValidatorTypeGuesser($this->metadataFactory); } public function testGuessMaxLengthForConstraintWithMaxValue() { - $constraint = new Length(array('max' => '2')); + $class = new \stdClass(); - $result = $this->typeGuesser->guessMaxLengthForConstraint($constraint); - $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); - $this->assertEquals(2, $result->getValue()); - $this->assertEquals(Guess::HIGH_CONFIDENCE, $result->getConfidence()); - } + $this->setupMetadata($class, 'foo', array(new Length(array('max' => '2')))); - public function testGuessMaxLengthForConstraintWithMinValue() - { - $constraint = new Length(array('min' => '2')); + $result = $this->typeGuesser->guessOptions($class, 'foo', 'text'); - $result = $this->typeGuesser->guessMaxLengthForConstraint($constraint); - $this->assertNull($result); + $this->assertEquals(array('max_length' => 2), $result); } - /** - * @dataProvider dataProviderTestGuessMaxLengthForConstraintWithType - */ - public function testGuessMaxLengthForConstraintWithType($type) + public function testGuessMaxLengthForConstraintWithMinValue() { - $constraint = new Type($type); + $class = new \stdClass(); - $result = $this->typeGuesser->guessMaxLengthForConstraint($constraint); - $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); - $this->assertEquals(null, $result->getValue()); - $this->assertEquals(Guess::MEDIUM_CONFIDENCE, $result->getConfidence()); - } + $this->setupMetadata($class, 'foo', array(new Length(array('min' => '2')))); - public static function dataProviderTestGuessMaxLengthForConstraintWithType() - { - return array ( - array('double'), - array('float'), - array('numeric'), - array('real') - ); + $result = $this->typeGuesser->guessOptions($class, 'foo', 'text'); + + $this->assertEquals(array(), $result); } public function testGuessMinValueForConstraintWithMinValue() @@ -111,4 +92,29 @@ public function testGuessMaxValueForConstraintWithMinValue() $result = $this->typeGuesser->guessMaxValueForConstraint($constraint); $this->assertNull($result); } + + private function setupMetadata($class, $property, array $constraints) + { + $this->elementMetadata = $this->getMock('Symfony\Component\Validator\Mapping\ElementMetadata'); + $this->elementMetadata->expects($this->once()) + ->method('getConstraints') + ->will($this->returnValue($constraints)); + + $this->metadata = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata') + ->disableOriginalConstructor() + ->getMock(); + $this->metadata->expects($this->once()) + ->method('hasMemberMetadatas') + ->with($property) + ->will($this->returnValue(true)); + $this->metadata->expects($this->once()) + ->method('getMemberMetadatas') + ->with($property) + ->will($this->returnValue(array($this->elementMetadata))); + + $this->metadataFactory->expects($this->once()) + ->method('getMetadataFor') + ->with($class) + ->will($this->returnValue($this->metadata)); + } } From 8b084f02923cc2789510c4f2df654cc63377be04 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 29 Dec 2013 19:29:44 +0100 Subject: [PATCH 04/20] Options length, min, max discover --- .../Validator/ValidatorTypeGuesser.php | 19 ++++--- .../Form/FormTypeGuesserInterface.php | 8 +-- .../Component/Form/ResolvedFormType.php | 17 ++++++ .../Form/ResolvedFormTypeInterface.php | 8 +++ .../Validator/ValidatorTypeGuesserTest.php | 55 +++++++++++-------- 5 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index b9e93921fd6b8..d5a48eba895e2 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; +use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Constraint; @@ -42,16 +43,20 @@ public function guessType($class, $property) /** * {@inheritDoc} */ - public function guessOptions($class, $property, $type) + public function guessOptions($class, $property, ResolvedFormTypeInterface $type) { $options = array(); - switch ($type) { - case 'text': - if (($guess = $this->guessMaxLength($class, $property)) && null !== $guess->getValue()) { - $options = array_merge(array('max_length' => $guess->getValue()), $options); - } - break; + if ($type->isKnown('max_length') && ($guess = $this->guessMaxLength($class, $property)) && null !== $guess->getValue()) { + $options = array_merge_recursive(array('max_length' => $guess->getValue()), $options); + } + + if ($type->isKnown('min') && ($guess = $this->guessMinValue($class, $property)) && null !== $guess->getValue()) { + $options = array_merge_recursive(array('attr' => array('min' => $guess->getValue())), $options); + } + + if ($type->isKnown('max') && ($guess = $this->guessMaxValue($class, $property)) && null !== $guess->getValue()) { + $options = array_merge_recursive(array('attr' => array('max' => $guess->getValue())), $options); } return $options; diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index b03acca881558..1f2c1ce398ffd 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -29,11 +29,11 @@ public function guessType($class, $property); /** * Returns an array of guessed options * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param string $type Boh. + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param ResolvedFormTypeInterface $type Field's type * * @return array An array of guesses for the field's option */ - public function guessOptions($class, $property, $type); + public function guessOptions($class, $property, ResolvedFormTypeInterface $type); } diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index f8d87d0f97ae5..ee276b90c28e7 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -13,6 +13,7 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\Extension\Core\Type as FormType; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -125,6 +126,22 @@ public function createView(FormInterface $form, FormView $parent = null) return $this->newView($parent); } + /** + * {@inheritdoc} + */ + public function isKnown($property) + { + switch ($property) { + case 'max_length': + return $this->innerType instanceof FormType\TextType; + case 'min': + case 'max': + return $this->innerType instanceof FormType\IntegerType; + } + + return false; + } + /** * Configures a form builder for the type hierarchy. * diff --git a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php index 5fd37f4b46340..2a86e15fb81f9 100644 --- a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php +++ b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php @@ -103,4 +103,12 @@ public function finishView(FormView $view, FormInterface $form, array $options); * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver. */ public function getOptionsResolver(); + + /** + * Checks if the form type supports the given property + * + * @param string $property The property to check + * @return boolean True if the form type supports the given property + */ + public function isKnown($property); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 37b41f9cfb4cc..bb3da65d87d90 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -13,6 +13,8 @@ use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; use Symfony\Component\Form\Guess\Guess; +use Symfony\Component\Form\ResolvedFormType; +use Symfony\Component\Form\Extension\Core\Type as FormType; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Range; use Symfony\Component\Validator\Constraints\Type; @@ -35,54 +37,59 @@ public function setUp() $this->typeGuesser = new ValidatorTypeGuesser($this->metadataFactory); } - public function testGuessMaxLengthForConstraintWithMaxValue() + public function testGuessOptionsForConstraintWithMaxLength() { $class = new \stdClass(); $this->setupMetadata($class, 'foo', array(new Length(array('max' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', 'text'); + $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\TextType())); $this->assertEquals(array('max_length' => 2), $result); } - public function testGuessMaxLengthForConstraintWithMinValue() + public function testGuessOptionsForConstraintWithMinLength() { $class = new \stdClass(); $this->setupMetadata($class, 'foo', array(new Length(array('min' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', 'text'); + $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\TextType())); $this->assertEquals(array(), $result); } - public function testGuessMinValueForConstraintWithMinValue() + public function testGuessOptionsForConstraintWithMinValue() { - $constraint = new Range(array('min' => '2')); + $class = new \stdClass(); + + $this->setupMetadata($class, 'foo', array(new Range(array('min' => '2')))); - $result = $this->typeGuesser->guessMinValueForConstraint($constraint); - $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); - $this->assertEquals(2, $result->getValue()); - $this->assertEquals(Guess::HIGH_CONFIDENCE, $result->getConfidence()); + $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + + $this->assertEquals(array('attr' => array('min' => 2)), $result); } - public function testGuessMinValueForConstraintWithMaxValue() + public function testGuessOptionsForConstraintWithMaxValue() { - $constraint = new Range(array('max' => '2')); + $class = new \stdClass(); - $result = $this->typeGuesser->guessMinValueForConstraint($constraint); - $this->assertNull($result); + $this->setupMetadata($class, 'foo', array(new Range(array('max' => '2')))); + + $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + + $this->assertEquals(array('attr' => array('max' => 2)), $result); } - public function testGuessMaxValueForConstraintWithMaxValue() + public function testGuessOptionsForConstraintWithMinAndMaxValue() { - $constraint = new Range(array('max' => '2')); + $class = new \stdClass(); - $result = $this->typeGuesser->guessMaxValueForConstraint($constraint); - $this->assertInstanceOf('Symfony\Component\Form\Guess\ValueGuess', $result); - $this->assertEquals(2, $result->getValue()); - $this->assertEquals(Guess::HIGH_CONFIDENCE, $result->getConfidence()); + $this->setupMetadata($class, 'foo', array(new Range(array('min' => 1, 'max' => '2')))); + + $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + + $this->assertEquals(array('attr' => array('min' => 1, 'max' => 2)), $result); } public function testGuessMaxValueForConstraintWithMinValue() @@ -96,23 +103,23 @@ public function testGuessMaxValueForConstraintWithMinValue() private function setupMetadata($class, $property, array $constraints) { $this->elementMetadata = $this->getMock('Symfony\Component\Validator\Mapping\ElementMetadata'); - $this->elementMetadata->expects($this->once()) + $this->elementMetadata->expects($this->any()) ->method('getConstraints') ->will($this->returnValue($constraints)); $this->metadata = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata') ->disableOriginalConstructor() ->getMock(); - $this->metadata->expects($this->once()) + $this->metadata->expects($this->any()) ->method('hasMemberMetadatas') ->with($property) ->will($this->returnValue(true)); - $this->metadata->expects($this->once()) + $this->metadata->expects($this->any()) ->method('getMemberMetadatas') ->with($property) ->will($this->returnValue(array($this->elementMetadata))); - $this->metadataFactory->expects($this->once()) + $this->metadataFactory->expects($this->any()) ->method('getMetadataFor') ->with($class) ->will($this->returnValue($this->metadata)); From 53b03a09677e70d47f6f20b888c6be4ceb5a68da Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 29 Dec 2013 19:42:04 +0100 Subject: [PATCH 05/20] Changed from visibility of not more public methods --- .../Validator/ValidatorTypeGuesser.php | 40 +++++++++++++++---- .../Validator/ValidatorTypeGuesserTest.php | 8 ---- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index d5a48eba895e2..bc21e4f1c488d 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -77,7 +77,12 @@ public function guessRequired($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's maximum length + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's maximum length */ protected function guessMaxLength($class, $property) { @@ -89,9 +94,14 @@ protected function guessMaxLength($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's maximum value + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's maximum value */ - public function guessMaxValue($class, $property) + protected function guessMaxValue($class, $property) { $guesser = $this; @@ -101,9 +111,14 @@ public function guessMaxValue($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's minimum value + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's minimum value */ - public function guessMinValue($class, $property) + protected function guessMinValue($class, $property) { $guesser = $this; @@ -113,9 +128,20 @@ public function guessMinValue($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's pattern + * + * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below + * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. + * Example: + * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) + * @link https://github.com/symfony/symfony/pull/3927 + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's required pattern */ - public function guessPattern($class, $property) + protected function guessPattern($class, $property) { $guesser = $this; diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index bb3da65d87d90..f625ffa51ae25 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -92,14 +92,6 @@ public function testGuessOptionsForConstraintWithMinAndMaxValue() $this->assertEquals(array('attr' => array('min' => 1, 'max' => 2)), $result); } - public function testGuessMaxValueForConstraintWithMinValue() - { - $constraint = new Range(array('min' => '2')); - - $result = $this->typeGuesser->guessMaxValueForConstraint($constraint); - $this->assertNull($result); - } - private function setupMetadata($class, $property, array $constraints) { $this->elementMetadata = $this->getMock('Symfony\Component\Validator\Mapping\ElementMetadata'); From 5633dd7185d9d2f391f33deec9af98415ea54569 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Mon, 30 Dec 2013 22:55:45 +0100 Subject: [PATCH 06/20] Added pattern option --- src/Symfony/Component/Form/ResolvedFormType.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index ee276b90c28e7..b76a114a26dbf 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -137,6 +137,8 @@ public function isKnown($property) case 'min': case 'max': return $this->innerType instanceof FormType\IntegerType; + case 'pattern': + return $this->innerType instanceof FormType\TextType; } return false; From cd2661d2822cbc1c6e32b8eacac94897c3114c86 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Thu, 2 Jan 2014 19:53:31 +0100 Subject: [PATCH 07/20] Refactored guess options to guess attributes and added a mapping for form types supported attributes --- .../Validator/ValidatorTypeGuesser.php | 38 ++++++---- src/Symfony/Component/Form/FormFactory.php | 74 +++++++------------ .../Component/Form/FormTypeGuesserChain.php | 56 ++++---------- .../Form/FormTypeGuesserInterface.php | 6 +- .../Component/Form/ResolvedFormType.php | 18 ----- .../Form/ResolvedFormTypeInterface.php | 8 -- .../Validator/ValidatorTypeGuesserTest.php | 28 ++++--- .../Component/Form/Tests/FormFactoryTest.php | 62 ++++++++-------- 8 files changed, 117 insertions(+), 173 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index bc21e4f1c488d..151e8848f7091 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -43,29 +43,41 @@ public function guessType($class, $property) /** * {@inheritDoc} */ - public function guessOptions($class, $property, ResolvedFormTypeInterface $type) + public function guessAttributes($class, $property) { - $options = array(); + $attributes = array(); - if ($type->isKnown('max_length') && ($guess = $this->guessMaxLength($class, $property)) && null !== $guess->getValue()) { - $options = array_merge_recursive(array('max_length' => $guess->getValue()), $options); + if ($guess = $this->guessRequired($class, $property)) { + $attributes['required'] = $guess; } - if ($type->isKnown('min') && ($guess = $this->guessMinValue($class, $property)) && null !== $guess->getValue()) { - $options = array_merge_recursive(array('attr' => array('min' => $guess->getValue())), $options); + if ($guess = $this->guessMaxLength($class, $property)) { + $attributes['maxlength'] = $guess; } - if ($type->isKnown('max') && ($guess = $this->guessMaxValue($class, $property)) && null !== $guess->getValue()) { - $options = array_merge_recursive(array('attr' => array('max' => $guess->getValue())), $options); + if ($guess = $this->guessMinValue($class, $property)) { + $attributes['min'] = $guess; } - return $options; + if ($guess = $this->guessMaxValue($class, $property)) { + $attributes['max'] = $guess; + } + + return $attributes; } - /** - * {@inheritDoc} - */ - public function guessRequired($class, $property) + private function addAttribute(array $attributes, $key, Guess $guess = null) + { + if (null === $guess) { + return $attributes; + } + + if ($value = $guess->getValue()) { + return array_merge($attributes, array($key => $guess->getValue())); + } + } + + protected function guessRequired($class, $property) { $guesser = $this; diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 70ebd9f3c78e1..fae1d012f6c6c 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -24,6 +24,22 @@ class FormFactory implements FormFactoryInterface * @var ResolvedFormTypeFactoryInterface */ private $resolvedTypeFactory; + + protected $supportedAttributes = array( + 'text' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), + 'search' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), + 'url' => array('autocomplete', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), + 'email' => array('autocomplete', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), + 'password' => array('autocomplete', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), + 'date' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), + 'datetime' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), + 'time' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), + 'integer' => array('autocomplete', 'list', 'max', 'min', 'placeholder', 'readonly', 'required', 'step'), + 'decimal' => array('autocomplete', 'list', 'max', 'min', 'placeholder', 'readonly', 'required', 'step'), + 'range' => array('autocomplete', 'list', 'max', 'min', 'step'), + 'checkbox' => array('checked', 'required'), + 'file' => array('accept', 'multiple', 'required') + ); public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory) { @@ -103,37 +119,21 @@ public function createBuilderForProperty($class, $property, $data = null, array } $typeGuess = $guesser->guessType($class, $property); - $maxLengthGuess = $guesser->guessMaxLength($class, $property); - $minValueGuess = $guesser->guessMinValue($class, $property); - $maxValueGuess = $guesser->guessMaxValue($class, $property); - $requiredGuess = $guesser->guessRequired($class, $property); - $patternGuess = $guesser->guessPattern($class, $property); + $guessedAttributes = $guesser->guessAttributes($class, $property); $type = $typeGuess ? $typeGuess->getType() : 'text'; - $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null; - $minValue = $minValueGuess ? $minValueGuess->getValue() : null; - $maxValue = $maxValueGuess ? $maxValueGuess->getValue() : null; - $pattern = $patternGuess ? $patternGuess->getValue() : null; + $filteredAttributes = array(); - if (null !== $pattern) { - $options = array_merge(array('attr' => array('pattern' => $pattern)), $options); + foreach ($guessedAttributes as $key => $value) { + if (isset($this->supportedAttributes[$type]) && in_array($key, $this->supportedAttributes[$type])) { + $filteredAttributes[$key] = $value->getValue(); + } } - if (null !== $maxLength) { - $options = array_merge(array('attr' => array('maxlength' => $maxLength)), $options); - } - - // Should we add number type? - // At the moment number types are rendered as text (@see form_div_layout.html.twig#163) - if (in_array($type, array('integer'))) { - $options = $this->addAttrValue($options, 'min', $minValue); - $options = $this->addAttrValue($options, 'max', $maxValue); - } - - if ($requiredGuess) { - $options = array_merge(array('required' => $requiredGuess->getValue()), $options); - } + $options = array_merge(array( + 'attr' => $filteredAttributes + ), $options); // user options may override guessed options if ($typeGuess) { @@ -143,30 +143,6 @@ public function createBuilderForProperty($class, $property, $data = null, array return $this->createNamedBuilder($property, $type, $data, $options); } - /** - * Add attribute value to attr option - * - * @param array $options The options - * @param string $key The key of the array - * @param string $value The value of the attribute - * - * @return array $options The options - */ - protected function addAttrValue(array $options, $key, $value = null) - { - if (null === $value) { - return $options; - } - - if (false === isset($options['attr'])) { - $options['attr'] = array(); - } - - $options['attr'] = array_merge(array($key => $value), $options['attr']); - - return $options; - } - /** * Wraps a type into a ResolvedFormTypeInterface implementation and connects * it with its parent type. diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index c9b577c18d820..5408132dc87e3 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -53,51 +53,25 @@ public function guessType($class, $property) /** * {@inheritDoc} */ - public function guessRequired($class, $property) + public function guessAttributes($class, $property) { - return $this->guess(function ($guesser) use ($class, $property) { - return $guesser->guessRequired($class, $property); - }); - } + $attributes = array(); - /** - * {@inheritDoc} - */ - public function guessMaxLength($class, $property) - { - return $this->guess(function ($guesser) use ($class, $property) { - return $guesser->guessMaxLength($class, $property); - }); - } - - /** - * {@inheritDoc} - */ - public function guessMinValue($class, $property) - { - return $this->guess(function ($guesser) use ($class, $property) { - return $guesser->guessMinValue($class, $property); - }); - } + foreach ($this->guessers as $guesser) { + $guessedAttributes = $guesser->guessAttributes($class, $property); - /** - * {@inheritDoc} - */ - public function guessMaxValue($class, $property) - { - return $this->guess(function ($guesser) use ($class, $property) { - return $guesser->guessMaxValue($class, $property); - }); - } + if (is_array($guessedAttributes)) { + foreach ($guessedAttributes as $key => $value) { + if (isset($attributes[$key])) { + $attributes[$key] = Guess::getBestGuess(array($attributes[$key], $value)); + } else { + $attributes[$key] = $value; + } + } + } + } - /** - * {@inheritDoc} - */ - public function guessPattern($class, $property) - { - return $this->guess(function ($guesser) use ($class, $property) { - return $guesser->guessPattern($class, $property); - }); + return $attributes; } /** diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index 1f2c1ce398ffd..d9c58f6b7f619 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -27,13 +27,13 @@ interface FormTypeGuesserInterface public function guessType($class, $property); /** - * Returns an array of guessed options + * Returns an array of guessed attributes * * @param string $class The fully qualified class name * @param string $property The name of the property to guess for * @param ResolvedFormTypeInterface $type Field's type * - * @return array An array of guesses for the field's option + * @return array An array of guesses for the field's attributes */ - public function guessOptions($class, $property, ResolvedFormTypeInterface $type); + public function guessAttributes($class, $property); } diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index b76a114a26dbf..d63d3e7e60bf5 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -126,24 +126,6 @@ public function createView(FormInterface $form, FormView $parent = null) return $this->newView($parent); } - /** - * {@inheritdoc} - */ - public function isKnown($property) - { - switch ($property) { - case 'max_length': - return $this->innerType instanceof FormType\TextType; - case 'min': - case 'max': - return $this->innerType instanceof FormType\IntegerType; - case 'pattern': - return $this->innerType instanceof FormType\TextType; - } - - return false; - } - /** * Configures a form builder for the type hierarchy. * diff --git a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php index 2a86e15fb81f9..5fd37f4b46340 100644 --- a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php +++ b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php @@ -103,12 +103,4 @@ public function finishView(FormView $view, FormInterface $form, array $options); * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver. */ public function getOptionsResolver(); - - /** - * Checks if the form type supports the given property - * - * @param string $property The property to check - * @return boolean True if the form type supports the given property - */ - public function isKnown($property); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index f625ffa51ae25..02d32b0106e08 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -43,9 +43,11 @@ public function testGuessOptionsForConstraintWithMaxLength() $this->setupMetadata($class, 'foo', array(new Length(array('max' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\TextType())); + $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertEquals(array('max_length' => 2), $result); + $this->assertArrayHasKey('maxlength', $result); + $this->assertEquals(2, $result['maxlength']->getValue()); + $this->assertFalse(isset($result['min'])); } public function testGuessOptionsForConstraintWithMinLength() @@ -54,9 +56,10 @@ public function testGuessOptionsForConstraintWithMinLength() $this->setupMetadata($class, 'foo', array(new Length(array('min' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\TextType())); + $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertEquals(array(), $result); + $this->assertArrayHasKey('required', $result); + $this->assertFalse($result['required']->getValue()); } public function testGuessOptionsForConstraintWithMinValue() @@ -65,9 +68,10 @@ public function testGuessOptionsForConstraintWithMinValue() $this->setupMetadata($class, 'foo', array(new Range(array('min' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertEquals(array('attr' => array('min' => 2)), $result); + $this->assertArrayHasKey('min', $result); + $this->assertEquals(2, $result['min']->getValue()); } public function testGuessOptionsForConstraintWithMaxValue() @@ -76,9 +80,10 @@ public function testGuessOptionsForConstraintWithMaxValue() $this->setupMetadata($class, 'foo', array(new Range(array('max' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertEquals(array('attr' => array('max' => 2)), $result); + $this->assertArrayHasKey('max', $result); + $this->assertEquals(2, $result['max']->getValue()); } public function testGuessOptionsForConstraintWithMinAndMaxValue() @@ -87,9 +92,12 @@ public function testGuessOptionsForConstraintWithMinAndMaxValue() $this->setupMetadata($class, 'foo', array(new Range(array('min' => 1, 'max' => '2')))); - $result = $this->typeGuesser->guessOptions($class, 'foo', new ResolvedFormType(new FormType\IntegerType())); + $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertEquals(array('attr' => array('min' => 1, 'max' => 2)), $result); + $this->assertArrayHasKey('min', $result); + $this->assertEquals(1, $result['min']->getValue()); + $this->assertArrayHasKey('max', $result); + $this->assertEquals(2, $result['max']->getValue()); } private function setupMetadata($class, $property, array $constraints) diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 1b12880ccb20c..349ffa26fb61a 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -474,20 +474,20 @@ public function testOptionsCanBeOverridden() public function testCreateBuilderUsesMaxLengthIfFound() { $this->guesser1->expects($this->once()) - ->method('guessMaxLength') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('maxlength' => new ValueGuess( 15, Guess::MEDIUM_CONFIDENCE - ))); + )))); $this->guesser2->expects($this->once()) - ->method('guessMaxLength') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('maxlength' => new ValueGuess( 20, Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -515,20 +515,20 @@ public function testCreateBuilderUsesMinAndMaxValueIfFound() ))); $this->guesser1->expects($this->once()) - ->method('guessMinValue') + ->method('guessAttributes') ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('min' => new ValueGuess( -276, Guess::HIGH_CONFIDENCE - ))); + )))); $this->guesser2->expects($this->once()) - ->method('guessMaxValue') + ->method('guessAttributes') ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('max' => new ValueGuess( 100, Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -556,12 +556,12 @@ public function testMinAndMaxAttributesCanBeOverridden() ))); $this->guesser1->expects($this->once()) - ->method('guessMinValue') + ->method('guessAttributes') ->with('Application\Temperature', 'degrees') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('min' => new ValueGuess( -276, Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -583,12 +583,12 @@ public function testMinAndMaxAttributesCanBeOverridden() public function testMinAndMaxAttributesAreNotAddedToTextType() { $this->guesser1->expects($this->once()) - ->method('guessMinValue') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('min' => new ValueGuess( -276, Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -610,26 +610,26 @@ public function testMinAndMaxAttributesAreNotAddedToTextType() public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() { $this->guesser1->expects($this->once()) - ->method('guessRequired') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('required' => new ValueGuess( true, Guess::MEDIUM_CONFIDENCE - ))); + )))); $this->guesser2->expects($this->once()) - ->method('guessRequired') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('required' => new ValueGuess( false, Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); $factory->expects($this->once()) ->method('createNamedBuilder') - ->with('firstName', 'text', null, array('required' => false)) + ->with('firstName', 'text', null, array('attr' => array('required' => false))) ->will($this->returnValue('builderInstance')); $this->builder = $factory->createBuilderForProperty( @@ -643,20 +643,20 @@ public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() public function testCreateBuilderUsesPatternIfFound() { $this->guesser1->expects($this->once()) - ->method('guessPattern') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('pattern' => new ValueGuess( '[a-z]', Guess::MEDIUM_CONFIDENCE - ))); + )))); $this->guesser2->expects($this->once()) - ->method('guessPattern') + ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(new ValueGuess( + ->will($this->returnValue(array('pattern' => new ValueGuess( '[a-zA-Z]', Guess::HIGH_CONFIDENCE - ))); + )))); $factory = $this->getMockFactory(array('createNamedBuilder')); From 36f89a8f9d51bc2dbff4d9b4fea250296c5d2a43 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Thu, 2 Jan 2014 21:36:58 +0100 Subject: [PATCH 08/20] Implemented new interface in DoctrineOrmTypeGuesser --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 47 +++++++++++++++++-- .../Tests/Form/DoctrineOrmTypeGuesserTest.php | 16 ++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 09602b053b774..3289da25b560c 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -82,7 +82,44 @@ public function guessType($class, $property) /** * {@inheritDoc} */ - public function guessRequired($class, $property) + public function guessAttributes($class, $property) + { + $attributes = array(); + + if ($guess = $this->guessRequired($class, $property)) { + $attributes['required'] = $guess; + } + + if ($guess = $this->guessMaxLength($class, $property)) { + $attributes['maxlength'] = $guess; + } + + if ($guess = $this->guessMinValue($class, $property)) { + $attributes['min'] = $guess; + } + + if ($guess = $this->guessMaxValue($class, $property)) { + $attributes['max'] = $guess; + } + + return $attributes; + } + + private function addAttribute(array $attributes, $key, Guess $guess = null) + { + if (null === $guess) { + return $attributes; + } + + if ($value = $guess->getValue()) { + return array_merge($attributes, array($key => $guess->getValue())); + } + } + + /** + * {@inheritDoc} + */ + protected function guessRequired($class, $property) { $classMetadatas = $this->getMetadata($class); @@ -122,7 +159,7 @@ public function guessRequired($class, $property) /** * {@inheritDoc} */ - public function guessMaxLength($class, $property) + protected function guessMaxLength($class, $property) { $ret = $this->getMetadata($class); if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) { @@ -141,7 +178,7 @@ public function guessMaxLength($class, $property) /** * {@inheritDoc} */ - public function guessMinValue($class, $property) + protected function guessMinValue($class, $property) { // Unfortunately we can't guess anything from database return null; @@ -150,7 +187,7 @@ public function guessMinValue($class, $property) /** * {@inheritDoc} */ - public function guessMaxValue($class, $property) + protected function guessMaxValue($class, $property) { // Unfortunately we can't guess anything from database return null; @@ -159,7 +196,7 @@ public function guessMaxValue($class, $property) /** * {@inheritDoc} */ - public function guessPattern($class, $property) + protected function guessPattern($class, $property) { $ret = $this->getMetadata($class); if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index 82c587aaffec1..9ef51bb2009c9 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -23,7 +23,9 @@ class DoctrineOrmTypeGuesserTest extends \PHPUnit_Framework_TestCase */ public function testRequiredGuesser($classMetadata, $expected) { - $this->assertEquals($expected, $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); + $attributes = $this->getGuesser($classMetadata)->guessAttributes('TestEntity', 'field'); + + $this->assertEquals($expected, isset($attributes['required']) ? $attributes['required'] : null); } public function requiredProvider() @@ -32,21 +34,21 @@ public function requiredProvider() // Simple field, not nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(true)); $classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(false)); $return[] = array($classMetadata, new ValueGuess(true, Guess::HIGH_CONFIDENCE)); // Simple field, nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(true)); $classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(true)); $return[] = array($classMetadata, new ValueGuess(false, Guess::MEDIUM_CONFIDENCE)); // One-to-one, nullable (by default) $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array())); @@ -56,7 +58,7 @@ public function requiredProvider() // One-to-one, nullable (explicit) $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array('nullable'=>true))); @@ -66,7 +68,7 @@ public function requiredProvider() // One-to-one, not nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array('nullable'=>false))); @@ -76,7 +78,7 @@ public function requiredProvider() // One-to-many, no clue $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(false)); $return[] = array($classMetadata, null); From 30cbb884cd325a8f0a4444fd33b1342b3d686db6 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Thu, 2 Jan 2014 21:52:21 +0100 Subject: [PATCH 09/20] Implemented new interface in PropelTypeGuesser --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 11 ------ .../Bridge/Propel1/Form/PropelTypeGuesser.php | 36 ++++++++++++++++--- .../Tests/Form/PropelTypeGuesserTest.php | 35 +++++++++--------- 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 3289da25b560c..4ddfaf4385b2c 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -105,17 +105,6 @@ public function guessAttributes($class, $property) return $attributes; } - private function addAttribute(array $attributes, $key, Guess $guess = null) - { - if (null === $guess) { - return $attributes; - } - - if ($value = $guess->getValue()) { - return array_merge($attributes, array($key => $guess->getValue())); - } - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index 762465a847f14..1f23a088702b9 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -110,7 +110,33 @@ public function guessType($class, $property) /** * {@inheritDoc} */ - public function guessRequired($class, $property) + public function guessAttributes($class, $property) + { + $attributes = array(); + + if ($guess = $this->guessRequired($class, $property)) { + $attributes['required'] = $guess; + } + + if ($guess = $this->guessMaxLength($class, $property)) { + $attributes['maxlength'] = $guess; + } + + if ($guess = $this->guessMinValue($class, $property)) { + $attributes['min'] = $guess; + } + + if ($guess = $this->guessMaxValue($class, $property)) { + $attributes['max'] = $guess; + } + + return $attributes; + } + + /** + * {@inheritDoc} + */ + protected function guessRequired($class, $property) { if ($column = $this->getColumn($class, $property)) { return new ValueGuess($column->isNotNull(), Guess::HIGH_CONFIDENCE); @@ -120,7 +146,7 @@ public function guessRequired($class, $property) /** * {@inheritDoc} */ - public function guessMaxLength($class, $property) + protected function guessMaxLength($class, $property) { if ($column = $this->getColumn($class, $property)) { if ($column->isText()) { @@ -139,7 +165,7 @@ public function guessMaxLength($class, $property) /** * {@inheritDoc} */ - public function guessMinValue($class, $property) + protected function guessMinValue($class, $property) { // Unfortunately we can't guess anything from database return null; @@ -148,7 +174,7 @@ public function guessMinValue($class, $property) /** * {@inheritDoc} */ - public function guessMaxValue($class, $property) + protected function guessMaxValue($class, $property) { // Unfortunately we can't guess anything from database return null; @@ -157,7 +183,7 @@ public function guessMaxValue($class, $property) /** * {@inheritDoc} */ - public function guessPattern($class, $property) + protected function guessPattern($class, $property) { if ($column = $this->getColumn($class, $property)) { switch ($column->getType()) { diff --git a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php index bb59503e61c63..5bf860189c66f 100644 --- a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php +++ b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php @@ -30,49 +30,50 @@ public function setUp() public function testGuessMaxLengthWithText() { - $value = $this->guesser->guessMaxLength(self::CLASS_NAME, 'value'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'value'); - $this->assertNotNull($value); - $this->assertEquals(255, $value->getValue()); + $this->assertArrayHasKey('maxlength', $attributes); + $this->assertEquals(255, $attributes['maxlength']->getValue()); } public function testGuessMaxLengthWithFloat() { - $value = $this->guesser->guessMaxLength(self::CLASS_NAME, 'price'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); - $this->assertNotNull($value); - $this->assertNull($value->getValue()); + $this->assertArrayHasKey('maxlength', $attributes); + $this->assertEquals(null, $attributes['maxlength']->getValue()); } public function testGuessMinLengthWithText() { - $value = $this->guesser->guessPattern(self::CLASS_NAME, 'value'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); - $this->assertNull($value); + $this->assertArrayHasKey('maxlength', $attributes); + $this->assertEquals(null, $attributes['maxlength']->getValue()); } public function testGuessMinLengthWithFloat() { - $value = $this->guesser->guessPattern(self::CLASS_NAME, 'price'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); - $this->assertNotNull($value); - $this->assertNull($value->getValue()); + $this->assertArrayHasKey('maxlength', $attributes); + $this->assertEquals(null, $attributes['maxlength']->getValue()); } public function testGuessRequired() { - $value = $this->guesser->guessRequired(self::CLASS_NAME, 'id'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'id'); - $this->assertNotNull($value); - $this->assertTrue($value->getValue()); + $this->assertArrayHasKey('required', $attributes); + $this->assertEquals(true, $attributes['required']->getValue()); } public function testGuessRequiredWithNullableColumn() { - $value = $this->guesser->guessRequired(self::CLASS_NAME, 'value'); + $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'value'); - $this->assertNotNull($value); - $this->assertFalse($value->getValue()); + $this->assertArrayHasKey('required', $attributes); + $this->assertEquals(false, $attributes['required']->getValue()); } public function testGuessTypeWithoutTable() From 2236bb71c0c541e656a15acc515b7e6845c7ba1c Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Thu, 2 Jan 2014 21:53:19 +0100 Subject: [PATCH 10/20] Fixed CS --- .../Form/Extension/Validator/ValidatorTypeGuesser.php | 1 - src/Symfony/Component/Form/FormFactory.php | 2 +- src/Symfony/Component/Form/ResolvedFormType.php | 1 - .../Tests/Extension/Validator/ValidatorTypeGuesserTest.php | 4 ---- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 151e8848f7091..a8fa25d6d83e2 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -15,7 +15,6 @@ use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; -use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Constraint; diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index fae1d012f6c6c..3466fdf207059 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -24,7 +24,7 @@ class FormFactory implements FormFactoryInterface * @var ResolvedFormTypeFactoryInterface */ private $resolvedTypeFactory; - + protected $supportedAttributes = array( 'text' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), 'search' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index d63d3e7e60bf5..f8d87d0f97ae5 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -13,7 +13,6 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Core\Type as FormType; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 02d32b0106e08..d5cce93a6dc5e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -12,12 +12,8 @@ namespace Symfony\Component\Form\Tests\Extension\Validator; use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; -use Symfony\Component\Form\Guess\Guess; -use Symfony\Component\Form\ResolvedFormType; -use Symfony\Component\Form\Extension\Core\Type as FormType; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Range; -use Symfony\Component\Validator\Constraints\Type; /** * @author franek From 3174f8718f86c1f603d75e36db5b179407c0b1fd Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Fri, 3 Jan 2014 09:40:09 +0100 Subject: [PATCH 11/20] Cleaned up tests and db guesser implementation --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 26 +------------ .../Bridge/Propel1/Form/PropelTypeGuesser.php | 26 +------------ .../Validator/ValidatorTypeGuesser.php | 23 +++++------ src/Symfony/Component/Form/FormFactory.php | 18 +++++---- .../Component/Form/Tests/FormFactoryTest.php | 39 +++++++++++++++---- 5 files changed, 58 insertions(+), 74 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 4ddfaf4385b2c..7eb3a9bf99cb3 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -94,12 +94,8 @@ public function guessAttributes($class, $property) $attributes['maxlength'] = $guess; } - if ($guess = $this->guessMinValue($class, $property)) { - $attributes['min'] = $guess; - } - - if ($guess = $this->guessMaxValue($class, $property)) { - $attributes['max'] = $guess; + if ($guess = $this->guessPattern($class, $property)) { + $attributes['pattern'] = $guess; } return $attributes; @@ -164,24 +160,6 @@ protected function guessMaxLength($class, $property) } } - /** - * {@inheritDoc} - */ - protected function guessMinValue($class, $property) - { - // Unfortunately we can't guess anything from database - return null; - } - - /** - * {@inheritDoc} - */ - protected function guessMaxValue($class, $property) - { - // Unfortunately we can't guess anything from database - return null; - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index 1f23a088702b9..da77d83fc079d 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -122,12 +122,8 @@ public function guessAttributes($class, $property) $attributes['maxlength'] = $guess; } - if ($guess = $this->guessMinValue($class, $property)) { - $attributes['min'] = $guess; - } - - if ($guess = $this->guessMaxValue($class, $property)) { - $attributes['max'] = $guess; + if ($guess = $this->guessPattern($class, $property)) { + $attributes['pattern'] = $guess; } return $attributes; @@ -162,24 +158,6 @@ protected function guessMaxLength($class, $property) } } - /** - * {@inheritDoc} - */ - protected function guessMinValue($class, $property) - { - // Unfortunately we can't guess anything from database - return null; - } - - /** - * {@inheritDoc} - */ - protected function guessMaxValue($class, $property) - { - // Unfortunately we can't guess anything from database - return null; - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index a8fa25d6d83e2..e3deb4a6ef472 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -62,20 +62,21 @@ public function guessAttributes($class, $property) $attributes['max'] = $guess; } - return $attributes; - } - - private function addAttribute(array $attributes, $key, Guess $guess = null) - { - if (null === $guess) { - return $attributes; + if ($guess = $this->guessPattern($class, $property)) { + $attributes['pattern'] = $guess; } - if ($value = $guess->getValue()) { - return array_merge($attributes, array($key => $guess->getValue())); - } + return $attributes; } + /** + * Returns a guess whether a property of a class is required + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess A guess for the field's required setting + */ protected function guessRequired($class, $property) { $guesser = $this; @@ -273,7 +274,7 @@ public function guessRequiredForConstraint(Constraint $constraint) * * @return ValueGuess|null The guess for the maximum length */ - protected function guessMaxLengthForConstraint(Constraint $constraint) + public function guessMaxLengthForConstraint(Constraint $constraint) { switch (get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\Length': diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 3466fdf207059..dfecd0a671964 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -123,21 +123,23 @@ public function createBuilderForProperty($class, $property, $data = null, array $type = $typeGuess ? $typeGuess->getType() : 'text'; + // user options may override guessed options + if ($typeGuess) { + $options = array_merge($typeGuess->getOptions(), $options); + } + $filteredAttributes = array(); foreach ($guessedAttributes as $key => $value) { - if (isset($this->supportedAttributes[$type]) && in_array($key, $this->supportedAttributes[$type])) { + if (null !== $value->getValue() && isset($this->supportedAttributes[$type]) && in_array($key, $this->supportedAttributes[$type])) { $filteredAttributes[$key] = $value->getValue(); } } - $options = array_merge(array( - 'attr' => $filteredAttributes - ), $options); - - // user options may override guessed options - if ($typeGuess) { - $options = array_merge($typeGuess->getOptions(), $options); + if (count($filteredAttributes)) { + $options = array_merge(array( + 'attr' => $filteredAttributes + ), $options); } return $this->createNamedBuilder($property, $type, $data, $options); diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 349ffa26fb61a..7e82574e70d35 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -446,13 +446,13 @@ public function testCreateBuilderCreatesTextFormIfNoGuess() public function testOptionsCanBeOverridden() { $this->guesser1->expects($this->once()) - ->method('guessType') - ->with('Application\Author', 'firstName') - ->will($this->returnValue(new TypeGuess( - 'text', - array('attr' => array('maxlength' => 10)), - Guess::MEDIUM_CONFIDENCE - ))); + ->method('guessType') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(new TypeGuess( + 'text', + array('attr' => array('maxlength' => 10)), + Guess::MEDIUM_CONFIDENCE + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); @@ -673,6 +673,31 @@ public function testCreateBuilderUsesPatternIfFound() $this->assertEquals('builderInstance', $this->builder); } + public function testCreateBuilderWithNullAttribute() + { + $this->guesser1->expects($this->once()) + ->method('guessAttributes') + ->with('Application\Author', 'firstName') + ->will($this->returnValue(array('required' => new ValueGuess( + null, + Guess::MEDIUM_CONFIDENCE + )))); + + $factory = $this->getMockFactory(array('createNamedBuilder')); + + $factory->expects($this->once()) + ->method('createNamedBuilder') + ->with('firstName', 'text', null, array()) + ->will($this->returnValue('builderInstance')); + + $this->builder = $factory->createBuilderForProperty( + 'Application\Author', + 'firstName' + ); + + $this->assertEquals('builderInstance', $this->builder); + } + private function getMockFactory(array $methods = array()) { return $this->getMockBuilder('Symfony\Component\Form\FormFactory') From 2f48c3bfe4bd753f0af027cc4120bbf811275ee7 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Fri, 3 Jan 2014 10:13:44 +0100 Subject: [PATCH 12/20] Removed max_length and pattern from options --- .../Form/Extension/Core/Type/FormType.php | 2 -- .../Component/Form/FormFactoryInterface.php | 2 +- .../Extension/Core/Type/CollectionTypeTest.php | 17 ++++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index c66c7b3fb9058..674435dbef6e0 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -192,8 +192,6 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) 'trim' => true, 'required' => true, 'read_only' => false, - 'max_length' => null, - 'pattern' => null, 'property_path' => null, 'mapped' => true, 'by_reference' => true, diff --git a/src/Symfony/Component/Form/FormFactoryInterface.php b/src/Symfony/Component/Form/FormFactoryInterface.php index 31c46b55d7d29..46abd998757e0 100644 --- a/src/Symfony/Component/Form/FormFactoryInterface.php +++ b/src/Symfony/Component/Form/FormFactoryInterface.php @@ -93,7 +93,7 @@ public function createNamedBuilder($name, $type = 'form', $data = null, array $o /** * Returns a form builder for a property of a class. * - * If any of the 'max_length', 'required' and type options can be guessed, + * If any of the 'required' and type options can be guessed, * and are not provided in the options argument, the guessed value is used. * * @param string $class The fully qualified class name diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index 77be4b01e69c7..a2b94628bada4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -31,7 +31,7 @@ public function testSetDataAdjustsSize() $form = $this->factory->create('collection', null, array( 'type' => 'text', 'options' => array( - 'attr' => array('maxlength' => 20), + 'attr' => array('maxlength' => 20) ), )); $form->setData(array('foo@foo.com', 'foo@bar.com')); @@ -41,18 +41,21 @@ public function testSetDataAdjustsSize() $this->assertCount(2, $form); $this->assertEquals('foo@foo.com', $form[0]->getData()); $this->assertEquals('foo@bar.com', $form[1]->getData()); - $formAttrs0 = $form[0]->getConfig()->getOption('attr'); - $formAttrs1 = $form[1]->getConfig()->getOption('attr'); - $this->assertEquals(20, $formAttrs0['maxlength']); - $this->assertEquals(20, $formAttrs1['maxlength']); + + $attrsForm0 = $form[0]->getConfig()->getOption('attr'); + $attrsForm1 = $form[1]->getConfig()->getOption('attr'); + + $this->assertEquals(20, $attrsForm0['maxlength']); + $this->assertEquals(20, $attrsForm1['maxlength']); $form->setData(array('foo@baz.com')); $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]); $this->assertFalse(isset($form[1])); $this->assertCount(1, $form); $this->assertEquals('foo@baz.com', $form[0]->getData()); - $formAttrs0 = $form[0]->getConfig()->getOption('attr'); - $this->assertEquals(20, $formAttrs0['maxlength']); + + $attrsForm0 = $form[0]->getConfig()->getOption('attr'); + $this->assertEquals(20, $attrsForm0['maxlength']); } public function testThrowsExceptionIfObjectIsNotTraversable() From a194e477bf8fd7b603def31ae60c0adbfd288b72 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 4 Jan 2014 17:07:23 +0100 Subject: [PATCH 13/20] Removed old test for pattern and fixed renderWidget string --- src/Symfony/Component/Form/Tests/AbstractLayoutTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index dfd38fdc1be4d..eca512c6b242b 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -1921,7 +1921,7 @@ public function testWidgetAttributes() $html = $this->renderWidget($form->createView()); // compare plain HTML to check the whitespace - $this->assertSame('', $html); + $this->assertSame('', $html); } public function testWidgetAttributeNameRepeatedIfTrue() From 17ba7b7fbf3414b3736383d6f1e342b6a3fb28a3 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 4 Jan 2014 17:52:27 +0100 Subject: [PATCH 14/20] Removed required from attributes guessing --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 6 +--- .../Tests/Form/DoctrineOrmTypeGuesserTest.php | 4 +-- .../Bridge/Propel1/Form/PropelTypeGuesser.php | 6 +--- .../Tests/Form/PropelTypeGuesserTest.php | 12 +++---- .../Validator/ValidatorTypeGuesser.php | 13 ++------ src/Symfony/Component/Form/FormFactory.php | 33 +++++++++++-------- .../Component/Form/FormTypeGuesserChain.php | 10 ++++++ .../Form/FormTypeGuesserInterface.php | 10 ++++++ .../Validator/ValidatorTypeGuesserTest.php | 3 +- .../Component/Form/Tests/FormFactoryTest.php | 16 ++++----- 10 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 7eb3a9bf99cb3..ada8a4b313bf4 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -86,10 +86,6 @@ public function guessAttributes($class, $property) { $attributes = array(); - if ($guess = $this->guessRequired($class, $property)) { - $attributes['required'] = $guess; - } - if ($guess = $this->guessMaxLength($class, $property)) { $attributes['maxlength'] = $guess; } @@ -104,7 +100,7 @@ public function guessAttributes($class, $property) /** * {@inheritDoc} */ - protected function guessRequired($class, $property) + public function guessRequired($class, $property) { $classMetadatas = $this->getMetadata($class); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index 9ef51bb2009c9..0890c6aa25909 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -23,9 +23,7 @@ class DoctrineOrmTypeGuesserTest extends \PHPUnit_Framework_TestCase */ public function testRequiredGuesser($classMetadata, $expected) { - $attributes = $this->getGuesser($classMetadata)->guessAttributes('TestEntity', 'field'); - - $this->assertEquals($expected, isset($attributes['required']) ? $attributes['required'] : null); + $this->assertEquals($expected, $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } public function requiredProvider() diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index da77d83fc079d..96097c8d4d778 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -114,10 +114,6 @@ public function guessAttributes($class, $property) { $attributes = array(); - if ($guess = $this->guessRequired($class, $property)) { - $attributes['required'] = $guess; - } - if ($guess = $this->guessMaxLength($class, $property)) { $attributes['maxlength'] = $guess; } @@ -132,7 +128,7 @@ public function guessAttributes($class, $property) /** * {@inheritDoc} */ - protected function guessRequired($class, $property) + public function guessRequired($class, $property) { if ($column = $this->getColumn($class, $property)) { return new ValueGuess($column->isNotNull(), Guess::HIGH_CONFIDENCE); diff --git a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php index 5bf860189c66f..6942647cd2c64 100644 --- a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php +++ b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php @@ -62,18 +62,18 @@ public function testGuessMinLengthWithFloat() public function testGuessRequired() { - $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'id'); + $value = $this->guesser->guessRequired(self::CLASS_NAME, 'id'); - $this->assertArrayHasKey('required', $attributes); - $this->assertEquals(true, $attributes['required']->getValue()); + $this->assertNotNull($value); + $this->assertTrue($value->getValue()); } public function testGuessRequiredWithNullableColumn() { - $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'value'); + $value = $this->guesser->guessRequired(self::CLASS_NAME, 'value'); - $this->assertArrayHasKey('required', $attributes); - $this->assertEquals(false, $attributes['required']->getValue()); + $this->assertNotNull($value); + $this->assertFalse($value->getValue()); } public function testGuessTypeWithoutTable() diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index e3deb4a6ef472..c650239f21a02 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -46,10 +46,6 @@ public function guessAttributes($class, $property) { $attributes = array(); - if ($guess = $this->guessRequired($class, $property)) { - $attributes['required'] = $guess; - } - if ($guess = $this->guessMaxLength($class, $property)) { $attributes['maxlength'] = $guess; } @@ -70,14 +66,9 @@ public function guessAttributes($class, $property) } /** - * Returns a guess whether a property of a class is required - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess A guess for the field's required setting + * {@inheritDoc} */ - protected function guessRequired($class, $property) + public function guessRequired($class, $property) { $guesser = $this; diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index dfecd0a671964..e1851d8bf3bd6 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -26,19 +26,22 @@ class FormFactory implements FormFactoryInterface private $resolvedTypeFactory; protected $supportedAttributes = array( - 'text' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), - 'search' => array('autocomplete', 'dirname', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), - 'url' => array('autocomplete', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), - 'email' => array('autocomplete', 'list', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), - 'password' => array('autocomplete', 'maxlength', 'pattern', 'placeholder', 'readonly', 'required', 'size'), - 'date' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), - 'datetime' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), - 'time' => array('autocomplete', 'list', 'max', 'min', 'readonly', 'required', 'step'), - 'integer' => array('autocomplete', 'list', 'max', 'min', 'placeholder', 'readonly', 'required', 'step'), - 'decimal' => array('autocomplete', 'list', 'max', 'min', 'placeholder', 'readonly', 'required', 'step'), - 'range' => array('autocomplete', 'list', 'max', 'min', 'step'), - 'checkbox' => array('checked', 'required'), - 'file' => array('accept', 'multiple', 'required') + // rendered as input[type=text] + 'text' => array('maxlength', 'pattern'), + 'email' => array('maxlength', 'pattern'), + 'money' => array('maxlength', 'pattern'), + 'number' => array('maxlength', 'pattern'), + 'percent' => array('maxlength', 'pattern'), + // rendered as input[type=number] + 'integer' => array('max', 'min'), + // rendered as input[type=password] + 'password' => array('maxlength', 'pattern'), + // rendered as input[type=search] + 'search' => array('maxlength', 'pattern'), + // rendered as input[type=url] + 'url' => array('maxlength', 'pattern'), + // rendered as textarea + 'textarea' => array('maxlength'), ); public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory) @@ -123,6 +126,10 @@ public function createBuilderForProperty($class, $property, $data = null, array $type = $typeGuess ? $typeGuess->getType() : 'text'; + if ($requiredGuess = $guesser->guessRequired($class, $property)) { + $options = array_merge(array('required' => $requiredGuess->getValue()), $options); + } + // user options may override guessed options if ($typeGuess) { $options = array_merge($typeGuess->getOptions(), $options); diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index 5408132dc87e3..203f1829277ff 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -50,6 +50,16 @@ public function guessType($class, $property) }); } + /** + * {@inheritDoc} + */ + public function guessRequired($class, $property) + { + return $this->guess(function ($guesser) use ($class, $property) { + return $guesser->guessRequired($class, $property); + }); + } + /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index d9c58f6b7f619..872b10ed5f9b1 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -36,4 +36,14 @@ public function guessType($class, $property); * @return array An array of guesses for the field's attributes */ public function guessAttributes($class, $property); + + /** + * Returns a guess whether a property of a class is required + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess A guess for the field's required setting + */ + public function guessRequired($class, $property); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index d5cce93a6dc5e..b0e628fc63af7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -54,8 +54,7 @@ public function testGuessOptionsForConstraintWithMinLength() $result = $this->typeGuesser->guessAttributes($class, 'foo'); - $this->assertArrayHasKey('required', $result); - $this->assertFalse($result['required']->getValue()); + $this->assertFalse(isset($result['maxlength'])); } public function testGuessOptionsForConstraintWithMinValue() diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 7e82574e70d35..744f5e0d1627c 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -610,26 +610,26 @@ public function testMinAndMaxAttributesAreNotAddedToTextType() public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() { $this->guesser1->expects($this->once()) - ->method('guessAttributes') + ->method('guessRequired') ->with('Application\Author', 'firstName') - ->will($this->returnValue(array('required' => new ValueGuess( + ->will($this->returnValue(new ValueGuess( true, Guess::MEDIUM_CONFIDENCE - )))); + ))); $this->guesser2->expects($this->once()) - ->method('guessAttributes') + ->method('guessRequired') ->with('Application\Author', 'firstName') - ->will($this->returnValue(array('required' => new ValueGuess( + ->will($this->returnValue(new ValueGuess( false, Guess::HIGH_CONFIDENCE - )))); + ))); $factory = $this->getMockFactory(array('createNamedBuilder')); $factory->expects($this->once()) ->method('createNamedBuilder') - ->with('firstName', 'text', null, array('attr' => array('required' => false))) + ->with('firstName', 'text', null, array('required' => false)) ->will($this->returnValue('builderInstance')); $this->builder = $factory->createBuilderForProperty( @@ -678,7 +678,7 @@ public function testCreateBuilderWithNullAttribute() $this->guesser1->expects($this->once()) ->method('guessAttributes') ->with('Application\Author', 'firstName') - ->will($this->returnValue(array('required' => new ValueGuess( + ->will($this->returnValue(array('maxlength' => new ValueGuess( null, Guess::MEDIUM_CONFIDENCE )))); From e85639a1e74ed4b02f5d09ecb3738ffd9c00f18e Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 4 Jan 2014 18:20:26 +0100 Subject: [PATCH 15/20] Deprecated max_length and pattern options --- .../Tests/Form/DoctrineOrmTypeGuesserTest.php | 12 ++++++------ .../Form/Extension/Core/Type/FormType.php | 2 ++ .../Component/Form/FormTypeGuesserChain.php | 17 ++++++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index 0890c6aa25909..82c587aaffec1 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -32,21 +32,21 @@ public function requiredProvider() // Simple field, not nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(true)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true)); $classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(false)); $return[] = array($classMetadata, new ValueGuess(true, Guess::HIGH_CONFIDENCE)); // Simple field, nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(true)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true)); $classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(true)); $return[] = array($classMetadata, new ValueGuess(false, Guess::MEDIUM_CONFIDENCE)); // One-to-one, nullable (by default) $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array())); @@ -56,7 +56,7 @@ public function requiredProvider() // One-to-one, nullable (explicit) $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array('nullable'=>true))); @@ -66,7 +66,7 @@ public function requiredProvider() // One-to-one, not nullable $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true)); $mapping = array('joinColumns' => array(array('nullable'=>false))); @@ -76,7 +76,7 @@ public function requiredProvider() // One-to-many, no clue $classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock(); - $classMetadata->expects($this->any())->method('hasField')->with('field')->will($this->returnValue(false)); + $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false)); $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(false)); $return[] = array($classMetadata, null); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 674435dbef6e0..5c12d7dfd8ad3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -191,6 +191,8 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) 'empty_data' => $emptyData, 'trim' => true, 'required' => true, + 'max_length' => null, + 'pattern' => null, 'read_only' => false, 'property_path' => null, 'mapped' => true, diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index 203f1829277ff..7978ed7ca18b4 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -67,16 +67,19 @@ public function guessAttributes($class, $property) { $attributes = array(); + // Cleanup attributes if I get the same attribute from different guessers. foreach ($this->guessers as $guesser) { $guessedAttributes = $guesser->guessAttributes($class, $property); - if (is_array($guessedAttributes)) { - foreach ($guessedAttributes as $key => $value) { - if (isset($attributes[$key])) { - $attributes[$key] = Guess::getBestGuess(array($attributes[$key], $value)); - } else { - $attributes[$key] = $value; - } + if (false === is_array($guessedAttributes)) { + continue; + } + + foreach ($guessedAttributes as $key => $value) { + if (isset($attributes[$key])) { + $attributes[$key] = Guess::getBestGuess(array($attributes[$key], $value)); + } else { + $attributes[$key] = $value; } } } From 014f3e1c8d0b6fd1a4429e08eea63f9366ac1681 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sat, 4 Jan 2014 18:25:56 +0100 Subject: [PATCH 16/20] Added the changes to the CHANGELOG --- src/Symfony/Component/Form/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index c210f9e7924ac..3e9c73ef8c26a 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * [BC BREAK] added two optional parameters to FormInterface::getErrors() and changed the method to return a Symfony\Component\Form\FormErrorIterator instance instead of an array + * added the guessing of "min" and "max" attributes 2.4.0 ----- From 5a2488832a3a2629d4c3d342e9c3be9af5cd8794 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 5 Jan 2014 10:25:35 +0100 Subject: [PATCH 17/20] Changed visibility of methods for PR and fixed Docblock --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 24 +++++++++++++++---- .../Bridge/Propel1/Form/PropelTypeGuesser.php | 24 +++++++++++++++---- .../Validator/ValidatorTypeGuesser.php | 8 +++---- .../Form/FormTypeGuesserInterface.php | 2 +- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index ada8a4b313bf4..dd99a88fb9306 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -138,9 +138,14 @@ public function guessRequired($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's maximum length + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's maximum length */ - protected function guessMaxLength($class, $property) + public function guessMaxLength($class, $property) { $ret = $this->getMetadata($class); if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) { @@ -157,9 +162,20 @@ protected function guessMaxLength($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's pattern + * + * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below + * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. + * Example: + * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) + * @link https://github.com/symfony/symfony/pull/3927 + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's required pattern */ - protected function guessPattern($class, $property) + public function guessPattern($class, $property) { $ret = $this->getMetadata($class); if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) { diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index 96097c8d4d778..e9aab5d4a96ce 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -136,9 +136,14 @@ public function guessRequired($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's maximum length + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's maximum length */ - protected function guessMaxLength($class, $property) + public function guessMaxLength($class, $property) { if ($column = $this->getColumn($class, $property)) { if ($column->isText()) { @@ -155,9 +160,20 @@ protected function guessMaxLength($class, $property) } /** - * {@inheritDoc} + * Returns a guess about the field's pattern + * + * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below + * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. + * Example: + * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) + * @link https://github.com/symfony/symfony/pull/3927 + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's required pattern */ - protected function guessPattern($class, $property) + public function guessPattern($class, $property) { if ($column = $this->getColumn($class, $property)) { switch ($column->getType()) { diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index c650239f21a02..7685d3e7ce004 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -87,7 +87,7 @@ public function guessRequired($class, $property) * * @return Guess\ValueGuess|null A guess for the field's maximum length */ - protected function guessMaxLength($class, $property) + public function guessMaxLength($class, $property) { $guesser = $this; @@ -104,7 +104,7 @@ protected function guessMaxLength($class, $property) * * @return Guess\ValueGuess|null A guess for the field's maximum value */ - protected function guessMaxValue($class, $property) + public function guessMaxValue($class, $property) { $guesser = $this; @@ -121,7 +121,7 @@ protected function guessMaxValue($class, $property) * * @return Guess\ValueGuess|null A guess for the field's minimum value */ - protected function guessMinValue($class, $property) + public function guessMinValue($class, $property) { $guesser = $this; @@ -144,7 +144,7 @@ protected function guessMinValue($class, $property) * * @return Guess\ValueGuess|null A guess for the field's required pattern */ - protected function guessPattern($class, $property) + public function guessPattern($class, $property) { $guesser = $this; diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index 872b10ed5f9b1..ca430c846c0a2 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -33,7 +33,7 @@ public function guessType($class, $property); * @param string $property The name of the property to guess for * @param ResolvedFormTypeInterface $type Field's type * - * @return array An array of guesses for the field's attributes + * @return Guess\ValueGuess[] An array of guesses for the field's attributes */ public function guessAttributes($class, $property); From 14a4bd70aedd312d3b4a1ba893cfec66b14bcd8e Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 5 Jan 2014 12:42:23 +0100 Subject: [PATCH 18/20] Fixed coding style after review --- .../Tests/Form/PropelTypeGuesserTest.php | 6 +++--- .../Validator/ValidatorTypeGuesser.php | 17 +++++------------ src/Symfony/Component/Form/FormFactory.php | 2 +- .../Component/Form/FormTypeGuesserChain.php | 2 +- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php index 6942647cd2c64..9804e4534948f 100644 --- a/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php +++ b/src/Symfony/Bridge/Propel1/Tests/Form/PropelTypeGuesserTest.php @@ -41,7 +41,7 @@ public function testGuessMaxLengthWithFloat() $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); $this->assertArrayHasKey('maxlength', $attributes); - $this->assertEquals(null, $attributes['maxlength']->getValue()); + $this->assertNull($attributes['maxlength']->getValue()); } public function testGuessMinLengthWithText() @@ -49,7 +49,7 @@ public function testGuessMinLengthWithText() $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); $this->assertArrayHasKey('maxlength', $attributes); - $this->assertEquals(null, $attributes['maxlength']->getValue()); + $this->assertNull($attributes['maxlength']->getValue()); } public function testGuessMinLengthWithFloat() @@ -57,7 +57,7 @@ public function testGuessMinLengthWithFloat() $attributes = $this->guesser->guessAttributes(self::CLASS_NAME, 'price'); $this->assertArrayHasKey('maxlength', $attributes); - $this->assertEquals(null, $attributes['maxlength']->getValue()); + $this->assertNull($attributes['maxlength']->getValue()); } public function testGuessRequired() diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 7685d3e7ce004..6bdf1fa4a782b 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -17,6 +17,7 @@ use Symfony\Component\Form\Guess\ValueGuess; use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\Range; class ValidatorTypeGuesser implements FormTypeGuesserInterface { @@ -299,12 +300,8 @@ public function guessMaxLengthForConstraint(Constraint $constraint) */ public function guessMaxValueForConstraint(Constraint $constraint) { - switch (get_class($constraint)) { - case 'Symfony\Component\Validator\Constraints\Range': - if (is_numeric($constraint->max)) { - return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE); - } - break; + if ($constraint instanceof Range && is_numeric($constraint->max)) { + return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE); } return null; @@ -319,12 +316,8 @@ public function guessMaxValueForConstraint(Constraint $constraint) */ public function guessMinValueForConstraint(Constraint $constraint) { - switch (get_class($constraint)) { - case 'Symfony\Component\Validator\Constraints\Range': - if (is_numeric($constraint->min)) { - return new ValueGuess($constraint->min, Guess::HIGH_CONFIDENCE); - } - break; + if ($constraint instanceof Range && is_numeric($constraint->min)) { + return new ValueGuess($constraint->min, Guess::HIGH_CONFIDENCE); } return null; diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index e1851d8bf3bd6..55fd1bb0df3ea 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -143,7 +143,7 @@ public function createBuilderForProperty($class, $property, $data = null, array } } - if (count($filteredAttributes)) { + if (!empty($filteredAttributes)) { $options = array_merge(array( 'attr' => $filteredAttributes ), $options); diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index 7978ed7ca18b4..ab979870391f5 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -71,7 +71,7 @@ public function guessAttributes($class, $property) foreach ($this->guessers as $guesser) { $guessedAttributes = $guesser->guessAttributes($class, $property); - if (false === is_array($guessedAttributes)) { + if (!is_array($guessedAttributes)) { continue; } From 5b804c36e6ae4492c353fc8cd0a3e4d02eed43cd Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 5 Jan 2014 14:09:26 +0100 Subject: [PATCH 19/20] Fixed BC in FormTypeGuesserInterface --- .../Component/Form/FormTypeGuesserChain.php | 20 ++++++++ .../Form/FormTypeGuesserInterface.php | 48 +++++++++++++++---- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php index ab979870391f5..0b29c58a7cd2e 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserChain.php +++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php @@ -60,6 +60,26 @@ public function guessRequired($class, $property) }); } + /** + * {@inheritDoc} + */ + public function guessMaxLength($class, $property) + { + return $this->guess(function ($guesser) use ($class, $property) { + return $guesser->guessMaxLength($class, $property); + }); + } + + /** + * {@inheritDoc} + */ + public function guessPattern($class, $property) + { + return $this->guess(function ($guesser) use ($class, $property) { + return $guesser->guessPattern($class, $property); + }); + } + /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index ca430c846c0a2..2550d8017005d 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -27,23 +27,53 @@ interface FormTypeGuesserInterface public function guessType($class, $property); /** - * Returns an array of guessed attributes + * Returns a guess whether a property of a class is required * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param ResolvedFormTypeInterface $type Field's type + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for * - * @return Guess\ValueGuess[] An array of guesses for the field's attributes + * @return Guess\ValueGuess A guess for the field's required setting */ - public function guessAttributes($class, $property); + public function guessRequired($class, $property); /** - * Returns a guess whether a property of a class is required + * Returns a guess about the field's maximum length * * @param string $class The fully qualified class name * @param string $property The name of the property to guess for * - * @return Guess\ValueGuess A guess for the field's required setting + * @return Guess\ValueGuess|null A guess for the field's maximum length + * + * @deprecated since 2.5, to be removed in 3.0. Use guessAttributes() instead. */ - public function guessRequired($class, $property); + public function guessMaxLength($class, $property); + + /** + * Returns a guess about the field's pattern + * + * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below + * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. + * Example: + * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) + * @link https://github.com/symfony/symfony/pull/3927 + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * + * @return Guess\ValueGuess|null A guess for the field's required pattern + * + * @deprecated since 2.5, to be removed in 3.0. Use guessAttributes() instead. + */ + public function guessPattern($class, $property); + + /** + * Returns an array of guessed attributes + * + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param ResolvedFormTypeInterface $type Field's type + * + * @return Guess\ValueGuess[] An array of guesses for the field's attributes + */ + public function guessAttributes($class, $property); } From 0c94ac27d4c8a43f9c0a17a49e89bb52f2a0f084 Mon Sep 17 00:00:00 2001 From: Stefano Sala Date: Sun, 5 Jan 2014 20:16:43 +0100 Subject: [PATCH 20/20] Replaced docblock with {@inheritDoc} --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 20 ++----------------- .../Bridge/Propel1/Form/PropelTypeGuesser.php | 20 ++----------------- .../Validator/ValidatorTypeGuesser.php | 20 ++----------------- 3 files changed, 6 insertions(+), 54 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index dd99a88fb9306..468ebd1166a7b 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -138,12 +138,7 @@ public function guessRequired($class, $property) } /** - * Returns a guess about the field's maximum length - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's maximum length + * {@inheritDoc} */ public function guessMaxLength($class, $property) { @@ -162,18 +157,7 @@ public function guessMaxLength($class, $property) } /** - * Returns a guess about the field's pattern - * - * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below - * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. - * Example: - * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) - * @link https://github.com/symfony/symfony/pull/3927 - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's required pattern + * {@inheritDoc} */ public function guessPattern($class, $property) { diff --git a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php index e9aab5d4a96ce..7632159182e6a 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelTypeGuesser.php @@ -136,12 +136,7 @@ public function guessRequired($class, $property) } /** - * Returns a guess about the field's maximum length - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's maximum length + * {@inheritDoc} */ public function guessMaxLength($class, $property) { @@ -160,18 +155,7 @@ public function guessMaxLength($class, $property) } /** - * Returns a guess about the field's pattern - * - * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below - * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. - * Example: - * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) - * @link https://github.com/symfony/symfony/pull/3927 - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's required pattern + * {@inheritDoc} */ public function guessPattern($class, $property) { diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 6bdf1fa4a782b..e43d02f5f5d49 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -81,12 +81,7 @@ public function guessRequired($class, $property) } /** - * Returns a guess about the field's maximum length - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's maximum length + * {@inheritDoc} */ public function guessMaxLength($class, $property) { @@ -132,18 +127,7 @@ public function guessMinValue($class, $property) } /** - * Returns a guess about the field's pattern - * - * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below - * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. - * Example: - * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) - * @link https://github.com/symfony/symfony/pull/3927 - * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * - * @return Guess\ValueGuess|null A guess for the field's required pattern + * {@inheritDoc} */ public function guessPattern($class, $property) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy