Skip to content

Commit 3d05ca6

Browse files
authored
Symfony 4.2 compatiblity (#2333)
* Symfony 4.2 compatiblity * Fix TreeBuilder construct * Fix PHPStan * Imrpove compat
1 parent d1bca2c commit 3d05ca6

File tree

12 files changed

+87
-34
lines changed

12 files changed

+87
-34
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
/composer.lock
55
/phpunit.xml
66
/vendor/
7+
/tests/Fixtures/app/var/*
78
/tests/Fixtures/app/cache/*
89
/tests/Fixtures/app/logs/*

phpstan.neon

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,10 @@ parameters:
3737
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\AbstractFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
3838
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\FilterInterface::apply\(\) invoked with 5 parameters, 3-4 required\.#'
3939
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\OrderFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
40-
- '#Method ApiPlatform\\Core\\DataProvider\\CollectionDataProviderInterface::getCollection\(\) invoked with 3 parameters, 1-2 required.#'
40+
- '#Method ApiPlatform\\Core\\DataProvider\\CollectionDataProviderInterface::getCollection\(\) invoked with 3 parameters, 1-2 required\.#'
41+
42+
# Expected, due to feature detection, to adapt when Symfony 4.2 will be released
43+
- '#Class Symfony\\Component\\Serializer\\NameConverter\\AdvancedNameConverterInterface not found\.#'
44+
- '#Method Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer::__construct\(\) invoked with 6 parameters, 0-4 required\.#'
45+
- '#Parameter \#1 \$bitmask of class Symfony\\Component\\Serializer\\Encoder\\JsonEncode constructor expects int, array<string, int> given\.#'
46+
- '#Parameter \#1 \$associative of class Symfony\\Component\\Serializer\\Encoder\\JsonDecode constructor expects bool, array<string, true> given\.#'

src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,13 @@ final class Configuration implements ConfigurationInterface
3838
*/
3939
public function getConfigTreeBuilder()
4040
{
41-
$treeBuilder = new TreeBuilder();
42-
$rootNode = $treeBuilder->root('api_platform');
41+
if (method_exists(TreeBuilder::class, 'getRootNode')) {
42+
$treeBuilder = new TreeBuilder('api_platform');
43+
$rootNode = $treeBuilder->getRootNode();
44+
} else {
45+
$treeBuilder = new TreeBuilder();
46+
$rootNode = $treeBuilder->root('api_platform');
47+
}
4348

4449
$rootNode
4550
->children()

src/Serializer/AbstractItemNormalizer.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2929
use Symfony\Component\PropertyInfo\Type;
3030
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
31+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
3132
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
3233
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
3334
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
@@ -54,7 +55,15 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer
5455

5556
public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, ItemDataProviderInterface $itemDataProvider = null, bool $allowPlainIdentifiers = false)
5657
{
57-
parent::__construct($classMetadataFactory, $nameConverter);
58+
$defaultContext = ['circular_reference_handler' => function ($object) {
59+
return $this->iriConverter->getIriFromItem($object);
60+
}];
61+
62+
if (!interface_exists(AdvancedNameConverterInterface::class)) {
63+
$this->setCircularReferenceHandler($defaultContext['circular_reference_handler']);
64+
}
65+
66+
parent::__construct($classMetadataFactory, $nameConverter, null, null, null, $defaultContext);
5867

5968
$this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
6069
$this->propertyMetadataFactory = $propertyMetadataFactory;
@@ -63,10 +72,6 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName
6372
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
6473
$this->itemDataProvider = $itemDataProvider;
6574
$this->allowPlainIdentifiers = $allowPlainIdentifiers;
66-
67-
$this->setCircularReferenceHandler(function ($object) {
68-
return $this->iriConverter->getIriFromItem($object);
69-
});
7075
}
7176

7277
/**

src/Serializer/JsonEncoder.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Serializer\Encoder\JsonDecode;
1919
use Symfony\Component\Serializer\Encoder\JsonEncode;
2020
use Symfony\Component\Serializer\Encoder\JsonEncoder as BaseJsonEncoder;
21+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
2122

2223
/**
2324
* A JSON encoder with appropriate default options to embed the generated document into HTML.
@@ -32,11 +33,23 @@ final class JsonEncoder implements EncoderInterface, DecoderInterface
3233
public function __construct(string $format, BaseJsonEncoder $jsonEncoder = null)
3334
{
3435
$this->format = $format;
36+
$this->jsonEncoder = $jsonEncoder;
37+
38+
if (null !== $this->jsonEncoder) {
39+
return;
40+
}
3541

3642
// Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML.
37-
$this->jsonEncoder = $jsonEncoder ?: new BaseJsonEncoder(
38-
new JsonEncode(JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE), new JsonDecode(true)
39-
);
43+
$jsonEncodeOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE;
44+
if (interface_exists(AdvancedNameConverterInterface::class)) {
45+
$jsonEncode = new JsonEncode(['json_encode_options' => $jsonEncodeOptions]);
46+
$jsonDecode = new JsonDecode(['json_decode_associative' => true]);
47+
} else {
48+
$jsonEncode = new JsonEncode($jsonEncodeOptions);
49+
$jsonDecode = new JsonDecode(true);
50+
}
51+
52+
$this->jsonEncoder = new BaseJsonEncoder($jsonEncode, $jsonDecode);
4053
}
4154

4255
/**

tests/Action/ExceptionActionTest.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class ExceptionActionTest extends TestCase
3333
public function testActionWithCatchableException()
3434
{
3535
$serializerException = $this->prophesize(ExceptionInterface::class);
36-
$serializerException->willExtend(\Exception::class);
37-
36+
if (!is_a(ExceptionInterface::class, \Throwable::class, true)) {
37+
$serializerException->willExtend(\Exception::class);
38+
}
3839
$flattenException = FlattenException::create($serializerException->reveal());
3940

4041
$serializer = $this->prophesize(SerializerInterface::class);
@@ -57,7 +58,9 @@ public function testActionWithCatchableException()
5758
public function testActionWithUncatchableException()
5859
{
5960
$serializerException = $this->prophesize(ExceptionInterface::class);
60-
$serializerException->willExtend(\Exception::class);
61+
if (!is_a(ExceptionInterface::class, \Throwable::class, true)) {
62+
$serializerException->willExtend(\Exception::class);
63+
}
6164

6265
$flattenException = FlattenException::create($serializerException->reveal());
6366

tests/Fixtures/TestBundle/Controller/CustomActionController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller;
1515

1616
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\CustomActionDummy;
17-
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
17+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1818
use Symfony\Component\HttpFoundation\Request;
1919
use Symfony\Component\Routing\Annotation\Route;
2020

2121
/**
2222
* @author Kévin Dunglas <[email protected]>
2323
*/
24-
class CustomActionController extends Controller
24+
class CustomActionController extends AbstractController
2525
{
2626
/**
2727
* @Route(

tests/Fixtures/TestBundle/Controller/CustomController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller;
1515

16-
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
16+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1717
use Symfony\Component\HttpFoundation\JsonResponse;
1818

1919
/**
2020
* Custom Controller.
2121
*
2222
* @author Kévin Dunglas <[email protected]>
2323
*/
24-
class CustomController extends Controller
24+
class CustomController extends AbstractController
2525
{
2626
public function customAction(int $id): JsonResponse
2727
{

tests/Fixtures/app/AppKernel.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ public function registerBundles(): array
6363
return $bundles;
6464
}
6565

66+
public function getProjectDir()
67+
{
68+
return __DIR__;
69+
}
70+
6671
protected function configureRoutes(RouteCollectionBuilder $routes)
6772
{
6873
$routes->import('config/routing.yml');
@@ -76,7 +81,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
7681
{
7782
$c->setParameter('kernel.project_dir', __DIR__);
7883

79-
$loader->load("{$this->getRootDir()}/config/config_{$this->getEnvironment()}.yml");
84+
$loader->load(__DIR__."/config/config_{$this->getEnvironment()}.yml");
8085

8186
$securityConfig = [
8287
'encoders' => [

tests/Hal/Serializer/ItemNormalizerTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ public function testNormalize()
128128
$serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled();
129129

130130
$nameConverter = $this->prophesize(NameConverterInterface::class);
131-
$nameConverter->normalize('name')->shouldBeCalled()->willReturn('name');
132-
$nameConverter->normalize('relatedDummy')->shouldBeCalled()->willReturn('related_dummy');
131+
$nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('name');
132+
$nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('related_dummy');
133133

134134
$normalizer = new ItemNormalizer(
135135
$propertyNameCollectionFactoryProphecy->reveal(),
@@ -188,8 +188,8 @@ public function testNormalizeWithoutCache()
188188
$serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled();
189189

190190
$nameConverter = $this->prophesize(NameConverterInterface::class);
191-
$nameConverter->normalize('name')->shouldBeCalled()->willReturn('name');
192-
$nameConverter->normalize('relatedDummy')->shouldBeCalled()->willReturn('related_dummy');
191+
$nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('name');
192+
$nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('related_dummy');
193193

194194
$normalizer = new ItemNormalizer(
195195
$propertyNameCollectionFactoryProphecy->reveal(),

0 commit comments

Comments
 (0)