Skip to content

Commit

Permalink
Merge pull request #752 from Ener-Getick/SF3
Browse files Browse the repository at this point in the history
Add symfony 3.0 support
  • Loading branch information
willdurand committed Dec 4, 2015
2 parents 97707ea + 0461f5c commit 1df3ddf
Show file tree
Hide file tree
Showing 30 changed files with 515 additions and 137 deletions.
40 changes: 13 additions & 27 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 10 additions & 3 deletions Extractor/ApiDocExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
Expand Down
8 changes: 4 additions & 4 deletions Extractor/Handler/FosRestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
));
}
Expand Down
3 changes: 2 additions & 1 deletion Form/Extension/DescriptionFormTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -61,6 +62,6 @@ public function configureOptions(OptionsResolver $resolver)
*/
public function getExtendedType()
{
return 'form';
return LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\FormType');
}
}
131 changes: 106 additions & 25 deletions Parser/FormTypeParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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)) {
Expand All @@ -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,
);
Expand All @@ -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(),
);
}
Expand Down Expand Up @@ -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);
}
}

Expand Down
10 changes: 7 additions & 3 deletions Parser/ValidationParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</service>

<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 id="nelmio_api_doc.twig.extension.extra_markdown" class="%nelmio_api_doc.twig.extension.extra_markdown.class%">
Expand Down

0 comments on commit 1df3ddf

Please sign in to comment.