From b022f6b2196d4077d44754c1dfd5c2cd92e8ea44 Mon Sep 17 00:00:00 2001 From: Lucas dos Santos Abreu Date: Fri, 2 Oct 2020 13:52:30 -0300 Subject: [PATCH 1/7] (feat): add utf-8 charset to response `swagger-ui-bundle` is very sensible to encoding changes because of the RegExp performed. ensuring UTF-8 on the response prevents end-user config to break it. the annotations already needs to be UTF-8 compatible to generate the JSON, so it should not break users applications. --- Controller/SwaggerUiController.php | 4 +++- Tests/Functional/SwaggerUiTest.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Controller/SwaggerUiController.php b/Controller/SwaggerUiController.php index 8c88e3b..5fc979a 100644 --- a/Controller/SwaggerUiController.php +++ b/Controller/SwaggerUiController.php @@ -65,10 +65,12 @@ final class SwaggerUiController $spec['basePath'] = $request->getBaseUrl(); } - return new Response( + $response = new Response( $this->twig->render('@NelmioApiDoc/SwaggerUi/index.html.twig', ['swagger_data' => ['spec' => $spec]]), Response::HTTP_OK, ['Content-Type' => 'text/html'] ); + + return $response->setCharset('UTF-8'); } } diff --git a/Tests/Functional/SwaggerUiTest.php b/Tests/Functional/SwaggerUiTest.php index 0ed8ce5..0b32453 100644 --- a/Tests/Functional/SwaggerUiTest.php +++ b/Tests/Functional/SwaggerUiTest.php @@ -33,6 +33,7 @@ class SwaggerUiTest extends WebTestCase $response = $this->client->getResponse(); $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('UTF-8', $response->getCharset()); $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); $expected = $this->getSwaggerDefinition()->toArray(); From 0912c85a0dc80bf910356daac33c9df59c40f7b7 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Fri, 20 Nov 2020 17:06:56 +0100 Subject: [PATCH 2/7] Improve error when the items type of an array is not specified --- Exception/UndocumentedArrayItemsException.php | 42 +++++++++++++++++++ ModelDescriber/ObjectModelDescriber.php | 11 ++++- PropertyDescriber/ArrayPropertyDescriber.php | 13 +++++- Tests/Functional/ArrayItemsErrorTest.php | 37 ++++++++++++++++ Tests/Functional/BazingaFunctionalTest.php | 2 +- .../Controller/ArrayItemsErrorController.php | 35 ++++++++++++++++ .../Functional/Entity/ArrayItemsError/Bar.php | 25 +++++++++++ .../Functional/Entity/ArrayItemsError/Foo.php | 30 +++++++++++++ Tests/Functional/JMSFunctionalTest.php | 2 +- Tests/Functional/TestKernel.php | 30 +++++++------ 10 files changed, 210 insertions(+), 17 deletions(-) create mode 100644 Exception/UndocumentedArrayItemsException.php create mode 100644 Tests/Functional/ArrayItemsErrorTest.php create mode 100644 Tests/Functional/Controller/ArrayItemsErrorController.php create mode 100644 Tests/Functional/Entity/ArrayItemsError/Bar.php create mode 100644 Tests/Functional/Entity/ArrayItemsError/Foo.php diff --git a/Exception/UndocumentedArrayItemsException.php b/Exception/UndocumentedArrayItemsException.php new file mode 100644 index 0000000..570642f --- /dev/null +++ b/Exception/UndocumentedArrayItemsException.php @@ -0,0 +1,42 @@ +class = $class; + $this->path = $path; + + $propertyName = ''; + if (null !== $class) { + $propertyName = $class.'::'; + } + $propertyName .= $path; + + parent::__construct(sprintf('Property "%s" is an array, but its items type isn\'t specified. You can specify that by using the type `string[]` for instance or `@SWG\Property(type="array", @SWG\Items(type="string"))`.', $propertyName)); + } + + public function getClass() + { + return $this->class; + } + + public function getPath() + { + return $this->path; + } +} diff --git a/ModelDescriber/ObjectModelDescriber.php b/ModelDescriber/ObjectModelDescriber.php index 7a4a269..6350bfc 100644 --- a/ModelDescriber/ObjectModelDescriber.php +++ b/ModelDescriber/ObjectModelDescriber.php @@ -15,6 +15,7 @@ use Doctrine\Common\Annotations\Reader; use EXSyst\Component\Swagger\Schema; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait; +use Nelmio\ApiDocBundle\Exception\UndocumentedArrayItemsException; use Nelmio\ApiDocBundle\Model\Model; use Nelmio\ApiDocBundle\ModelDescriber\Annotations\AnnotationsReader; use Nelmio\ApiDocBundle\PropertyDescriber\PropertyDescriberInterface; @@ -144,7 +145,15 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar $propertyDescriber->setModelRegistry($this->modelRegistry); } if ($propertyDescriber->supports($type)) { - $propertyDescriber->describe($type, $property, $model->getGroups()); + try { + $propertyDescriber->describe($type, $property, $model->getGroups()); + } catch (UndocumentedArrayItemsException $e) { + if (null !== $e->getClass()) { + throw $e; // This exception is already complete + } + + throw new UndocumentedArrayItemsException($model->getType()->getClassName(), sprintf("%s%s", $propertyName, $e->getPath())); + } return; } diff --git a/PropertyDescriber/ArrayPropertyDescriber.php b/PropertyDescriber/ArrayPropertyDescriber.php index 7055df4..fe8f63a 100644 --- a/PropertyDescriber/ArrayPropertyDescriber.php +++ b/PropertyDescriber/ArrayPropertyDescriber.php @@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\PropertyDescriber; use EXSyst\Component\Swagger\Schema; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait; +use Nelmio\ApiDocBundle\Exception\UndocumentedArrayItemsException; use Symfony\Component\PropertyInfo\Type; class ArrayPropertyDescriber implements PropertyDescriberInterface, ModelRegistryAwareInterface @@ -32,7 +33,7 @@ class ArrayPropertyDescriber implements PropertyDescriberInterface, ModelRegistr { $type = $type->getCollectionValueType(); if (null === $type) { - throw new \LogicException(sprintf('Property "%s" is an array, but its items type isn\'t specified. You can specify that by using the type `string[]` for instance or `@SWG\Property(type="array", @SWG\Items(type="string"))`.', $property->getTitle())); + throw new UndocumentedArrayItemsException(); } $property->setType('array'); @@ -43,7 +44,15 @@ class ArrayPropertyDescriber implements PropertyDescriberInterface, ModelRegistr $propertyDescriber->setModelRegistry($this->modelRegistry); } if ($propertyDescriber->supports($type)) { - $propertyDescriber->describe($type, $property, $groups); + try { + $propertyDescriber->describe($type, $property, $groups); + } catch (UndocumentedArrayItemsException $e) { + if (null !== $e->getClass()) { + throw $e; // This exception is already complete + } + + throw new UndocumentedArrayItemsException(null, sprintf("%s[]", $e->getPath())); + } break; } diff --git a/Tests/Functional/ArrayItemsErrorTest.php b/Tests/Functional/ArrayItemsErrorTest.php new file mode 100644 index 0000000..24acb63 --- /dev/null +++ b/Tests/Functional/ArrayItemsErrorTest.php @@ -0,0 +1,37 @@ + 'api.example.com']); + } + + public function testModelPictureDocumentation() + { + $this->expectException(UndocumentedArrayItemsException::class); + $this->expectExceptionMessage('Property "Nelmio\ApiDocBundle\Tests\Functional\Entity\ArrayItemsError\Bar::things[]" is an array, but its items type isn\'t specified.'); + + $this->getSwaggerDefinition(); + } + + protected static function createKernel(array $options = []) + { + return new TestKernel(TestKernel::ERROR_ARRAY_ITEMS); + } +} diff --git a/Tests/Functional/BazingaFunctionalTest.php b/Tests/Functional/BazingaFunctionalTest.php index beab5fd..ab82fe6 100644 --- a/Tests/Functional/BazingaFunctionalTest.php +++ b/Tests/Functional/BazingaFunctionalTest.php @@ -122,6 +122,6 @@ class BazingaFunctionalTest extends WebTestCase protected static function createKernel(array $options = []) { - return new TestKernel(true, true); + return new TestKernel(TestKernel::USE_JMS | TestKernel::USE_BAZINGA); } } diff --git a/Tests/Functional/Controller/ArrayItemsErrorController.php b/Tests/Functional/Controller/ArrayItemsErrorController.php new file mode 100644 index 0000000..6bbabbd --- /dev/null +++ b/Tests/Functional/Controller/ArrayItemsErrorController.php @@ -0,0 +1,35 @@ + + */ +class Bar +{ + /** + * @var array[] + */ + public $things; +} diff --git a/Tests/Functional/Entity/ArrayItemsError/Foo.php b/Tests/Functional/Entity/ArrayItemsError/Foo.php new file mode 100644 index 0000000..177a84f --- /dev/null +++ b/Tests/Functional/Entity/ArrayItemsError/Foo.php @@ -0,0 +1,30 @@ + + */ +class Foo +{ + /** + * @var string + */ + public $articles; + + /** + * @var Bar[] + */ + public $bars; +} diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 990f181..1532ca0 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -304,6 +304,6 @@ class JMSFunctionalTest extends WebTestCase protected static function createKernel(array $options = []) { - return new TestKernel(true); + return new TestKernel(TestKernel::USE_JMS); } } diff --git a/Tests/Functional/TestKernel.php b/Tests/Functional/TestKernel.php index 32e9399..edb64e4 100644 --- a/Tests/Functional/TestKernel.php +++ b/Tests/Functional/TestKernel.php @@ -33,17 +33,19 @@ use Symfony\Component\Serializer\Annotation\SerializedName; class TestKernel extends Kernel { + const USE_JMS = 1; + const USE_BAZINGA = 2; + const ERROR_ARRAY_ITEMS = 4; + use MicroKernelTrait; - private $useJMS; - private $useBazinga; + private $flags; - public function __construct(bool $useJMS = false, bool $useBazinga = false) + public function __construct(int $flags = 0) { - parent::__construct('test'.(int) $useJMS.(int) $useBazinga, true); + parent::__construct('test'.$flags, true); - $this->useJMS = $useJMS; - $this->useBazinga = $useBazinga; + $this->flags = $flags; } /** @@ -61,10 +63,10 @@ class TestKernel extends Kernel new FOSRestBundle(), ]; - if ($this->useJMS) { + if ($this->flags & self::USE_JMS) { $bundles[] = new JMSSerializerBundle(); - if ($this->useBazinga) { + if ($this->flags & self::USE_BAZINGA) { $bundles[] = new BazingaHateoasBundle(); } } @@ -91,11 +93,11 @@ class TestKernel extends Kernel $routes->import(__DIR__.'/Controller/SerializedNameController.php', '/', 'annotation'); } - if ($this->useJMS) { + if ($this->flags & self::USE_JMS) { $routes->import(__DIR__.'/Controller/JMSController.php', '/', 'annotation'); } - if ($this->useBazinga) { + if ($this->flags & self::USE_BAZINGA) { $routes->import(__DIR__.'/Controller/BazingaController.php', '/', 'annotation'); try { @@ -104,6 +106,10 @@ class TestKernel extends Kernel } catch (\ReflectionException $e) { } } + + if ($this->flags & self::ERROR_ARRAY_ITEMS) { + $routes->import(__DIR__.'/Controller/ArrayItemsErrorController.php', '/', 'annotation'); + } } /** @@ -231,7 +237,7 @@ class TestKernel extends Kernel */ public function getCacheDir() { - return parent::getCacheDir().'/'.(int) $this->useJMS; + return parent::getCacheDir().'/'.$this->flags; } /** @@ -239,7 +245,7 @@ class TestKernel extends Kernel */ public function getLogDir() { - return parent::getLogDir().'/'.(int) $this->useJMS; + return parent::getLogDir().'/'.$this->flags; } public function serialize() From 68bf1670f3e4592f52e81781c93832b694f5e5f3 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Fri, 20 Nov 2020 17:10:21 +0100 Subject: [PATCH 3/7] Fix CS --- Exception/UndocumentedArrayItemsException.php | 2 +- ModelDescriber/ObjectModelDescriber.php | 2 +- PropertyDescriber/ArrayPropertyDescriber.php | 2 +- Tests/Functional/Entity/ArrayItemsError/Bar.php | 2 -- Tests/Functional/Entity/ArrayItemsError/Foo.php | 2 -- Tests/Functional/TestKernel.php | 2 +- 6 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Exception/UndocumentedArrayItemsException.php b/Exception/UndocumentedArrayItemsException.php index 570642f..b44c05f 100644 --- a/Exception/UndocumentedArrayItemsException.php +++ b/Exception/UndocumentedArrayItemsException.php @@ -16,7 +16,7 @@ class UndocumentedArrayItemsException extends \LogicException private $class; private $path; - public function __construct(string $class = null, string $path = "") + public function __construct(string $class = null, string $path = '') { $this->class = $class; $this->path = $path; diff --git a/ModelDescriber/ObjectModelDescriber.php b/ModelDescriber/ObjectModelDescriber.php index 6350bfc..0f41324 100644 --- a/ModelDescriber/ObjectModelDescriber.php +++ b/ModelDescriber/ObjectModelDescriber.php @@ -152,7 +152,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar throw $e; // This exception is already complete } - throw new UndocumentedArrayItemsException($model->getType()->getClassName(), sprintf("%s%s", $propertyName, $e->getPath())); + throw new UndocumentedArrayItemsException($model->getType()->getClassName(), sprintf('%s%s', $propertyName, $e->getPath())); } return; diff --git a/PropertyDescriber/ArrayPropertyDescriber.php b/PropertyDescriber/ArrayPropertyDescriber.php index fe8f63a..defb84f 100644 --- a/PropertyDescriber/ArrayPropertyDescriber.php +++ b/PropertyDescriber/ArrayPropertyDescriber.php @@ -51,7 +51,7 @@ class ArrayPropertyDescriber implements PropertyDescriberInterface, ModelRegistr throw $e; // This exception is already complete } - throw new UndocumentedArrayItemsException(null, sprintf("%s[]", $e->getPath())); + throw new UndocumentedArrayItemsException(null, sprintf('%s[]', $e->getPath())); } break; diff --git a/Tests/Functional/Entity/ArrayItemsError/Bar.php b/Tests/Functional/Entity/ArrayItemsError/Bar.php index fc020cc..76a8073 100644 --- a/Tests/Functional/Entity/ArrayItemsError/Bar.php +++ b/Tests/Functional/Entity/ArrayItemsError/Bar.php @@ -11,8 +11,6 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\ArrayItemsError; -use Symfony\Component\Serializer\Annotation\Groups; - /** * @author Guilhem N. */ diff --git a/Tests/Functional/Entity/ArrayItemsError/Foo.php b/Tests/Functional/Entity/ArrayItemsError/Foo.php index 177a84f..c9d7704 100644 --- a/Tests/Functional/Entity/ArrayItemsError/Foo.php +++ b/Tests/Functional/Entity/ArrayItemsError/Foo.php @@ -11,8 +11,6 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\ArrayItemsError; -use Symfony\Component\Serializer\Annotation\Groups; - /** * @author Guilhem N. */ diff --git a/Tests/Functional/TestKernel.php b/Tests/Functional/TestKernel.php index edb64e4..edf9e2e 100644 --- a/Tests/Functional/TestKernel.php +++ b/Tests/Functional/TestKernel.php @@ -66,7 +66,7 @@ class TestKernel extends Kernel if ($this->flags & self::USE_JMS) { $bundles[] = new JMSSerializerBundle(); - if ($this->flags & self::USE_BAZINGA) { + if ($this->flags & self::USE_BAZINGA) { $bundles[] = new BazingaHateoasBundle(); } } From a01fd1e4f0c09793f891516cbc93d06a33ca70ba Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Sat, 28 Nov 2020 16:11:05 +0100 Subject: [PATCH 4/7] Fix error --- Tests/Functional/Entity/ArrayItemsError/Bar.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tests/Functional/Entity/ArrayItemsError/Bar.php b/Tests/Functional/Entity/ArrayItemsError/Bar.php index 76a8073..214e99f 100644 --- a/Tests/Functional/Entity/ArrayItemsError/Bar.php +++ b/Tests/Functional/Entity/ArrayItemsError/Bar.php @@ -16,8 +16,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\ArrayItemsError; */ class Bar { - /** - * @var array[] - */ public $things; + + public function addThing(array $thing) { } } From 90f835f1ef31342527c6ec64868a901db286be15 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Wed, 2 Dec 2020 15:38:38 +0100 Subject: [PATCH 5/7] Allow to not document form types fields (#1752) * Allow the usage of `@SWG\Definition` on form types * Allow to not document form types fields * Reduce the number of changes --- .../Compiler/ConfigurationPass.php | 1 + Form/Extension/DocumentationExtension.php | 2 +- ModelDescriber/FormModelDescriber.php | 22 +++++++++++++++++-- Tests/Functional/Form/UserType.php | 7 ++++++ Tests/Functional/FunctionalTest.php | 1 + 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/DependencyInjection/Compiler/ConfigurationPass.php b/DependencyInjection/Compiler/ConfigurationPass.php index df128be..8ea1aca 100644 --- a/DependencyInjection/Compiler/ConfigurationPass.php +++ b/DependencyInjection/Compiler/ConfigurationPass.php @@ -29,6 +29,7 @@ final class ConfigurationPass implements CompilerPassInterface $container->register('nelmio_api_doc.model_describers.form', FormModelDescriber::class) ->setPublic(false) ->addArgument(new Reference('form.factory')) + ->addArgument(new Reference('annotation_reader')) ->addTag('nelmio_api_doc.model_describer', ['priority' => 100]); } } diff --git a/Form/Extension/DocumentationExtension.php b/Form/Extension/DocumentationExtension.php index 0bebeef..2cc03a4 100644 --- a/Form/Extension/DocumentationExtension.php +++ b/Form/Extension/DocumentationExtension.php @@ -29,7 +29,7 @@ class DocumentationExtension extends AbstractTypeExtension public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(['documentation' => []]) - ->setAllowedTypes('documentation', ['array']); + ->setAllowedTypes('documentation', ['array', 'bool']); } public function getExtendedType() diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index c18f270..cc7284d 100644 --- a/ModelDescriber/FormModelDescriber.php +++ b/ModelDescriber/FormModelDescriber.php @@ -11,10 +11,12 @@ namespace Nelmio\ApiDocBundle\ModelDescriber; +use Doctrine\Common\Annotations\Reader; use EXSyst\Component\Swagger\Schema; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait; use Nelmio\ApiDocBundle\Model\Model; +use Nelmio\ApiDocBundle\ModelDescriber\Annotations\AnnotationsReader; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormConfigBuilderInterface; @@ -32,10 +34,15 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry use ModelRegistryAwareTrait; private $formFactory; + private $doctrineReader; - public function __construct(FormFactoryInterface $formFactory = null) + public function __construct(FormFactoryInterface $formFactory = null, Reader $reader = null) { $this->formFactory = $formFactory; + $this->doctrineReader = $reader; + if (null === $reader) { + @trigger_error(sprintf('Not passing a doctrine reader to the constructor of %s is deprecated since version 3.8 and won\'t be allowed in version 5.', self::class), E_USER_DEPRECATED); + } } public function describe(Model $model, Schema $schema) @@ -51,6 +58,11 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry $class = $model->getType()->getClassName(); + if (null !== $this->doctrineReader) { + $annotationsReader = new AnnotationsReader($this->doctrineReader, $this->modelRegistry); + $annotationsReader->updateDefinition(new \ReflectionClass($class), $schema); + } + $form = $this->formFactory->create($class, null, $model->getOptions() ?? []); $this->parseForm($schema, $form); } @@ -66,6 +78,12 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry foreach ($form as $name => $child) { $config = $child->getConfig(); + + // This field must not be documented + if ($config->hasOption('documentation') && false === $config->getOption('documentation')) { + continue; + } + $property = $properties->get($name); if ($config->getRequired()) { @@ -75,7 +93,7 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry $schema->setRequired($required); } - if ($config->hasOption('documentation')) { + if ($config->hasOption('documentation') && is_array($config->getOption('documentation'))) { $property->merge($config->getOption('documentation')); } diff --git a/Tests/Functional/Form/UserType.php b/Tests/Functional/Form/UserType.php index a05591c..063a01a 100644 --- a/Tests/Functional/Form/UserType.php +++ b/Tests/Functional/Form/UserType.php @@ -12,6 +12,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Form; use Nelmio\ApiDocBundle\Tests\Functional\Entity\User; +use Swagger\Annotations as SWG; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -19,6 +20,11 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @SWG\Definition( + * description="this is the description of an user" + * ) + */ class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) @@ -42,6 +48,7 @@ class UserType extends AbstractType ->add('document', DocumentType::class, ['class' => 'Document']) ->add('documents', DocumentType::class, ['class' => 'Document', 'multiple' => true]) ->add('extended_builtin', ExtendedBuiltinType::class, ['required_option' => 'foo']) + ->add('hidden', DummyType::class, ['documentation' => false]) ->add('save', SubmitType::class); } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index f9023e1..5759256 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -211,6 +211,7 @@ class FunctionalTest extends WebTestCase { $this->assertEquals([ 'type' => 'object', + 'description' => 'this is the description of an user', 'properties' => [ 'strings' => [ 'items' => ['type' => 'string'], From 67b28f1f7f2a944ec0bc09d5c6a9c60cf58f30f0 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Wed, 2 Dec 2020 15:39:15 +0100 Subject: [PATCH 6/7] Allow the usage of `@SWG\Definition` on form types (#1751) From 6d995a6e03295d05074f6fd65afcea829fc21cb0 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Thu, 10 Dec 2020 21:59:36 +0100 Subject: [PATCH 7/7] Add php 8 support (#1745) * Add php 8 support * Ignore platform reqs * Change php constraint * Use vendor/bin/simple-phpunit directly * Remove willdurand/hateoas-bundle when testing php8 * Merge 3.x * Move to github actions * Fix the tests * Change ./phpunit permissions * Update deprecations policy --- .github/workflows/continuous-integration.yml | 64 +++++++++++++++++++ .gitignore | 1 + .travis.yml | 38 ----------- CONTRIBUTING.md | 2 +- .../DependencyInjection/ConfigurationTest.php | 5 +- Tests/Describer/RouteDescriberTest.php | 2 +- Tests/Functional/ArrayItemsErrorTest.php | 2 +- Tests/Functional/BazingaFunctionalTest.php | 2 +- Tests/Functional/FOSRestTest.php | 2 +- Tests/Functional/FunctionalTest.php | 2 +- Tests/Functional/JMSFunctionalTest.php | 2 +- Tests/Functional/SwaggerUiTest.php | 2 +- .../FilteredRouteCollectionBuilderTest.php | 4 +- composer.json | 5 +- phpunit | 1 - 15 files changed, 81 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/continuous-integration.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..272fee9 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,64 @@ +# from doctrine/instantiator: +# https://github.com/doctrine/instantiator/blob/97aa11bb71ad6259a8c5a1161b4de2d6cdcc5501/.github/workflows/continuous-integration.yml + +name: "CI" + +on: + pull_request: + branches: + - "*.x" + push: + branches: + - "*.x" + +env: + fail-fast: true + COMPOSER_ROOT_VERSION: "1.4" + +jobs: + phpunit: + name: "PHPUnit" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + include: + - php-version: 7.1 + composer-flags: "--prefer-lowest" + - php-version: 7.2 + symfony-require: "3.4.*" + - php-version: 7.3 + symfony-require: "4.4.*" + - php-version: 7.3 + symfony-require: "^5.0" + - php-version: 8.0 + composer-flags: "--ignore-platform-reqs" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 2 + + - name: "Install PHP without coverage" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + coverage: "none" + + - name: "Cache dependencies installed with composer" + uses: "actions/cache@v2" + with: + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-locked-" + + - name: "Install dependencies with composer" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony-require }}" + run: | + composer global require --no-progress --no-scripts --no-plugins symfony/flex + composer update --no-interaction --no-progress ${{ matrix.composer-flags }} + + - name: "Run PHPUnit" + run: "./phpunit" diff --git a/.gitignore b/.gitignore index d4acd14..ae94d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ /.php_cs /phpunit.xml /.phpunit +/.phpunit.result.cache /Tests/Functional/cache /Tests/Functional/logs diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d8601ec..0000000 --- a/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -language: php - -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 - -sudo: false - -cache: - directories: - - .phpunit - - $HOME/.composer/cache - -matrix: - fast_finish: true - include: - - php: 7.1 - env: COMPOSER_FLAGS="--prefer-lowest" - - php: 7.2 - env: SYMFONY_VERSION=^3.4 - - php: 7.3 - env: SYMFONY_VERSION=^4.0 - - php: 7.3 - env: SYMFONY_VERSION=^5.0 - - php: 7.4 - env: SYMFONY_VERSION=^4.0 - - php: 7.4 - env: SYMFONY_VERSION=^5.0 - -before_install: - - phpenv config-rm xdebug.ini || true - - if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --dev --no-update; fi; - -install: composer update --no-interaction $COMPOSER_FLAGS - -script: ./phpunit diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75f90ec..18bf10e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ You MUST follow the [PSR-1](http://www.php-fig.org/psr/psr-1/) and should really read the recommendations. Can't wait? Use the [PHP-CS-Fixer tool](http://cs.sensiolabs.org/). -You MUST run the test suite. +You MUST run the test suite (run `composer update`, and then execute `vendor/bin/simple-phpunit`). You MUST write (or update) unit tests. diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 5c9509b..3a7d545 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -147,11 +147,12 @@ class ConfigurationTest extends TestCase /** * @group legacy - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage You must not use both `nelmio_api_doc.areas` and `nelmio_api_doc.routes` config options. Please update your config to only use `nelmio_api_doc.areas`. */ public function testBothAreasAndRoutes() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('You must not use both `nelmio_api_doc.areas` and `nelmio_api_doc.routes` config options. Please update your config to only use `nelmio_api_doc.areas`.'); + $processor = new Processor(); $config = $processor->processConfiguration(new Configuration(), [['areas' => [], 'routes' => []]]); } diff --git a/Tests/Describer/RouteDescriberTest.php b/Tests/Describer/RouteDescriberTest.php index b21baaf..e995291 100644 --- a/Tests/Describer/RouteDescriberTest.php +++ b/Tests/Describer/RouteDescriberTest.php @@ -35,7 +35,7 @@ class RouteDescriberTest extends AbstractDescriberTest $this->assertEquals((new Swagger())->toArray(), $this->getSwaggerDoc()->toArray()); } - protected function setUp() + protected function setUp(): void { $this->routeDescriber = $this->createMock(RouteDescriberInterface::class); $this->routes = new RouteCollection(); diff --git a/Tests/Functional/ArrayItemsErrorTest.php b/Tests/Functional/ArrayItemsErrorTest.php index 24acb63..cd8214e 100644 --- a/Tests/Functional/ArrayItemsErrorTest.php +++ b/Tests/Functional/ArrayItemsErrorTest.php @@ -15,7 +15,7 @@ use Nelmio\ApiDocBundle\Exception\UndocumentedArrayItemsException; class ArrayItemsErrorTest extends WebTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Functional/BazingaFunctionalTest.php b/Tests/Functional/BazingaFunctionalTest.php index ab82fe6..6be482b 100644 --- a/Tests/Functional/BazingaFunctionalTest.php +++ b/Tests/Functional/BazingaFunctionalTest.php @@ -15,7 +15,7 @@ use Hateoas\Configuration\Embedded; class BazingaFunctionalTest extends WebTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Functional/FOSRestTest.php b/Tests/Functional/FOSRestTest.php index 2ddf417..1e9c695 100644 --- a/Tests/Functional/FOSRestTest.php +++ b/Tests/Functional/FOSRestTest.php @@ -13,7 +13,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional; class FOSRestTest extends WebTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 5759256..d501ff8 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -16,7 +16,7 @@ use Symfony\Component\Serializer\Annotation\SerializedName; class FunctionalTest extends WebTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 1532ca0..5645f0f 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -13,7 +13,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional; class JMSFunctionalTest extends WebTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Functional/SwaggerUiTest.php b/Tests/Functional/SwaggerUiTest.php index 0b32453..209db31 100644 --- a/Tests/Functional/SwaggerUiTest.php +++ b/Tests/Functional/SwaggerUiTest.php @@ -20,7 +20,7 @@ class SwaggerUiTest extends WebTestCase */ private $client; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/Tests/Routing/FilteredRouteCollectionBuilderTest.php b/Tests/Routing/FilteredRouteCollectionBuilderTest.php index f8d01c1..8a782f3 100644 --- a/Tests/Routing/FilteredRouteCollectionBuilderTest.php +++ b/Tests/Routing/FilteredRouteCollectionBuilderTest.php @@ -84,12 +84,12 @@ class FilteredRouteCollectionBuilderTest extends TestCase } /** - * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidArgumentException - * * @dataProvider getInvalidOptions */ public function testFilterWithInvalidOption(array $options) { + $this->expectException(\Symfony\Component\OptionsResolver\Exception\InvalidArgumentException::class); + new FilteredRouteCollectionBuilder( new AnnotationReader(), $this->createControllerReflector(), diff --git a/composer.json b/composer.json index f22eada..c1832c5 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.1", + "php": ">=7.1.3", "symfony/framework-bundle": "^3.4|^4.0|^5.0", "symfony/options-resolver": "^3.4.4|^4.0|^5.0", "symfony/property-info": "^3.4|^4.0|^5.0", @@ -30,6 +30,7 @@ "symfony/console": "^3.4|^4.0|^5.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/property-access": "^3.4|^4.0|^5.0", "symfony/form": "^3.4|^4.0|^5.0", "symfony/dom-crawler": "^3.4|^4.0|^5.0", @@ -43,7 +44,7 @@ "doctrine/common": "^2.4", "api-platform/core": "^2.1.2", - "friendsofsymfony/rest-bundle": "^2.0|^3.0@beta", + "friendsofsymfony/rest-bundle": "^2.0|^3.0@dev", "willdurand/hateoas-bundle": "^1.0|^2.0", "jms/serializer-bundle": "^2.3|^3.0", "jms/serializer": "^1.14|^3.0" diff --git a/phpunit b/phpunit index 2934e5b..ffa70d2 100755 --- a/phpunit +++ b/phpunit @@ -5,5 +5,4 @@ if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) { exit(1); } putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); -putenv('SYMFONY_PHPUNIT_VERSION=6.5'); require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit';