diff --git a/Parser/FormTypeParser.php b/Parser/FormTypeParser.php index 87dc9e8..be98b10 100644 --- a/Parser/FormTypeParser.php +++ b/Parser/FormTypeParser.php @@ -13,6 +13,8 @@ namespace Nelmio\ApiDocBundle\Parser; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\InvalidArgumentException; +use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface; +use Symfony\Component\Form\Extension\Core\View\ChoiceView; use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\Exception\FormException; @@ -42,6 +44,7 @@ class FormTypeParser implements ParserInterface 'integer' => 'int', 'textarea' => 'string', 'country' => 'string', + 'choice' => 'choice', ); public function __construct(FormFactoryInterface $formFactory) @@ -153,6 +156,37 @@ class FormTypeParser implements ParserInterface 'description' => $config->getAttribute('description'), 'readonly' => $config->getDisabled(), ); + + switch ($bestType) { + case 'datetime': + if (($format = $config->getOption('date_format')) && is_string($format)) { + $parameters[$name]['format'] = $format; + } elseif ('single_text' == $config->getOption('widget') && $format = $config->getOption('format')) { + $parameters[$name]['format'] = $format; + } + break; + + case 'date': + if (($format = $config->getOption('format')) && is_string($format)) { + $parameters[$name]['format'] = $format; + } + break; + + case 'choice': + if ($config->getOption('multiple')) { + $parameters[$name]['dataType'] = sprintf('array of %ss', $parameters[$name]['dataType']); + } + + if (($choices = $config->getOption('choices')) && is_array($choices) && count($choices)) { + $parameters[$name]['format'] = json_encode($choices); + } elseif (($choiceList = $config->getOption('choice_list')) && $choiceList instanceof ChoiceListInterface) { + $choices = $this->handleChoiceListValues($choiceList); + if (is_array($choices) && count($choices)) { + $parameters[$name]['format'] = json_encode($choices); + } + } + break; + } } return $parameters; @@ -188,4 +222,24 @@ class FormTypeParser implements ParserInterface // nothing } } + + private function handleChoiceListValues(ChoiceListInterface $choiceList) { + $choices = array(); + foreach (array($choiceList->getPreferredViews(), $choiceList->getRemainingViews()) as $viewList) { + $choices = array_merge($choices, $this->handleChoiceViewsHierarchy($viewList)); + } + return $choices; + } + + private function handleChoiceViewsHierarchy(array $choiceViews) { + $choices = array(); + foreach ($choiceViews as $item) { + if ($item instanceof ChoiceView) { + $choices[$item->value] = $item->label; + } elseif (is_array($item)) { + $choices = array_merge($choices, $this->handleChoiceViewsHierarchy($item)); + } + } + return $choices; + } } diff --git a/Tests/Fixtures/Form/ImprovedTestType.php b/Tests/Fixtures/Form/ImprovedTestType.php new file mode 100644 index 0000000..2ab4773 --- /dev/null +++ b/Tests/Fixtures/Form/ImprovedTestType.php @@ -0,0 +1,56 @@ +add('dt1', 'datetime', array('widget' => 'single_text', 'description' => 'A nice description')) + ->add('dt2', 'datetime', array('date_format' => 'M/d/y')) + ->add('dt3', 'datetime', array('widget' => 'single_text', 'format' => 'M/d/y H:i:s')) + ->add('dt4', 'datetime', array('date_format' => \IntlDateFormatter::MEDIUM)) + ->add('dt5', 'datetime', array('format' => 'M/d/y H:i:s')) + ->add('d1', 'date', array('format' => \IntlDateFormatter::MEDIUM)) + ->add('d2', 'date', array('format' => 'd-M-y')) + ->add('c1', 'choice', array('choices' => array('m' => 'Male', 'f' => 'Female'))) + ->add('c2', 'choice', array('choices' => array('m' => 'Male', 'f' => 'Female'), 'multiple' => true)) + ->add('c3', 'choice', array('choices' => array())) + ->add('c4', 'choice', array('choice_list' => new SimpleChoiceList(array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz'))))) + ; + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'data_class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\ImprovedTest', + )); + + return; + } + + public function getName() + { + return ''; + } +} + diff --git a/Tests/Fixtures/Model/ImprovedTest.php b/Tests/Fixtures/Model/ImprovedTest.php new file mode 100644 index 0000000..2339276 --- /dev/null +++ b/Tests/Fixtures/Model/ImprovedTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model; + +use Symfony\Component\Validator\Constraints as Assert; + +class ImprovedTest +{ + public $dt1; + public $dt2; + public $dt3; + public $dt4; + public $dt5; + public $d1; + public $d2; + public $c1; + public $c2; + public $c3; + public $c4; +} diff --git a/Tests/Parser/FormTypeParserTest.php b/Tests/Parser/FormTypeParserTest.php index 4bfc66f..eb7bdb0 100644 --- a/Tests/Parser/FormTypeParserTest.php +++ b/Tests/Parser/FormTypeParserTest.php @@ -5,6 +5,7 @@ use Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension; use Nelmio\ApiDocBundle\Parser\FormTypeParser; use Nelmio\ApiDocBundle\Tests\Fixtures; use Symfony\Component\Form\Extension\Core\CoreExtension; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Form\ResolvedFormTypeFactory; @@ -147,6 +148,84 @@ class FormTypeParserTest extends \PHPUnit_Framework_TestCase ) ) ), + array( + array('class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\ImprovedTestType'), + array( + 'dt1' => array( + 'dataType' => 'datetime', + 'required' => true, + 'description' => 'A nice description', + 'readonly' => false, + 'format' => DateTimeType::HTML5_FORMAT, + ), + 'dt2' => array( + 'dataType' => 'datetime', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => 'M/d/y', + ), + 'dt3' => array( + 'dataType' => 'datetime', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => 'M/d/y H:i:s', + ), + 'dt4' => array( + 'dataType' => 'datetime', + 'required' => true, + 'description' => '', + 'readonly' => false, + ), + 'dt5' => array( + 'dataType' => 'datetime', + 'required' => true, + 'description' => '', + 'readonly' => false, + ), + 'd1' => array( + 'dataType' => 'date', + 'required' => true, + 'description' => '', + 'readonly' => false, + ), + 'd2' => array( + 'dataType' => 'date', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => 'd-M-y', + ), + 'c1' => array( + 'dataType' => 'choice', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => json_encode(array('m' => 'Male', 'f' => 'Female')), + ), + 'c2' => array( + 'dataType' => 'array of choices', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => json_encode(array('m' => 'Male', 'f' => 'Female')), + ), + 'c3' => array( + 'dataType' => 'choice', + 'required' => true, + 'description' => '', + 'readonly' => false, + ), + 'c4' => array( + 'dataType' => 'choice', + 'required' => true, + 'description' => '', + 'readonly' => false, + 'format' => json_encode(array('foo' => 'bar', 'baz' => 'Buzz')), + ), + ) + ), ); } }