Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactored guess options to guess attributes and added a mapping for …
…form types supported attributes
  • Loading branch information
Stefano Sala committed Mar 31, 2014
commit cd2661d2822cbc1c6e32b8eacac94897c3114c86
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
74 changes: 25 additions & 49 deletions src/Symfony/Component/Form/FormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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) {
Expand All @@ -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.
Expand Down
56 changes: 15 additions & 41 deletions src/Symfony/Component/Form/FormTypeGuesserChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/Symfony/Component/Form/FormTypeGuesserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guess\ValueGuess[]

*/
public function guessOptions($class, $property, ResolvedFormTypeInterface $type);
public function guessAttributes($class, $property);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removal of guessMaxLength() + guessPattern() from interface is BC break.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know. What do you suggest?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik, it's not a BC break as it doesn't fail when you have an extra method in the interface (as long as you keep the 2 methods in the core classes as a BC layer).

The BC break is adding guessAttributes and guessRequired to the interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC old methods must be still in interface, but with @deprecated phpdoc with note (for details look around code, there is plenty of examples), adding new ones to interface is as BC break too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that ok or should I remove the new method too?

}
18 changes: 0 additions & 18 deletions src/Symfony/Component/Form/ResolvedFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
8 changes: 0 additions & 8 deletions src/Symfony/Component/Form/ResolvedFormTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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)
Expand Down
Loading