From cce360ce4e71d0ab8fd2409513d6c5b818fcf7ab Mon Sep 17 00:00:00 2001 From: Olivier Doucet Date: Thu, 11 Feb 2021 15:20:18 +0100 Subject: [PATCH 1/5] fix searchFilter with binary types (like UUID) --- .../Doctrine/Orm/Filter/SearchFilter.php | 68 ++++++++++++++++--- .../Doctrine/Orm/Filter/SearchFilterTest.php | 23 +++---- 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php index d56ecc5046f..2e28720111c 100644 --- a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php +++ b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php @@ -21,8 +21,10 @@ use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Core\Exception\InvalidArgumentException; use Doctrine\DBAL\Types\Type as DBALType; +use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\Mapping\ClassMetadata; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\PropertyAccess\PropertyAccess; @@ -113,7 +115,7 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB $caseSensitive = false; } - $this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $alias, $field, $values, $caseSensitive); + $this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $alias, $field, $values, $caseSensitive, $metadata); return; } @@ -149,14 +151,39 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB $associationField = $associationFieldIdentifier; } - if (1 === \count($values)) { + /* + * If field type is string/float, Doctrine does not call convertToDatabaseValueSQL() because it + * does not know it needs conversion. + * This would lead to incorrect values for Ramsey\Uuid\Doctrine\UuidBinaryType for example. + * The only fix is to provide field type to doctrine ... + * It's easy if setParameter() sets only one value BUT impossible if multiple values are provided. + * The only way to do this is to rewrite the IN() statement to multiple values + * and map a global setParameters() + */ + $type = $metadata->getTypeOfField($associationField); + $nbValues = \count($values); + + if (1 === $nbValues) { $queryBuilder ->andWhere($queryBuilder->expr()->eq($associationAlias.'.'.$associationField, ':'.$valueParameter)) - ->setParameter($valueParameter, $values[0]); + ->setParameter($valueParameter, $values[0], $type); } else { + // get current parameters, because QueryBuilder->setParameters() erase previous parameters set + $parameters = $queryBuilder->getParameters(); + $inQuery = []; + + // convertToDatabaseValue() can only convert one value at a time ... We can no longer pass an array of values, we should use multiple values + + for ($i = 0; $i < $nbValues; ++$i) { + $inQuery[] = ':'.$valueParameter; + $parameters->add(new Parameter($valueParameter, $values[$i], $type)); + $valueParameter = $queryNameGenerator->generateParameterName($associationField); + } + + // we cannot use expr->in() here because it considers $inQuery parameters as strings. $queryBuilder - ->andWhere($queryBuilder->expr()->in($associationAlias.'.'.$associationField, ':'.$valueParameter)) - ->setParameter($valueParameter, $values); + ->andWhere($associationAlias.'.'.$associationField.' IN ('.implode(', ', $inQuery).')') + ->setParameters($parameters); } } @@ -165,28 +192,47 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB * * @throws InvalidArgumentException If strategy does not exist */ - protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $values, bool $caseSensitive) + protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $values, bool $caseSensitive/*, ClassMetadata $metadata = null*/) { + // check if we have metadata + if (\func_num_args() > 7 && ($metadata = func_get_arg(7)) instanceof ClassMetadata) { + $type = $metadata->getTypeOfField($field); + } else { + @trigger_error(sprintf('Method %s() will have a 8th argument `$metadata` in version API Platform 3.0.', __FUNCTION__), E_USER_DEPRECATED); + $type = null; // default setParameter() value + } + if (!\is_array($values)) { $values = [$values]; } + $nbValues = \count($values); $wrapCase = $this->createWrapCase($caseSensitive); $valueParameter = ':'.$queryNameGenerator->generateParameterName($field); $aliasedField = sprintf('%s.%s', $alias, $field); if (null == $strategy || self::STRATEGY_EXACT == $strategy) { - if (1 == \count($values)) { + if (1 == $nbValues) { $queryBuilder ->andWhere($queryBuilder->expr()->eq($wrapCase($aliasedField), $wrapCase($valueParameter))) - ->setParameter($valueParameter, $values[0]); + ->setParameter($valueParameter, $values[0], $type); return; } + // get current parameters, because QueryBuilder->setParameters() erase previous parameters set + $parameters = $queryBuilder->getParameters(); + $inQuery = []; + for ($i = 0; $i < $nbValues; ++$i) { + $inQuery[] = $valueParameter; + $parameters->add(new Parameter($valueParameter, $caseSensitive ? $values[$i] : strtolower($values[$i]), $type)); + $valueParameter = ':'.$queryNameGenerator->generateParameterName($field); + } + + // we cannot use expr->in() here because it considers $inQuery parameters as strings. $queryBuilder - ->andWhere($queryBuilder->expr()->in($wrapCase($aliasedField), $valueParameter)) - ->setParameter($valueParameter, $caseSensitive ? $values : array_map('strtolower', $values)); + ->andWhere($wrapCase($aliasedField).' IN ('.implode(', ', $inQuery).')') + ->setParameters($parameters); return; } @@ -228,7 +274,7 @@ protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuild } $queryBuilder->andWhere($queryBuilder->expr()->orX(...$ors)); - array_walk($parameters, [$queryBuilder, 'setParameter']); + array_walk($parameters, [$queryBuilder, 'setParameter'], $type); } /** diff --git a/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php b/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php index 1dbb23905dd..c202e3c5475 100644 --- a/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php +++ b/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php @@ -390,22 +390,18 @@ public function provideApplyTestData(): array $filterFactory, ], 'exact (multiple values)' => [ - sprintf('SELECT %s FROM %s %1$s WHERE %1$s.name IN(:name_p1)', $this->alias, Dummy::class), + sprintf('SELECT %s FROM %s %1$s WHERE %1$s.name IN (:name_p1, :name_p2)', $this->alias, Dummy::class), [ - 'name_p1' => [ - 'CaSE', - 'SENSitive', - ], + 'name_p1' => 'CaSE', + 'name_p2' => 'SENSitive', ], $filterFactory, ], 'exact (multiple values; case insensitive)' => [ - sprintf('SELECT %s FROM %s %1$s WHERE LOWER(%1$s.name) IN(:name_p1)', $this->alias, Dummy::class), + sprintf('SELECT %s FROM %s %1$s WHERE LOWER(%1$s.name) IN (:name_p1, :name_p2)', $this->alias, Dummy::class), [ - 'name_p1' => [ - 'case', - 'insensitive', - ], + 'name_p1' => 'case', + 'name_p2' => 'insensitive', ], $filterFactory, ], @@ -547,10 +543,11 @@ public function provideApplyTestData(): array $filterFactory, ], 'mixed IRI and entity ID values for relations' => [ - sprintf('SELECT %s FROM %s %1$s INNER JOIN %1$s.relatedDummies relatedDummies_a1 WHERE %1$s.relatedDummy IN(:relatedDummy_p1) AND relatedDummies_a1.id = :relatedDummies_p2', $this->alias, Dummy::class), + sprintf('SELECT %s FROM %s %1$s INNER JOIN %1$s.relatedDummies relatedDummies_a1 WHERE %1$s.relatedDummy IN (:relatedDummy_p1, :relatedDummy_p2) AND relatedDummies_a1.id = :relatedDummies_p4', $this->alias, Dummy::class), [ - 'relatedDummy_p1' => [1, 2], - 'relatedDummies_p2' => 1, + 'relatedDummy_p1' => 1, + 'relatedDummy_p2' => 2, + 'relatedDummies_p4' => 1, ], $filterFactory, ], From 5b448aede24d33f2bd13315beffb15e6b757ec19 Mon Sep 17 00:00:00 2001 From: Olivier Doucet Date: Thu, 11 Feb 2021 15:25:15 +0100 Subject: [PATCH 2/5] fix php-cs-fixer --- src/Bridge/Doctrine/Orm/Filter/SearchFilter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php index 2e28720111c..4d4a274c934 100644 --- a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php +++ b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php @@ -198,7 +198,7 @@ protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuild if (\func_num_args() > 7 && ($metadata = func_get_arg(7)) instanceof ClassMetadata) { $type = $metadata->getTypeOfField($field); } else { - @trigger_error(sprintf('Method %s() will have a 8th argument `$metadata` in version API Platform 3.0.', __FUNCTION__), E_USER_DEPRECATED); + @trigger_error(sprintf('Method %s() will have a 8th argument `$metadata` in version API Platform 3.0.', __FUNCTION__), \E_USER_DEPRECATED); $type = null; // default setParameter() value } From 04b8ffc18e5e147964bd215b35dcd847f604a9ce Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 19 Feb 2021 13:33:36 +0100 Subject: [PATCH 3/5] test: add Behat tests --- .github/workflows/ci.yml | 2 +- features/doctrine/search_filter.feature | 42 +++++++++ .../Doctrine/Orm/Filter/SearchFilter.php | 54 ++++------- tests/Behat/DoctrineContext.php | 30 +++++++ .../Entity/RamseyUuidBinaryDummy.php | 89 +++++++++++++++++++ tests/Fixtures/app/config/config_common.yml | 3 +- tests/Fixtures/app/config/config_mysql.yml | 1 + tests/Fixtures/app/config/config_postgres.yml | 1 + tests/Fixtures/app/config/config_sqlite.yml | 1 + 9 files changed, 186 insertions(+), 37 deletions(-) create mode 100644 tests/Fixtures/TestBundle/Entity/RamseyUuidBinaryDummy.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 684141b1cbe..faccaa57ed5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -384,7 +384,7 @@ jobs: - name: Clear test app cache run: tests/Fixtures/app/console cache:clear --ansi - name: Run Behat tests - run: vendor/bin/behat --out=std --format=progress --profile=default --no-interaction + run: vendor/bin/behat --out=std --format=progress --profile=default --no-interaction --tags '~@!lowest' postgresql: name: Behat (PHP ${{ matrix.php }}) (PostgreSQL) diff --git a/features/doctrine/search_filter.feature b/features/doctrine/search_filter.feature index c396159bf77..5e5cdefff4c 100644 --- a/features/doctrine/search_filter.feature +++ b/features/doctrine/search_filter.feature @@ -539,6 +539,48 @@ Feature: Search filter on collections } """ + @!mongodb + @!lowest + Scenario: Search collection by binary UUID (Ramsey) + Given there is a ramsey identified resource with binary uuid "c19900a9-d2b2-45bf-b040-05c72d321282" + And there is a ramsey identified resource with binary uuid "a96cb2ed-e3dc-4449-9842-830e770cdecc" + When I send a "GET" request to "/ramsey_uuid_binary_dummies?id=c19900a9-d2b2-45bf-b040-05c72d321282" + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" + And the JSON node "hydra:totalItems" should be equal to "1" + + @!mongodb + @!lowest + Scenario: Search collection by binary UUID (Ramsey) (multiple values) + Given there is a ramsey identified resource with binary uuid "f71a6469-1bfc-4945-bad1-d6092f09a8c3" + When I send a "GET" request to "/ramsey_uuid_binary_dummies?id[]=c19900a9-d2b2-45bf-b040-05c72d321282&id[]=f71a6469-1bfc-4945-bad1-d6092f09a8c3" + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" + And the JSON node "hydra:totalItems" should be equal to "2" + + @!mongodb + @!lowest + Scenario: Search collection by related binary UUID (Ramsey) + Given there is a ramsey identified resource with binary uuid "56fa36c3-2b5e-4813-9e3a-b0bbe2ab5553" having a related resource with binary uuid "02227dc6-a371-4b8b-a34c-bbbf921b8ebd" + And there is a ramsey identified resource with binary uuid "4d796212-4b26-4e19-b092-a32d990b1e7e" having a related resource with binary uuid "31f64c33-6061-4fc1-b0e8-f4711b607c7d" + When I send a "GET" request to "/ramsey_uuid_binary_dummies?relateds=02227dc6-a371-4b8b-a34c-bbbf921b8ebd" + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" + And the JSON node "hydra:totalItems" should be equal to "1" + + @!mongodb + @!lowest + Scenario: Search collection by related binary UUID (Ramsey) (multiple values) + Given there is a ramsey identified resource with binary uuid "3248c908-a89d-483a-b75f-25888730d391" having a related resource with binary uuid "d7b2e909-37b0-411e-814c-74e044afbccb" + When I send a "GET" request to "/ramsey_uuid_binary_dummies?relateds[]=02227dc6-a371-4b8b-a34c-bbbf921b8ebd&relateds[]=d7b2e909-37b0-411e-814c-74e044afbccb" + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" + And the JSON node "hydra:totalItems" should be equal to "2" + Scenario: Search for entities within an impossible range When I send a "GET" request to "/dummies?name=MuYm" Then the response status code should be 200 diff --git a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php index 4d4a274c934..ad26c178b54 100644 --- a/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php +++ b/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php @@ -151,40 +151,28 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB $associationField = $associationFieldIdentifier; } - /* - * If field type is string/float, Doctrine does not call convertToDatabaseValueSQL() because it - * does not know it needs conversion. - * This would lead to incorrect values for Ramsey\Uuid\Doctrine\UuidBinaryType for example. - * The only fix is to provide field type to doctrine ... - * It's easy if setParameter() sets only one value BUT impossible if multiple values are provided. - * The only way to do this is to rewrite the IN() statement to multiple values - * and map a global setParameters() - */ $type = $metadata->getTypeOfField($associationField); - $nbValues = \count($values); - if (1 === $nbValues) { + if (1 === \count($values)) { $queryBuilder ->andWhere($queryBuilder->expr()->eq($associationAlias.'.'.$associationField, ':'.$valueParameter)) ->setParameter($valueParameter, $values[0], $type); - } else { - // get current parameters, because QueryBuilder->setParameters() erase previous parameters set - $parameters = $queryBuilder->getParameters(); - $inQuery = []; - // convertToDatabaseValue() can only convert one value at a time ... We can no longer pass an array of values, we should use multiple values + return; + } - for ($i = 0; $i < $nbValues; ++$i) { - $inQuery[] = ':'.$valueParameter; - $parameters->add(new Parameter($valueParameter, $values[$i], $type)); - $valueParameter = $queryNameGenerator->generateParameterName($associationField); - } + $parameters = $queryBuilder->getParameters(); + $inQuery = []; - // we cannot use expr->in() here because it considers $inQuery parameters as strings. - $queryBuilder - ->andWhere($associationAlias.'.'.$associationField.' IN ('.implode(', ', $inQuery).')') - ->setParameters($parameters); + foreach ($values as $val) { + $inQuery[] = ':'.$valueParameter; + $parameters->add(new Parameter($valueParameter, $val, $type)); + $valueParameter = $queryNameGenerator->generateParameterName($associationField); } + + $queryBuilder + ->andWhere($associationAlias.'.'.$associationField.' IN ('.implode(', ', $inQuery).')') + ->setParameters($parameters); } /** @@ -192,27 +180,25 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB * * @throws InvalidArgumentException If strategy does not exist */ - protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $values, bool $caseSensitive/*, ClassMetadata $metadata = null*/) + protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $values, bool $caseSensitive/*, ClassMetadata $metadata*/) { - // check if we have metadata if (\func_num_args() > 7 && ($metadata = func_get_arg(7)) instanceof ClassMetadata) { $type = $metadata->getTypeOfField($field); } else { @trigger_error(sprintf('Method %s() will have a 8th argument `$metadata` in version API Platform 3.0.', __FUNCTION__), \E_USER_DEPRECATED); - $type = null; // default setParameter() value + $type = null; } if (!\is_array($values)) { $values = [$values]; } - $nbValues = \count($values); $wrapCase = $this->createWrapCase($caseSensitive); $valueParameter = ':'.$queryNameGenerator->generateParameterName($field); $aliasedField = sprintf('%s.%s', $alias, $field); - if (null == $strategy || self::STRATEGY_EXACT == $strategy) { - if (1 == $nbValues) { + if (self::STRATEGY_EXACT === $strategy) { + if (1 === \count($values)) { $queryBuilder ->andWhere($queryBuilder->expr()->eq($wrapCase($aliasedField), $wrapCase($valueParameter))) ->setParameter($valueParameter, $values[0], $type); @@ -220,16 +206,14 @@ protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuild return; } - // get current parameters, because QueryBuilder->setParameters() erase previous parameters set $parameters = $queryBuilder->getParameters(); $inQuery = []; - for ($i = 0; $i < $nbValues; ++$i) { + foreach ($values as $value) { $inQuery[] = $valueParameter; - $parameters->add(new Parameter($valueParameter, $caseSensitive ? $values[$i] : strtolower($values[$i]), $type)); + $parameters->add(new Parameter($valueParameter, $caseSensitive ? $value : strtolower($value), $type)); $valueParameter = ':'.$queryNameGenerator->generateParameterName($field); } - // we cannot use expr->in() here because it considers $inQuery parameters as strings. $queryBuilder ->andWhere($wrapCase($aliasedField).' IN ('.implode(', ', $inQuery).')') ->setParameters($parameters); diff --git a/tests/Behat/DoctrineContext.php b/tests/Behat/DoctrineContext.php index 3d5754c4f34..a62255ed6b5 100644 --- a/tests/Behat/DoctrineContext.php +++ b/tests/Behat/DoctrineContext.php @@ -139,6 +139,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Pet; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Product; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Question; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RamseyUuidBinaryDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RamseyUuidDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedOwnedDummy; @@ -1306,6 +1307,35 @@ public function thereIsARamseyIdentifiedResource(string $uuid) $this->manager->flush(); } + /** + * @Given there is a ramsey identified resource with binary uuid :uuid + */ + public function thereIsARamseyIdentifiedResourceWithBinaryUuid(string $uuid) + { + $dummy = new RamseyUuidBinaryDummy(); + $dummy->setId($uuid); + + $this->manager->persist($dummy); + $this->manager->flush(); + } + + /** + * @Given there is a ramsey identified resource with binary uuid :uuid having a related resource with binary uuid :uuid_related + */ + public function thereIsARamseyIdentifiedResourceWithBinaryUuidHavingARelatedResourceWithBinaryUuid(string $uuid, string $uuidRelated) + { + $related = new RamseyUuidBinaryDummy(); + $related->setId($uuidRelated); + + $dummy = new RamseyUuidBinaryDummy(); + $dummy->setId($uuid); + $dummy->addRelated($related); + + $this->manager->persist($related); + $this->manager->persist($dummy); + $this->manager->flush(); + } + /** * @Given there is a dummy object with a fourth level relation */ diff --git a/tests/Fixtures/TestBundle/Entity/RamseyUuidBinaryDummy.php b/tests/Fixtures/TestBundle/Entity/RamseyUuidBinaryDummy.php new file mode 100644 index 00000000000..5cede9f62b3 --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/RamseyUuidBinaryDummy.php @@ -0,0 +1,89 @@ + + * + * 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\Core\Tests\Fixtures\TestBundle\Entity; + +use ApiPlatform\Core\Annotation\ApiFilter; +use ApiPlatform\Core\Annotation\ApiResource; +use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; + +/** + * @ORM\Entity + * @ApiResource + * @ApiFilter(SearchFilter::class, properties={"id"="exact", "relateds"="exact"}) + */ +class RamseyUuidBinaryDummy +{ + /** + * @var UuidInterface + * + * @ORM\Id + * @ORM\Column(type="uuid_binary", unique=true) + */ + private $id; + + /** + * @var Collection + * + * @ORM\OneToMany(targetEntity="RamseyUuidBinaryDummy", mappedBy="relatedParent") + */ + private $relateds; + + /** + * @var ?RamseyUuidBinaryDummy + * + * @ORM\ManyToOne(targetEntity="RamseyUuidBinaryDummy", inversedBy="relateds") + */ + private $relatedParent; + + public function __construct() + { + $this->relateds = new ArrayCollection(); + } + + public function getId(): UuidInterface + { + return $this->id; + } + + public function setId(string $uuid): void + { + $this->id = Uuid::fromString($uuid); + } + + public function getRelateds(): Collection + { + return $this->relateds; + } + + public function addRelated(self $dummy): void + { + $this->relateds->add($dummy); + $dummy->setRelatedParent($this); + } + + public function getRelatedParent(): ?self + { + return $this->relatedParent; + } + + public function setRelatedParent(self $dummy): void + { + $this->relatedParent = $dummy; + } +} diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml index 6b989cfa8c8..69db4cfb002 100644 --- a/tests/Fixtures/app/config/config_common.yml +++ b/tests/Fixtures/app/config/config_common.yml @@ -8,7 +8,8 @@ doctrine: path: '%kernel.cache_dir%/db.sqlite' charset: 'UTF8' types: - uuid: Ramsey\Uuid\Doctrine\UuidType + uuid: Ramsey\Uuid\Doctrine\UuidType + uuid_binary: Ramsey\Uuid\Doctrine\UuidBinaryType orm: auto_generate_proxy_classes: '%kernel.debug%' diff --git a/tests/Fixtures/app/config/config_mysql.yml b/tests/Fixtures/app/config/config_mysql.yml index d83e9650176..e69bf6b474a 100644 --- a/tests/Fixtures/app/config/config_mysql.yml +++ b/tests/Fixtures/app/config/config_mysql.yml @@ -13,3 +13,4 @@ doctrine: server_version: '%env(MYSQL_VERSION)%' types: uuid: Ramsey\Uuid\Doctrine\UuidType + uuid_binary: Ramsey\Uuid\Doctrine\UuidBinaryType diff --git a/tests/Fixtures/app/config/config_postgres.yml b/tests/Fixtures/app/config/config_postgres.yml index 20c21168dd2..54928efaa0f 100644 --- a/tests/Fixtures/app/config/config_postgres.yml +++ b/tests/Fixtures/app/config/config_postgres.yml @@ -13,3 +13,4 @@ doctrine: server_version: '%env(POSTGRES_VERSION)%' types: uuid: Ramsey\Uuid\Doctrine\UuidType + uuid_binary: Ramsey\Uuid\Doctrine\UuidBinaryType diff --git a/tests/Fixtures/app/config/config_sqlite.yml b/tests/Fixtures/app/config/config_sqlite.yml index 1407de645d4..55707b7c681 100644 --- a/tests/Fixtures/app/config/config_sqlite.yml +++ b/tests/Fixtures/app/config/config_sqlite.yml @@ -10,3 +10,4 @@ doctrine: url: '%env(resolve:DATABASE_URL)%' types: uuid: Ramsey\Uuid\Doctrine\UuidType + uuid_binary: Ramsey\Uuid\Doctrine\UuidBinaryType From a1f12ca6cae5c8908eea3a628a8c93be6be545ba Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 19 Feb 2021 15:36:06 +0100 Subject: [PATCH 4/5] chore: add changelog entry --- CHANGELOG.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94e3115a93e..7ce9cb96450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,15 @@ # Changelog -# 2.6.4 - -* OpenApi: Fix missing 422 responses in the documentation (#4086) - ## 2.6.3 * Identifiers: Re-allow `POST` operations even if no identifier is defined (#4052) * Hydra: Fix partial pagination which no longer returns the `hydra:next` property (#4015) * Security: Use a `NullToken` when using the new authenticator manager in the resource access checker (#4067) * Mercure: Do not use data in options when deleting (#4056) -* Doctrine: Support for foreign identifiers -* JSON Schema: Allow generating documentation when property and method start from "is" (property `isActive` and method `isActive`) +* Doctrine: Support for foreign identifiers (#4042) +* Doctrine: Support for binary UUID in search filter (#3774) +* JSON Schema: Allow generating documentation when property and method start from "is" (property `isActive` and method `isActive`) (#4064) +* OpenAPI: Fix missing 422 responses in the documentation (#4086) * OpenAPI: Fix error when schema is empty (#4051) * OpenAPI: Do not set scheme to oauth2 when generating securitySchemes (#4073) * OpenAPI: Fix missing `$ref` when no `type` is used in context (#4076) From 810af16703cc03aafba14f55a428e8fbcb052a6d Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 19 Feb 2021 15:46:33 +0100 Subject: [PATCH 5/5] test: binary uuid are not working with postgres --- behat.yml.dist | 2 +- features/doctrine/search_filter.feature | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/behat.yml.dist b/behat.yml.dist index c3af2501185..6625645655c 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -50,7 +50,7 @@ postgres: - 'Behat\MinkExtension\Context\MinkContext' - 'behatch:context:rest' filters: - tags: '~@sqlite&&~@mongodb&&~@elasticsearch' + tags: '~@sqlite&&~@mongodb&&~@elasticsearch&&~@!postgres' mongodb: suites: diff --git a/features/doctrine/search_filter.feature b/features/doctrine/search_filter.feature index 5e5cdefff4c..ad4b30c0a10 100644 --- a/features/doctrine/search_filter.feature +++ b/features/doctrine/search_filter.feature @@ -539,6 +539,7 @@ Feature: Search filter on collections } """ + @!postgres @!mongodb @!lowest Scenario: Search collection by binary UUID (Ramsey) @@ -550,6 +551,7 @@ Feature: Search filter on collections And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" And the JSON node "hydra:totalItems" should be equal to "1" + @!postgres @!mongodb @!lowest Scenario: Search collection by binary UUID (Ramsey) (multiple values) @@ -560,6 +562,7 @@ Feature: Search filter on collections And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" And the JSON node "hydra:totalItems" should be equal to "2" + @!postgres @!mongodb @!lowest Scenario: Search collection by related binary UUID (Ramsey) @@ -571,6 +574,7 @@ Feature: Search filter on collections And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" And the JSON node "hydra:totalItems" should be equal to "1" + @!postgres @!mongodb @!lowest Scenario: Search collection by related binary UUID (Ramsey) (multiple values)