Skip to content

Commit

Permalink
fix(jsonld): remove request uri variables when denormalizing output (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka authored Jul 15, 2024
1 parent 1197e92 commit 84df467
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Serializer/AbstractItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public function denormalize(mixed $data, string $class, ?string $format = null,
throw new LogicException('Cannot denormalize the input because the injected serializer is not a denormalizer');
}

unset($context['input'], $context['operation'], $context['operation_name']);
unset($context['input'], $context['operation'], $context['operation_name'], $context['uri_variables']);
$context['resource_class'] = $inputClass;

try {
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Routing/IriConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public function getResourceFromIri(string $iri, array $context = [], ?Operation
throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
}

// uri_variables come from the Request context and may not be available
foreach ($context['uri_variables'] ?? [] as $key => $value) {
if (!isset($parameters[$key]) || $parameters[$key] !== (string) $value) {
throw new InvalidArgumentException(sprintf('The iri "%s" does not reference the correct resource.', $iri));
Expand Down
31 changes: 31 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue6465/Bar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity()]
#[ApiResource(shortName: 'Bar6465')]
#[ORM\Table(name: 'bar6465')]
class Bar
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public ?int $id = null;

#[ORM\Column]
public string $title = '';
}
22 changes: 22 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue6465/CustomInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465;

use Symfony\Component\Validator\Constraints\NotBlank;

class CustomInput
{
#[NotBlank]
public Bar $bar;
}
21 changes: 21 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue6465/CustomOutput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465;

class CustomOutput
{
public function __construct(public string $title)
{
}
}
58 changes: 58 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue6465/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity()]
#[ORM\Table(name: 'foo6465')]
#[ApiResource(
shortName: 'Foo6465',
operations: [
new Get(),
new GetCollection(),
new Post(),
new Post(
uriTemplate: '/foo/{id}/validate',
uriVariables: ['id' => new Link(fromClass: Foo::class)],
status: 200,
input: CustomInput::class,
output: CustomOutput::class,
processor: [self::class, 'process'],
),
]
)]
class Foo
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public ?int $id = null;

#[ORM\Column(length: 255)]
public ?string $title = null;

/**
* @param CustomInput $data
*/
public static function process($data): CustomOutput
{
return new CustomOutput($data->bar->title);
}
}
91 changes: 91 additions & 0 deletions tests/Functional/JsonLd.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Functional;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Bar;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Foo;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\SchemaTool;

class JsonLd extends ApiTestCase
{
/**
* The input DTO denormalizes an existing Doctrine entity.
*/
public function testIssue6465(): void
{
$container = static::getContainer();
if ('mongodb' === $container->getParameter('kernel.environment')) {
$this->markTestSkipped();
}

$response = self::createClient()->request('POST', '/foo/1/validate', [
'json' => ['bar' => '/bar6465s/2'],
]);

$res = $response->toArray();
$this->assertEquals('Bar two', $res['title']);
}

protected function setUp(): void
{
self::bootKernel();

$container = static::getContainer();
$registry = $container->get('doctrine');
$manager = $registry->getManager();
if (!$manager instanceof EntityManagerInterface) {
return;
}

$classes = [];
foreach ([Foo::class, Bar::class] as $entityClass) {
$classes[] = $manager->getClassMetadata($entityClass);
}

$schemaTool = new SchemaTool($manager);
@$schemaTool->createSchema($classes);

$foo = new Foo();
$foo->title = 'Foo';
$manager->persist($foo);
$bar = new Bar();
$bar->title = 'Bar one';
$manager->persist($bar);
$bar2 = new Bar();
$bar2->title = 'Bar two';
$manager->persist($bar2);
$manager->flush();
}

protected function tearDown(): void
{
$container = static::getContainer();
$registry = $container->get('doctrine');
$manager = $registry->getManager();
if (!$manager instanceof EntityManagerInterface) {
return;
}

$classes = [];
foreach ([Foo::class, Bar::class] as $entityClass) {
$classes[] = $manager->getClassMetadata($entityClass);
}

$schemaTool = new SchemaTool($manager);
@$schemaTool->dropSchema($classes);
parent::tearDown();
}
}

0 comments on commit 84df467

Please sign in to comment.