Add symfony 3.0 support

This commit is contained in:
Ener-Getick 2015-11-30 19:19:17 +01:00
parent 97707ea5f4
commit 67b7b46627
29 changed files with 504 additions and 112 deletions

View File

@ -20,7 +20,7 @@ env:
matrix: matrix:
include: include:
- php: 5.6 - php: 5.6
env: SYMFONY_VERSION=2.3.* env: COMPOSER_FLAGS="--prefer-lowest"
- php: 5.6 - php: 5.6
env: SYMFONY_VERSION=2.4.* env: SYMFONY_VERSION=2.4.*
- php: 5.6 - php: 5.6
@ -28,20 +28,20 @@ matrix:
- php: 5.6 - php: 5.6
env: SYMFONY_VERSION=2.7.* env: SYMFONY_VERSION=2.7.*
- php: 5.6 - php: 5.6
env: SYMFONY_VERSION=2.8.*@dev env: SYMFONY_VERSION=2.8.*@dev SYMFONY_DEPRECATIONS_HELPER=strict
- php: 5.6 - php: 5.6
env: SYMFONY_VERSION="3.0.x-dev as 2.8" env: SYMFONY_VERSION=3.0.* DEPENDENCIES=dev COMPOSER_FLAGS="--prefer-stable" SYMFONY_DEPRECATIONS_HELPER=strict
allow_failures: allow_failures:
- php: nightly - php: nightly
- env: SYMFONY_VERSION=2.8.*@dev - env: SYMFONY_VERSION=2.8.*@dev
- env: SYMFONY_VERSION="3.0.x-dev as 2.8" - env: SYMFONY_VERSION=3.0.*
fast_finish: true fast_finish: true
before_script: before_script:
- composer self-update - composer self-update
- if [ "$SYMFONY_VERSION" = "2.8.*@dev" ] || [ "$SYMFONY_VERSION" = "3.0.x-dev as 2.8" ]; then SYMFONY_DEPRECATIONS_HELPER=strict; fi; - if [ "$DEPENDENCIES" = "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi;
- if [ "$SYMFONY_VERSION" != "3.0.x-dev as 2.8" ] && [ "$SYMFONY_VERSION" != "2.7.*" ]; then sed -i "/dunglas\/api-bundle/d;/symfony\/serializer/d" composer.json; fi; - if [ "$SYMFONY_VERSION" != "3.0.x-dev as 2.8" ] && [ "$SYMFONY_VERSION" != "2.7.*" ]; then sed -i "/dunglas\/api-bundle/d;/symfony\/serializer/d" composer.json; fi;
- if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi; - if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
- composer install - composer update $COMPOSER_FLAGS
script: phpunit --coverage-text script: phpunit --coverage-text

View File

@ -218,10 +218,17 @@ class ApiDocExtractor
} }
if ($this->container->has($controller)) { if ($this->container->has($controller)) {
$this->container->enterScope('request'); // BC SF < 3.0
$this->container->set('request', new Request(), 'request'); if (method_exists($this->container, 'enterScope')) {
$this->container->enterScope('request');
$this->container->set('request', new Request(), 'request');
}
$class = ClassUtils::getRealClass(get_class($this->container->get($controller))); $class = ClassUtils::getRealClass(get_class($this->container->get($controller)));
$this->container->leaveScope('request'); // BC SF < 3.0
if (method_exists($this->container, 'enterScope')) {
$this->container->leaveScope('request');
}
if (!isset($method) && method_exists($class, '__invoke')) { if (!isset($method) && method_exists($class, '__invoke')) {
$method = '__invoke'; $method = '__invoke';
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Form\Extension; namespace Nelmio\ApiDocBundle\Form\Extension;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
@ -61,6 +62,6 @@ class DescriptionFormTypeExtension extends AbstractTypeExtension
*/ */
public function getExtendedType() public function getExtendedType()
{ {
return 'form'; return LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\FormType');
} }
} }

View File

@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Parser; namespace Nelmio\ApiDocBundle\Parser;
use Nelmio\ApiDocBundle\DataTypes; use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\Exception\FormException; use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\UnexpectedTypeException;
@ -44,6 +45,8 @@ class FormTypeParser implements ParserInterface
/** /**
* @var array * @var array
*
* @deprecated since 2.12, to be removed in 3.0. Use $extendedMapTypes instead.
*/ */
protected $mapTypes = array( protected $mapTypes = array(
'text' => DataTypes::STRING, 'text' => DataTypes::STRING,
@ -59,6 +62,53 @@ class FormTypeParser implements ParserInterface
'file' => DataTypes::FILE, 'file' => DataTypes::FILE,
); );
/**
* @var array
*/
protected $extendedMapTypes = array(
DataTypes::STRING => array(
'text',
'Symfony\Component\Form\Extension\Core\Type\TextType',
'textarea',
'Symfony\Component\Form\Extension\Core\Type\TextareaType',
'country',
'Symfony\Component\Form\Extension\Core\Type\CountryType',
),
DataTypes::DATE => array(
'date',
'Symfony\Component\Form\Extension\Core\Type\DateType',
),
DataTypes::DATETIME => array(
'datetime',
'Symfony\Component\Form\Extension\Core\Type\DatetimeType',
),
DataTypes::BOOLEAN => array(
'checkbox',
'Symfony\Component\Form\Extension\Core\Type\CheckboxType',
),
DataTypes::TIME => array(
'time',
'Symfony\Component\Form\Extension\Core\Type\TimeType',
),
DataTypes::FLOAT => array(
'number',
'Symfony\Component\Form\Extension\Core\Type\NumberType',
),
DataTypes::INTEGER => array(
'integer',
'Symfony\Component\Form\Extension\Core\Type\IntegerType',
),
DataTypes::ENUM => array(
'choice',
'Symfony\Component\Form\Extension\Core\Type\ChoiceType',
),
DataTypes::FILE => array(
'file',
'Symfony\Component\Form\Extension\Core\Type\FileType',
),
);
public function __construct(FormFactoryInterface $formFactory, $entityToChoice) public function __construct(FormFactoryInterface $formFactory, $entityToChoice)
{ {
$this->formFactory = $formFactory; $this->formFactory = $formFactory;
@ -94,13 +144,28 @@ class FormTypeParser implements ParserInterface
$type = $item['class']; $type = $item['class'];
$options = $item['options']; $options = $item['options'];
if ($this->implementsType($type)) { try {
$type = $this->getTypeInstance($type); $form = $this->formFactory->create($type, null, $options);
}
// TODO: find a better exception to catch
catch (\Exception $exception) {
if (!LegacyFormHelper::isLegacy()) {
@trigger_error('Using FormTypeInterface instance with required arguments without defining them as service is deprecated in symfony 2.8 and removed in 3.0.', E_USER_DEPRECATED);
}
} }
$form = $this->formFactory->create($type, null, $options); if(!isset($form)) {
if (!LegacyFormHelper::hasBCBreaks() && $this->implementsType($type)) {
$type = $this->getTypeInstance($type);
$form = $this->formFactory->create($type, null, $options);
} else {
throw new \InvalidArgumentException('Unsupported form type class.');
}
}
$name = array_key_exists('name', $item) ? $item['name'] : $form->getName(); $name = array_key_exists('name', $item)
? $item['name']
: (method_exists($form, 'getBlockPrefix') ? $form->getBlockPrefix() : $form->getName());
if (empty($name)) { if (empty($name)) {
return $this->parseForm($form); return $this->parseForm($form);
@ -129,6 +194,14 @@ class FormTypeParser implements ParserInterface
); );
} }
private function getDataType($type) {
foreach ($this->extendedMapTypes as $data => $types) {
if (in_array($type, $types)) {
return $data;
}
}
}
private function parseForm($form) private function parseForm($form)
{ {
$parameters = array(); $parameters = array();
@ -147,24 +220,27 @@ class FormTypeParser implements ParserInterface
$typeName = method_exists($type, 'getBlockPrefix') ? $typeName = method_exists($type, 'getBlockPrefix') ?
$type->getBlockPrefix() : $type->getName(); $type->getBlockPrefix() : $type->getName();
if (isset($this->mapTypes[$typeName])) { $dataType = $this->getDataType($typeName);
$bestType = $this->mapTypes[$typeName]; if (null !== $dataType) {
$actualType = $bestType; $actualType = $bestType = $dataType;
} elseif ('collection' === $typeName) { } elseif ('collection' === $typeName) {
$typeOption = $config->getOption('type'); // BC sf < 2.8
$typeOption = $config->hasOption('entry_type') ? $config->getOption('entry_type') : $config->getOption('type');
if (is_object($typeOption)) { if (is_object($typeOption)) {
$typeOption = method_exists($typeOption, 'getBlockPrefix') ? $typeOption = method_exists($typeOption, 'getBlockPrefix') ?
$typeOption->getBlockPrefix() : $typeOption->getName(); $typeOption->getBlockPrefix() : $typeOption->getName();
} }
if (isset($this->mapTypes[$typeOption])) { $dataType = $this->getDataType($typeOption);
$subType = $this->mapTypes[$typeOption]; if (null !== $dataType) {
$subType = $dataType;
$actualType = DataTypes::COLLECTION; $actualType = DataTypes::COLLECTION;
$bestType = sprintf('array of %ss', $subType); $bestType = sprintf('array of %ss', $subType);
} else { } else {
// Embedded form collection // Embedded form collection
$embbededType = $config->getOption('type'); // BC sf < 2.8
$embbededType = $config->hasOption('entry_type') ? $config->getOption('entry_type') : $config->getOption('type');
$subForm = $this->formFactory->create($embbededType, null, $config->getOption('options', array())); $subForm = $this->formFactory->create($embbededType, null, $config->getOption('options', array()));
$children = $this->parseForm($subForm); $children = $this->parseForm($subForm);
$actualType = DataTypes::COLLECTION; $actualType = DataTypes::COLLECTION;
@ -190,7 +266,16 @@ class FormTypeParser implements ParserInterface
*/ */
$addDefault = false; $addDefault = false;
try { try {
$subForm = $this->formFactory->create($type, null, $options); if (LegacyFormHelper::hasBCBreaks()) {
try {
$subForm = $this->formFactory->create(get_class($type), null, $options);
} catch (\Exception $e) {
}
}
if (!isset($subForm)) {
$subForm = $this->formFactory->create($type, null, $options);
}
$subParameters = $this->parseForm($subForm, $name); $subParameters = $this->parseForm($subForm, $name);
if (!empty($subParameters)) { if (!empty($subParameters)) {
@ -206,7 +291,7 @@ class FormTypeParser implements ParserInterface
'default' => null, 'default' => null,
'subType' => $subType, 'subType' => $subType,
'required' => $config->getRequired(), 'required' => $config->getRequired(),
'description' => ($config->getOption('description')) ? $config->getOption('description'):$config->getOption('label'), 'description' => ($config->getOption('description')) ? $config->getOption('description') : $config->getOption('label'),
'readonly' => $config->getDisabled(), 'readonly' => $config->getDisabled(),
'children' => $children, 'children' => $children,
); );
@ -224,7 +309,7 @@ class FormTypeParser implements ParserInterface
'actualType' => 'string', 'actualType' => 'string',
'default' => $config->getData(), 'default' => $config->getData(),
'required' => $config->getRequired(), 'required' => $config->getRequired(),
'description' => ($config->getOption('description')) ? $config->getOption('description'):$config->getOption('label'), 'description' => ($config->getOption('description')) ? $config->getOption('description') : $config->getOption('label'),
'readonly' => $config->getDisabled(), 'readonly' => $config->getDisabled(),
); );
} }
@ -321,20 +406,16 @@ class FormTypeParser implements ParserInterface
return $refl->newInstance(); return $refl->newInstance();
} }
private function createForm($item, $data = null, array $options = array()) private function createForm($type, $data = null, array $options = array())
{ {
if ($this->implementsType($item)) { try {
$type = $this->getTypeInstance($item); return $this->formFactory->create($type, null, $options);
} catch(InvalidArgumentException $exception) {
return $this->formFactory->create($type, $data, $options);
} }
try { if (!LegacyFormHelper::hasBCBreaks() && !isset($form) && $this->implementsType($type)) {
return $this->formFactory->create($item, $data, $options); $type = $this->getTypeInstance($type);
} catch (UnexpectedTypeException $e) { return $this->formFactory->create($type, null, $options);
// nothing
} catch (InvalidArgumentException $e) {
// nothing
} }
} }

View File

@ -13,7 +13,8 @@ namespace Nelmio\ApiDocBundle\Parser;
use Nelmio\ApiDocBundle\DataTypes; use Nelmio\ApiDocBundle\DataTypes;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\MetadataFactoryInterface as LegacyMetadataFactoryInterface;
use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Type; use Symfony\Component\Validator\Constraints\Type;
@ -45,10 +46,13 @@ class ValidationParser implements ParserInterface, PostParserInterface
/** /**
* Requires a validation MetadataFactory. * Requires a validation MetadataFactory.
* *
* @param MetadataFactoryInterface $factory * @param MetadataFactoryInterface|LegacyMetadataFactoryInterface $factory
*/ */
public function __construct(MetadataFactoryInterface $factory) public function __construct($factory)
{ {
if (!($factory instanceof MetadataFactoryInterface) && !($factory instanceof LegacyMetadataFactoryInterface)) {
throw new \InvalidArgumentException('Argument 1 of %s constructor must be either an instance of Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface or Symfony\Component\Validator\MetadataFactoryInterface.');
}
$this->factory = $factory; $this->factory = $factory;
} }

View File

@ -37,7 +37,7 @@
</service> </service>
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%"> <service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">
<tag name="form.type_extension" alias="form" /> <tag name="form.type_extension" alias="form" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
</service> </service>
<service id="nelmio_api_doc.twig.extension.extra_markdown" class="%nelmio_api_doc.twig.extension.extra_markdown.class%"> <service id="nelmio_api_doc.twig.extension.extra_markdown" class="%nelmio_api_doc.twig.extension.extra_markdown.class%">

View File

@ -14,6 +14,9 @@ namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller;
use FOS\RestBundle\Controller\Annotations\QueryParam; use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\RequestParam; use FOS\RestBundle\Controller\Annotations\RequestParam;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Tests\Fixtures\DependencyTypePath;
use Nelmio\ApiDocBundle\Tests\Fixtures\RequestParamHelper;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\Email;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
@ -114,7 +117,7 @@ class TestController
* @ApiDoc( * @ApiDoc(
* views= { "default", "test" }, * views= { "default", "test" },
* description="create another test", * description="create another test",
* input="dependency_type" * input=DependencyTypePath::TYPE
* ) * )
*/ */
public function anotherPostAction() public function anotherPostAction()
@ -166,7 +169,7 @@ class TestController
/** /**
* @ApiDoc( * @ApiDoc(
* description="Testing return", * description="Testing return",
* output="dependency_type" * output=DependencyTypePath::TYPE
* ) * )
*/ */
public function jmsReturnTestAction() public function jmsReturnTestAction()
@ -191,7 +194,7 @@ class TestController
/** /**
* @ApiDoc() * @ApiDoc()
* @RequestParam(name="param1", requirements="string", array=true) * @RequestParamHelper(name="param1", requirements="string", array=true)
*/ */
public function zActionWithArrayRequestParamAction() public function zActionWithArrayRequestParamAction()
{ {

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Fixtures;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
/**
* This class is used to have dynamic annotations for BC.
* {@see Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController}
*
* @author Ener-Getick <egetick@gmail.com>
*/
if (LegacyFormHelper::isLegacy()) {
class DependencyTypePath
{
const TYPE = 'dependency_type';
}
} else {
class DependencyTypePath
{
const TYPE = 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType';
}
}

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface;
@ -22,14 +23,30 @@ class CollectionType extends AbstractType
*/ */
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$collectionType = 'Symfony\Component\Form\Extension\Core\Type\CollectionType';
$builder $builder
->add('a', 'collection', array('type' => 'text')) ->add('a', LegacyFormHelper::getType($collectionType), array(
->add('b', 'collection', array('type' => new TestType())) LegacyFormHelper::hasBCBreaks() ? 'entry_type' : 'type' => LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\TextType')
))
->add('b', LegacyFormHelper::getType($collectionType), array(
LegacyFormHelper::hasBCBreaks() ? 'entry_type' : 'type' => LegacyFormHelper::isLegacy() ? new TestType() : __NAMESPACE__.'\TestType'
))
; ;
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return 'collection_type'; return 'collection_type';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -24,18 +25,24 @@ class CompoundType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('sub_form', new SimpleType()) ->add('sub_form', LegacyFormHelper::isLegacy() ? new SimpleType() : __NAMESPACE__.'\SimpleType')
->add('a', 'number') ->add('a', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\NumberType'))
; ;
} }
/** /**
* Returns the name of this type. * BC SF < 2.8
* * {@inheritdoc}
* @return string The name of this type
*/ */
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return ''; return '';
} }
} }

View File

@ -54,8 +54,19 @@ class DependencyType extends AbstractType
return; return;
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return 'dependency_type'; return 'dependency_type';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -43,11 +44,22 @@ class EntityType extends AbstractType
public function getParent() public function getParent()
{ {
return 'choice'; return LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\ChoiceType');
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return 'entity'; return 'entity';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -24,19 +25,35 @@ class ImprovedTestType extends AbstractType
*/ */
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$choiceType = LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\ChoiceType');
$datetimeType = LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\DateTimeType');
$dateType = LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\DateType');
$builder $builder
->add('dt1', 'datetime', array('widget' => 'single_text', 'description' => 'A nice description')) ->add('dt1', $datetimeType, array('widget' => 'single_text', 'description' => 'A nice description'))
->add('dt2', 'datetime', array('date_format' => 'M/d/y')) ->add('dt2', $datetimeType, array('date_format' => 'M/d/y'))
->add('dt3', 'datetime', array('widget' => 'single_text', 'format' => 'M/d/y H:i:s')) ->add('dt3', $datetimeType, array('widget' => 'single_text', 'format' => 'M/d/y H:i:s'))
->add('dt4', 'datetime', array('date_format' => \IntlDateFormatter::MEDIUM)) ->add('dt4', $datetimeType, array('date_format' => \IntlDateFormatter::MEDIUM))
->add('dt5', 'datetime', array('format' => 'M/d/y H:i:s')) ->add('dt5', $datetimeType, array('format' => 'M/d/y H:i:s'))
->add('d1', 'date', array('format' => \IntlDateFormatter::MEDIUM)) ->add('d1', $dateType, array('format' => \IntlDateFormatter::MEDIUM))
->add('d2', 'date', array('format' => 'd-M-y')) ->add('d2', $dateType, array('format' => 'd-M-y'))
->add('c1', 'choice', array('choices' => array('m' => 'Male', 'f' => 'Female'))) ->add('c1', $choiceType, array_merge(
->add('c2', 'choice', array('choices' => array('m' => 'Male', 'f' => 'Female'), 'multiple' => true)) array('choices' => array('m' => 'Male', 'f' => 'Female')), LegacyFormHelper::isLegacy() ? array() : array('choices_as_values' => true)
->add('c3', 'choice', array('choices' => array())) ))
->add('c4', 'choice', array('choices' => array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz')))) ->add('c2', $choiceType, array_merge(
->add('e1', new EntityType(), array('choice_list' => new SimpleChoiceList(array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz'))))) array('choices' => array('m' => 'Male', 'f' => 'Female'), 'multiple' => true),
LegacyFormHelper::isLegacy() ? array() : array('choices_as_values' => true)
))
->add('c3', $choiceType, array('choices' => array()))
->add('c4', $choiceType, array_merge(
array('choices' => array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz'))),
LegacyFormHelper::isLegacy() ? array() : array('choices_as_values' => true)
))
->add('e1', LegacyFormHelper::isLegacy() ? new EntityType() : __NAMESPACE__.'\EntityType',
LegacyFormHelper::isLegacy()
? array('choice_list' => new SimpleChoiceList(array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz'))))
: array('choices' => array('foo' => 'bar', 'bazgroup' => array('baz' => 'Buzz')), 'choices_as_values' => true)
)
; ;
} }
@ -62,8 +79,19 @@ class ImprovedTestType extends AbstractType
return; return;
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return ''; return '';
} }
} }

View File

@ -60,8 +60,19 @@ class RequireConstructionType extends AbstractType
return; return;
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return 'require_construction_type'; return 'require_construction_type';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -23,16 +24,22 @@ class RequiredType extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder->add('required_field', 'text', array('required' => true)); $builder->add('required_field', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\TextType'), array('required' => true));
} }
/** /**
* Returns the name of this type. * BC SF < 2.8
* * {@inheritdoc}
* @return string The name of this type
*/ */
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return ''; return '';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -23,26 +24,33 @@ class SimpleType extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder->add('a', 'text', array( $builder->add('a', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\TextType'), array(
'description' => 'Something that describes A.', 'description' => 'Something that describes A.',
)) ))
->add('b', 'number') ->add('b', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\NumberType'))
->add('c', 'choice', array( ->add('c', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\ChoiceType'), array_merge(
'choices' => array('x' => 'X', 'y' => 'Y', 'z' => 'Z'), array('choices' => array('x' => 'X', 'y' => 'Y', 'z' => 'Z')),
LegacyFormHelper::isLegacy() ? array() : array('choices_as_values' => true)
)) ))
->add('d', 'datetime') ->add('d', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\DateTimeType'))
->add('e', 'date') ->add('e', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\DateType'))
->add('g', 'textarea') ->add('g', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\TextareaType'))
; ;
} }
/** /**
* Returns the name of this type. * BC SF < 2.8
* * {@inheritdoc}
* @return string The name of this type
*/ */
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return 'simple'; return 'simple';
} }
} }

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Form;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
@ -26,8 +27,8 @@ class TestType extends AbstractType
$builder $builder
->add('a', null, array('description' => 'A nice description')) ->add('a', null, array('description' => 'A nice description'))
->add('b') ->add('b')
->add($builder->create('c', 'checkbox')) ->add($builder->create('c', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\CheckboxType')))
->add('d','text',array( 'data' => 'DefaultTest')) ->add('d', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\TextType'),array( 'data' => 'DefaultTest'))
; ;
} }
@ -53,8 +54,19 @@ class TestType extends AbstractType
return; return;
} }
/**
* BC SF < 2.8
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix() {
return ''; return '';
} }
} }

View File

@ -0,0 +1,29 @@
<?php
namespace Nelmio\ApiDocBundle\Tests\Fixtures;
use FOS\RestBundle\Controller\Annotations\RequestParam;
/**
* For BC FOSRestBundle < 2.0
*
* @Annotation
* @Target("METHOD")
*
* @author Ener-Getick
*/
class RequestParamHelper extends RequestParam {
public function __construct(array $data) {
foreach ($data as $key => $value) {
if ($key === 'array') {
if (property_exists($this, 'map')) {
$this->map = $value;
} else {
$this->array = $value;
}
} else {
$this->$key = $value;
}
}
}
}

View File

@ -59,6 +59,11 @@ class AppKernel extends Kernel
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) { if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$loader->load(__DIR__.'/config/dunglas_api.yml'); $loader->load(__DIR__.'/config/dunglas_api.yml');
} }
// If symfony/framework-bundle > 3.0
if (!class_exists('Symfony\Bundle\FrameworkBundle\Command\RouterApacheDumperCommand')) {
$loader->load(__DIR__.'/config/twig_assets.yml');
}
} }
public function serialize() public function serialize()

View File

@ -189,7 +189,7 @@ test_route_update_another_resource:
_format: json|xml|html _format: json|xml|html
swagger_doc: swagger_doc:
resource: @NelmioApiDocBundle/Resources/config/swagger_routing.yml resource: "@NelmioApiDocBundle/Resources/config/swagger_routing.yml"
prefix: /api-docs prefix: /api-docs
test_route_23: test_route_23:

View File

@ -0,0 +1,2 @@
framework:
assets: ~

View File

@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Tests\Formatter; namespace Nelmio\ApiDocBundle\Tests\Formatter;
use Nelmio\ApiDocBundle\Tests\WebTestCase; use Nelmio\ApiDocBundle\Tests\WebTestCase;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
class MarkdownFormatterTest extends WebTestCase class MarkdownFormatterTest extends WebTestCase
{ {
@ -27,6 +28,9 @@ class MarkdownFormatterTest extends WebTestCase
$suffix = class_exists('Dunglas\ApiBundle\DunglasApiBundle') ? '' : '-no-dunglas'; $suffix = class_exists('Dunglas\ApiBundle\DunglasApiBundle') ? '' : '-no-dunglas';
$expected = file_get_contents(__DIR__ . '/testFormat-result' . $suffix . '.markdown'); $expected = file_get_contents(__DIR__ . '/testFormat-result' . $suffix . '.markdown');
if (LegacyFormHelper::isLegacy()) {
$expected = str_replace('DependencyType', 'dependency_type', $expected);
}
$this->assertEquals($expected, $result . "\n"); $this->assertEquals($expected, $result . "\n");
} }

View File

@ -477,7 +477,7 @@ _create another test_
dependency_type: dependency_type:
* type: object (dependency_type) * type: object (DependencyType)
* required: true * required: true
dependency_type[a]: dependency_type[a]:
@ -610,7 +610,7 @@ _Testing return_
dependency_type: dependency_type:
* type: object (dependency_type) * type: object (DependencyType)
dependency_type[a]: dependency_type[a]:

View File

@ -1,5 +1,7 @@
<?php <?php
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
return array ( return array (
'/api/other-resources' => '/api/other-resources' =>
array ( array (
@ -1174,9 +1176,11 @@ With multiple lines.',
'readonly' => false, 'readonly' => false,
'description' => '', 'description' => '',
'default' => NULL, 'default' => NULL,
'dataType' => 'object (dependency_type)', 'dataType' => 'object ('.
(LegacyFormHelper::isLegacy() ? 'dependency_type' : 'DependencyType')
.')',
'actualType' => 'model', 'actualType' => 'model',
'subType' => 'dependency_type', 'subType' => LegacyFormHelper::isLegacy() ? 'dependency_type' : 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType',
'children' => 'children' =>
array ( array (
'a' => 'a' =>
@ -1526,9 +1530,11 @@ With multiple lines.',
'readonly' => false, 'readonly' => false,
'description' => '', 'description' => '',
'default' => NULL, 'default' => NULL,
'dataType' => 'object (dependency_type)', 'dataType' => 'object ('.
(LegacyFormHelper::isLegacy() ? 'dependency_type' : 'DependencyType')
.')',
'actualType' => 'model', 'actualType' => 'model',
'subType' => 'dependency_type', 'subType' => LegacyFormHelper::isLegacy() ? 'dependency_type' : 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType',
'children' => 'children' =>
array ( array (
'a' => 'a' =>

View File

@ -561,7 +561,7 @@ _create another test_
dependency_type: dependency_type:
* type: object (dependency_type) * type: object (DependencyType)
* required: true * required: true
dependency_type[a]: dependency_type[a]:
@ -694,7 +694,7 @@ _Testing return_
dependency_type: dependency_type:
* type: object (dependency_type) * type: object (DependencyType)
dependency_type[a]: dependency_type[a]:

View File

@ -1,5 +1,7 @@
<?php <?php
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
return array ( return array (
'/api/other-resources' => '/api/other-resources' =>
array ( array (
@ -1167,9 +1169,11 @@ With multiple lines.',
'readonly' => false, 'readonly' => false,
'description' => '', 'description' => '',
'default' => NULL, 'default' => NULL,
'dataType' => 'object (dependency_type)', 'dataType' => 'object ('.
(LegacyFormHelper::isLegacy() ? 'dependency_type' : 'DependencyType')
.')',
'actualType' => 'model', 'actualType' => 'model',
'subType' => 'dependency_type', 'subType' => LegacyFormHelper::isLegacy() ? 'dependency_type' : 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType',
'children' => 'children' =>
array ( array (
'a' => 'a' =>
@ -1518,9 +1522,11 @@ With multiple lines.',
'readonly' => false, 'readonly' => false,
'description' => '', 'description' => '',
'default' => NULL, 'default' => NULL,
'dataType' => 'object (dependency_type)', 'dataType' => 'object ('.
(LegacyFormHelper::isLegacy() ? 'dependency_type' : 'DependencyType')
.')',
'actualType' => 'model', 'actualType' => 'model',
'subType' => 'dependency_type', 'subType' => LegacyFormHelper::isLegacy() ? 'dependency_type' : 'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType',
'children' => 'children' =>
array ( array (
'a' => 'a' =>

View File

@ -15,6 +15,8 @@ use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension; use Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension;
use Nelmio\ApiDocBundle\Parser\FormTypeParser; use Nelmio\ApiDocBundle\Parser\FormTypeParser;
use Nelmio\ApiDocBundle\Tests\Fixtures; use Nelmio\ApiDocBundle\Tests\Fixtures;
use Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType;
use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\Extension\Core\CoreExtension; use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactory;
@ -28,6 +30,34 @@ class FormTypeParserTest extends \PHPUnit_Framework_TestCase
*/ */
public function testParse($typeName, $expected) public function testParse($typeName, $expected)
{ {
$resolvedTypeFactory = new ResolvedFormTypeFactory();
$formFactoryBuilder = new FormFactoryBuilder();
$formFactoryBuilder->setResolvedTypeFactory($resolvedTypeFactory);
$formFactoryBuilder->addExtension(new CoreExtension());
$formFactoryBuilder->addTypeExtension(new DescriptionFormTypeExtension());
$formFactoryBuilder->addType(new DependencyType(array('foo')));
$formFactory = $formFactoryBuilder->getFormFactory();
$formTypeParser = new FormTypeParser($formFactory, $entityToChoice = true);
set_error_handler(array('Nelmio\ApiDocBundle\Tests\WebTestCase', 'handleDeprecation'));
trigger_error('test', E_USER_DEPRECATED);
$output = $formTypeParser->parse($typeName);
restore_error_handler();
$this->assertEquals($expected, $output);
}
/**
* Checks that we can still use FormType with required arguments without defining them as services.
* @dataProvider dataTestParse
*/
public function testLegacyParse($typeName, $expected)
{
if(LegacyFormHelper::hasBCBreaks()) {
$this->markTestSkipped('Not supported on symfony 3.0.');
}
$resolvedTypeFactory = new ResolvedFormTypeFactory(); $resolvedTypeFactory = new ResolvedFormTypeFactory();
$formFactoryBuilder = new FormFactoryBuilder(); $formFactoryBuilder = new FormFactoryBuilder();
$formFactoryBuilder->setResolvedTypeFactory($resolvedTypeFactory); $formFactoryBuilder->setResolvedTypeFactory($resolvedTypeFactory);
@ -55,6 +85,7 @@ class FormTypeParserTest extends \PHPUnit_Framework_TestCase
$formFactoryBuilder->setResolvedTypeFactory($resolvedTypeFactory); $formFactoryBuilder->setResolvedTypeFactory($resolvedTypeFactory);
$formFactoryBuilder->addExtension(new CoreExtension()); $formFactoryBuilder->addExtension(new CoreExtension());
$formFactoryBuilder->addTypeExtension(new DescriptionFormTypeExtension()); $formFactoryBuilder->addTypeExtension(new DescriptionFormTypeExtension());
$formFactoryBuilder->addType(new DependencyType(array('bar')));
$formFactory = $formFactoryBuilder->getFormFactory(); $formFactory = $formFactoryBuilder->getFormFactory();
$formTypeParser = new FormTypeParser($formFactory, $entityToChoice = false); $formTypeParser = new FormTypeParser($formFactory, $entityToChoice = false);
@ -79,14 +110,17 @@ class FormTypeParserTest extends \PHPUnit_Framework_TestCase
protected function expectedData($entityToChoice) protected function expectedData($entityToChoice)
{ {
$entityData = array( $entityData = array_merge(
'dataType' => 'choice', array(
'actualType' => DataTypes::ENUM, 'dataType' => 'choice',
'subType' => null, 'actualType' => DataTypes::ENUM,
'default' => null, 'subType' => null,
'required' => true, 'default' => null,
'description' => '', 'required' => true,
'readonly' => false 'description' => '',
'readonly' => false,
),
LegacyFormHelper::isLegacy() ? array() : array('format' => '{"foo":"bar","bazgroup":{"baz":"Buzz"}}',)
); );
return array( return array(

65
Util/LegacyFormHelper.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Util;
/**
* Extracted from FOSUserBundle.
*
* @internal
*/
final class LegacyFormHelper
{
private static $map = array(
'Symfony\Component\Form\Extension\Core\Type\FormType' => 'form',
// Tests
'Symfony\Component\Form\Extension\Core\Type\CollectionType' => 'collection',
'Symfony\Component\Form\Extension\Core\Type\NumberType' => 'number',
'Symfony\Component\Form\Extension\Core\Type\DateTimeType' => 'datetime',
'Symfony\Component\Form\Extension\Core\Type\DateType' => 'date',
'Symfony\Component\Form\Extension\Core\Type\ChoiceType' => 'choice',
'Symfony\Component\Form\Extension\Core\Type\TextType' => 'text',
'Symfony\Component\Form\Extension\Core\Type\TextareaType' => 'textarea',
'Symfony\Component\Form\Extension\Core\Type\CheckboxType' => 'checkbox',
'Nelmio\ApiDocBundle\Tests\Fixtures\Form\DependencyType' => 'dependency_type',
);
public static function getType($class)
{
if (!self::isLegacy()) {
return $class;
}
if (!isset(self::$map[$class])) {
throw new \InvalidArgumentException(sprintf('Form type with class "%s" can not be found. Please check for typos or add it to the map in LegacyFormHelper', $class));
}
return self::$map[$class];
}
public static function isLegacy()
{
return !method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix');
}
public static function hasBCBreaks()
{
return !method_exists('Symfony\Component\Form\AbstractType', 'setDefaultOptions');
}
private function __construct()
{
}
private function __clone()
{
}
}

View File

@ -16,9 +16,9 @@
], ],
"require": { "require": {
"php": ">=5.3", "php": ">=5.3",
"symfony/twig-bundle": "~2.3", "symfony/twig-bundle": "~2.3|~3.0",
"symfony/framework-bundle": "~2.3", "symfony/framework-bundle": "~2.3|~3.0",
"symfony/console": "~2.3", "symfony/console": "~2.3|~3.0",
"michelf/php-markdown": "~1.4" "michelf/php-markdown": "~1.4"
}, },
"conflict": { "conflict": {
@ -27,20 +27,20 @@
"twig/twig": "<1.12" "twig/twig": "<1.12"
}, },
"require-dev": { "require-dev": {
"symfony/css-selector": "~2.3", "symfony/css-selector": "~2.3|~3.0",
"symfony/browser-kit": "~2.3", "symfony/browser-kit": "~2.3|~3.0",
"symfony/validator": "~2.3", "symfony/validator": "~2.3|~3.0",
"symfony/yaml": "~2.3", "symfony/yaml": "~2.3|~3.0",
"symfony/form": "~2.3", "symfony/form": "~2.3|~3.0",
"symfony/finder": "~2.3", "symfony/finder": "~2.3|~3.0",
"symfony/serializer": "~2.7", "symfony/serializer": "~2.7|~3.0",
"doctrine/orm": "~2.3", "doctrine/orm": "~2.3",
"doctrine/doctrine-bundle": "~1.5", "doctrine/doctrine-bundle": "~1.5",
"friendsofsymfony/rest-bundle": "~1.0", "friendsofsymfony/rest-bundle": "~1.0|~2.0",
"jms/serializer-bundle": ">=0.11", "jms/serializer-bundle": ">=0.11",
"dunglas/api-bundle": "~1.0@dev", "dunglas/api-bundle": "~1.0@dev",
"sensio/framework-extra-bundle": "~3.0", "sensio/framework-extra-bundle": "~3.0",
"symfony/phpunit-bridge": "~2.7" "symfony/phpunit-bridge": "~2.7|~3.0"
}, },
"suggest": { "suggest": {
"symfony/form": "For using form definitions as input.", "symfony/form": "For using form definitions as input.",