diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 4b347487936..d8527fddfa3 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -38,6 +38,7 @@
.
+ tests
features
vendor
.php-cs-fixer.dist.php
diff --git a/src/Laravel/Exception/ErrorHandler.php b/src/Laravel/Exception/ErrorHandler.php
index 7dcc70277a9..f496c5d1eb5 100644
--- a/src/Laravel/Exception/ErrorHandler.php
+++ b/src/Laravel/Exception/ErrorHandler.php
@@ -15,6 +15,7 @@
use ApiPlatform\Laravel\ApiResource\Error;
use ApiPlatform\Laravel\Controller\ApiPlatformController;
+use ApiPlatform\Metadata\Exception\InvalidUriVariableException;
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
use ApiPlatform\Metadata\Exception\StatusAwareExceptionInterface;
use ApiPlatform\Metadata\HttpOperation;
@@ -192,7 +193,7 @@ private function getStatusCode(?HttpOperation $apiOperation, ?HttpOperation $err
return $exception->getStatusCode();
}
- if ($exception instanceof RequestExceptionInterface) {
+ if ($exception instanceof RequestExceptionInterface || $exception instanceof InvalidUriVariableException) {
return 400;
}
diff --git a/src/Symfony/EventListener/ErrorListener.php b/src/Symfony/EventListener/ErrorListener.php
index 6f5bf6ebaf0..19e5593a3ca 100644
--- a/src/Symfony/EventListener/ErrorListener.php
+++ b/src/Symfony/EventListener/ErrorListener.php
@@ -15,6 +15,7 @@
use ApiPlatform\Metadata\Error as ErrorOperation;
use ApiPlatform\Metadata\Exception\HttpExceptionInterface;
+use ApiPlatform\Metadata\Exception\InvalidUriVariableException;
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
use ApiPlatform\Metadata\HttpOperation;
use ApiPlatform\Metadata\IdentifiersExtractorInterface;
@@ -178,7 +179,7 @@ private function getStatusCode(?HttpOperation $apiOperation, Request $request, ?
return $exception->getStatusCode();
}
- if ($exception instanceof RequestExceptionInterface) {
+ if ($exception instanceof RequestExceptionInterface || $exception instanceof InvalidUriVariableException) {
return 400;
}
diff --git a/tests/Fixtures/TestBundle/Entity/Issue7135/Bar.php b/tests/Fixtures/TestBundle/Entity/Issue7135/Bar.php
new file mode 100644
index 00000000000..c762b92c718
--- /dev/null
+++ b/tests/Fixtures/TestBundle/Entity/Issue7135/Bar.php
@@ -0,0 +1,46 @@
+
+ *
+ * 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\Issue7135;
+
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Uid\Uuid;
+
+#[ORM\Entity()]
+#[ApiResource(
+ shortName: 'BarPr7135',
+ operations: [
+ new Get(
+ uriTemplate: '/pull-request-7135/bar/{id}',
+ ),
+ ]
+)]
+#[ORM\Table(name: 'bar6466')]
+class Bar
+{
+ #[ORM\Id]
+ #[ORM\Column(type: 'symfony_uuid', unique: true)]
+ #[ORM\GeneratedValue(strategy: 'CUSTOM')]
+ #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
+ public Uuid $id;
+
+ #[ORM\Column]
+ public string $title = '';
+
+ public function __construct(?Uuid $id = null)
+ {
+ $this->id = $id ?: Uuid::v7();
+ }
+}
diff --git a/tests/Fixtures/TestBundle/Entity/Issue7135/Foo.php b/tests/Fixtures/TestBundle/Entity/Issue7135/Foo.php
new file mode 100644
index 00000000000..b45378e50c8
--- /dev/null
+++ b/tests/Fixtures/TestBundle/Entity/Issue7135/Foo.php
@@ -0,0 +1,48 @@
+
+ *
+ * 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\Issue7135;
+
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Post;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Uid\Uuid;
+
+#[ORM\Entity()]
+#[ApiResource(
+ shortName: 'FooPr7135',
+ operations: [
+ new Post(
+ uriTemplate: '/pull-request-7135/foo/',
+ ),
+ ],
+ normalizationContext: ['iri_only' => true],
+)]
+#[ORM\Table(name: 'foo6466')]
+class Foo
+{
+ #[ORM\Id]
+ #[ORM\Column(type: 'symfony_uuid', unique: true)]
+ #[ORM\GeneratedValue(strategy: 'CUSTOM')]
+ #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
+ public Uuid $id;
+
+ #[ORM\ManyToOne(targetEntity: Bar::class)]
+ #[ORM\JoinColumn(referencedColumnName: 'id', nullable: false)]
+ public Bar $bar;
+
+ public function __construct()
+ {
+ $this->id = Uuid::v7();
+ }
+}
diff --git a/tests/Functional/Issues/Issue7135Test.php b/tests/Functional/Issues/Issue7135Test.php
new file mode 100644
index 00000000000..22aa5c310fe
--- /dev/null
+++ b/tests/Functional/Issues/Issue7135Test.php
@@ -0,0 +1,121 @@
+
+ *
+ * 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\Issues;
+
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7135\Bar;
+use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7135\Foo;
+use ApiPlatform\Tests\RecreateSchemaTrait;
+use ApiPlatform\Tests\SetupClassResourcesTrait;
+use Doctrine\ORM\EntityManagerInterface;
+use Doctrine\ORM\Tools\SchemaTool;
+use Symfony\Component\Uid\Uuid;
+
+class Issue7135Test extends ApiTestCase
+{
+ use RecreateSchemaTrait;
+ use SetupClassResourcesTrait;
+
+ protected static ?bool $alwaysBootKernel = false;
+
+ /**
+ * @return class-string[]
+ */
+ public static function getResources(): array
+ {
+ return [Bar::class, Foo::class];
+ }
+
+ public function testValidPostRequestWithIriWhenIdentifierIsUuid(): void
+ {
+ $container = static::getContainer();
+ if ('mongodb' === $container->getParameter('kernel.environment')) {
+ $this->markTestSkipped();
+ }
+
+ $this->recreateSchema(self::getResources());
+ $bar = $this->loadBarFixture();
+
+ $response = self::createClient()->request('POST', '/pull-request-7135/foo/', [
+ 'json' => [
+ 'bar' => 'pull-request-7135/bar/'.$bar->id,
+ ],
+ ]);
+
+ self::assertEquals(201, $response->getStatusCode());
+ }
+
+ public function testInvalidPostRequestWithIriWhenIdentifierIsUuid(): void
+ {
+ $container = static::getContainer();
+ if ('mongodb' === $container->getParameter('kernel.environment')) {
+ $this->markTestSkipped();
+ }
+
+ $response = self::createClient()->request('POST', '/pull-request-7135/foo/', [
+ 'json' => [
+ 'bar' => 'pull-request-7135/bar/invalid-uuid',
+ ],
+ ]);
+
+ self::assertEquals(400, $response->getStatusCode());
+ self::assertJsonContains(['detail' => 'Identifier "id" could not be transformed.']);
+ }
+
+ public function testInvalidGetRequestWhenIdentifierIsUuid(): void
+ {
+ $container = static::getContainer();
+ if ('mongodb' === $container->getParameter('kernel.environment')) {
+ $this->markTestSkipped();
+ }
+
+ $response = self::createClient()->request('GET', '/pull-request-7135/bar/invalid-uuid');
+
+ self::assertEquals(404, $response->getStatusCode());
+ }
+
+ protected function loadBarFixture(): Bar
+ {
+ $container = static::getContainer();
+ $registry = $container->get('doctrine');
+ $manager = $registry->getManager();
+
+ $bar = new Bar(Uuid::fromString('0196b66f-66bd-780b-95fe-0ce987a32357'));
+ $bar->title = 'Bar one';
+ $manager->persist($bar);
+
+ $manager->flush();
+
+ return $bar;
+ }
+
+ protected function tearDown(): void
+ {
+ $container = static::getContainer();
+ $registry = $container->get('doctrine');
+ $manager = $registry->getManager();
+ if (!$manager instanceof EntityManagerInterface) {
+ return;
+ }
+
+ $classes = [];
+ foreach (self::getResources() as $entityClass) {
+ $classes[] = $manager->getClassMetadata($entityClass);
+ }
+
+ $schemaTool = new SchemaTool($manager);
+ @$schemaTool->dropSchema($classes);
+ parent::tearDown();
+ }
+}