diff --git a/.travis.yml b/.travis.yml
index 1aac7ae14..db767fcf5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,42 +6,28 @@ cache:
directories:
- $HOME/.composer/cache
-php:
- - 5.4
- - 5.5
- - 5.6
- - nightly
- - hhvm
-
-env:
- global:
- - SYMFONY_DEPRECATIONS_HELPER=weak
-
matrix:
include:
- - php: 5.6
+ - php: 5.4
env: SYMFONY_VERSION=2.3.*
+ - php: 5.5
- php: 5.6
- env: SYMFONY_VERSION=2.4.*
- - php: 5.6
- env: SYMFONY_VERSION=2.6.*
- - php: 5.6
- env: SYMFONY_VERSION=2.7.*
+ env: SYMFONY_VERSION=2.7.* COVERAGE=true
- php: 5.6
- env: SYMFONY_VERSION=2.8.*@dev
+ env: SYMFONY_VERSION=2.8.*
- php: 5.6
- env: SYMFONY_VERSION="3.0.x-dev as 2.8"
- allow_failures:
- - php: nightly
- - env: SYMFONY_VERSION=2.8.*@dev
- - env: SYMFONY_VERSION="3.0.x-dev as 2.8"
+ env: SYMFONY_VERSION=3.0.* DEPENDENCIES=dev COMPOSER_FLAGS="--prefer-stable"
+ - php: 7.0
+ - php: hhvm
fast_finish: true
before_script:
+ - if [ "$COVERAGE" != "true" ] && [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then phpenv config-rm xdebug.ini; fi
- 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 [ "$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 [ "$DEPENDENCIES" = "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi;
+ - if [ "$SYMFONY_VERSION" != "3.0.*" ] && [ "$SYMFONY_VERSION" != "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;
- - composer install
+ - composer update $COMPOSER_FLAGS
-script: phpunit --coverage-text
+script:
+ - if [ "$COVERAGE" == "true" ]; then phpunit --coverage-text; else phpunit; fi
diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php
index fde2c1282..904dc9005 100644
--- a/Extractor/ApiDocExtractor.php
+++ b/Extractor/ApiDocExtractor.php
@@ -218,10 +218,17 @@ public function getReflectionMethod($controller)
}
if ($this->container->has($controller)) {
- $this->container->enterScope('request');
- $this->container->set('request', new Request(), 'request');
+ // BC SF < 3.0
+ 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)));
- $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')) {
$method = '__invoke';
}
diff --git a/Extractor/Handler/FosRestHandler.php b/Extractor/Handler/FosRestHandler.php
index 1fe3659e2..7c22694d2 100644
--- a/Extractor/Handler/FosRestHandler.php
+++ b/Extractor/Handler/FosRestHandler.php
@@ -33,7 +33,7 @@ public function handle(ApiDoc $annotation, array $annotations, Route $route, \Re
$requirements = $this->handleRequirements($annot->requirements);
$data = array(
'required' => $annot->strict && $annot->nullable === false && $annot->default === null,
- 'dataType' => $requirements.($annot->array ? '[]' : ''),
+ 'dataType' => $requirements.((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'actualType' => $this->inferType($requirements),
'subType' => null,
'description' => $annot->description,
@@ -46,19 +46,19 @@ public function handle(ApiDoc $annotation, array $annotations, Route $route, \Re
} elseif ($annot instanceof QueryParam) {
if ($annot->strict && $annot->nullable === false && $annot->default === null) {
$annotation->addRequirement($annot->name, array(
- 'requirement' => $this->handleRequirements($annot->requirements).($annot->array ? '[]' : ''),
+ 'requirement' => $this->handleRequirements($annot->requirements).((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'dataType' => '',
'description' => $annot->description,
));
} elseif ($annot->default !== null) {
$annotation->addFilter($annot->name, array(
- 'requirement' => $this->handleRequirements($annot->requirements).($annot->array ? '[]' : ''),
+ 'requirement' => $this->handleRequirements($annot->requirements).((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'description' => $annot->description,
'default' => $annot->default,
));
} else {
$annotation->addFilter($annot->name, array(
- 'requirement' => $this->handleRequirements($annot->requirements).($annot->array ? '[]' : ''),
+ 'requirement' => $this->handleRequirements($annot->requirements).((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'description' => $annot->description,
));
}
diff --git a/Form/Extension/DescriptionFormTypeExtension.php b/Form/Extension/DescriptionFormTypeExtension.php
index 80c218d13..6bcf0415c 100644
--- a/Form/Extension/DescriptionFormTypeExtension.php
+++ b/Form/Extension/DescriptionFormTypeExtension.php
@@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Form\Extension;
+use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
@@ -61,6 +62,6 @@ public function configureOptions(OptionsResolver $resolver)
*/
public function getExtendedType()
{
- return 'form';
+ return LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\FormType');
}
}
diff --git a/Parser/FormTypeParser.php b/Parser/FormTypeParser.php
index dfcc0b8ea..d324d9548 100644
--- a/Parser/FormTypeParser.php
+++ b/Parser/FormTypeParser.php
@@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Parser;
use Nelmio\ApiDocBundle\DataTypes;
+use Nelmio\ApiDocBundle\Util\LegacyFormHelper;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
@@ -44,6 +45,8 @@ class FormTypeParser implements ParserInterface
/**
* @var array
+ *
+ * @deprecated since 2.12, to be removed in 3.0. Use $extendedMapTypes instead.
*/
protected $mapTypes = array(
'text' => DataTypes::STRING,
@@ -59,6 +62,53 @@ class FormTypeParser implements ParserInterface
'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)
{
$this->formFactory = $formFactory;
@@ -94,13 +144,28 @@ public function parse(array $item)
$type = $item['class'];
$options = $item['options'];
- if ($this->implementsType($type)) {
- $type = $this->getTypeInstance($type);
+ try {
+ $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)) {
return $this->parseForm($form);
@@ -129,6 +194,14 @@ public function parse(array $item)
);
}
+ private function getDataType($type) {
+ foreach ($this->extendedMapTypes as $data => $types) {
+ if (in_array($type, $types)) {
+ return $data;
+ }
+ }
+ }
+
private function parseForm($form)
{
$parameters = array();
@@ -147,24 +220,27 @@ private function parseForm($form)
$typeName = method_exists($type, 'getBlockPrefix') ?
$type->getBlockPrefix() : $type->getName();
- if (isset($this->mapTypes[$typeName])) {
- $bestType = $this->mapTypes[$typeName];
- $actualType = $bestType;
+ $dataType = $this->getDataType($typeName);
+ if (null !== $dataType) {
+ $actualType = $bestType = $dataType;
} 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)) {
$typeOption = method_exists($typeOption, 'getBlockPrefix') ?
$typeOption->getBlockPrefix() : $typeOption->getName();
}
- if (isset($this->mapTypes[$typeOption])) {
- $subType = $this->mapTypes[$typeOption];
+ $dataType = $this->getDataType($typeOption);
+ if (null !== $dataType) {
+ $subType = $dataType;
$actualType = DataTypes::COLLECTION;
$bestType = sprintf('array of %ss', $subType);
} else {
// 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()));
$children = $this->parseForm($subForm);
$actualType = DataTypes::COLLECTION;
@@ -190,7 +266,16 @@ private function parseForm($form)
*/
$addDefault = false;
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);
if (!empty($subParameters)) {
@@ -206,7 +291,7 @@ private function parseForm($form)
'default' => null,
'subType' => $subType,
'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(),
'children' => $children,
);
@@ -224,7 +309,7 @@ private function parseForm($form)
'actualType' => 'string',
'default' => $config->getData(),
'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(),
);
}
@@ -321,20 +406,16 @@ private function getTypeInstance($type)
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)) {
- $type = $this->getTypeInstance($item);
-
- return $this->formFactory->create($type, $data, $options);
+ try {
+ return $this->formFactory->create($type, null, $options);
+ } catch(InvalidArgumentException $exception) {
}
- try {
- return $this->formFactory->create($item, $data, $options);
- } catch (UnexpectedTypeException $e) {
- // nothing
- } catch (InvalidArgumentException $e) {
- // nothing
+ if (!LegacyFormHelper::hasBCBreaks() && !isset($form) && $this->implementsType($type)) {
+ $type = $this->getTypeInstance($type);
+ return $this->formFactory->create($type, null, $options);
}
}
diff --git a/Parser/ValidationParser.php b/Parser/ValidationParser.php
index ec64618e4..e24f201ca 100644
--- a/Parser/ValidationParser.php
+++ b/Parser/ValidationParser.php
@@ -13,7 +13,8 @@
use Nelmio\ApiDocBundle\DataTypes;
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\Constraints\Type;
@@ -45,10 +46,13 @@ class ValidationParser implements ParserInterface, PostParserInterface
/**
* 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;
}
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 3b5bfcad6..552584d69 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -37,7 +37,7 @@
-
+