Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Native UID support in search filter #5618

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 39 additions & 0 deletions features/doctrine/search_filter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,45 @@ Feature: Search filter on collections
}
"""

@createSchema
Scenario: Get collection by ulid 01H2ZS93NBKJW5W4Y01S8TZ43M
Given there is a UidBasedId resource with id "01H2ZS93NBKJW5W4Y01S8TZ43M"
When I send a "GET" request to "/uid_based_ids?id=/uid_based_ids/01H2ZS93NBKJW5W4Y01S8TZ43M"
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 should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/UidBasedId"},
"@id": {"pattern": "^/uid_based_ids"},
"@type": {"pattern": "^hydra:Collection$"},
"hydra:member": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@id": {
"oneOf": [
{"pattern": "^/uid_based_ids/01H2ZS93NBKJW5W4Y01S8TZ43M"}
]
}
}
}
},
"hydra:view": {
"type": "object",
"properties": {
"@id": {"pattern": "^/uid_based_ids\\?id=%2Fuid_based_ids%2F01H2ZS93NBKJW5W4Y01S8TZ43M"},
"@type": {"pattern": "^hydra:PartialCollectionView$"}
}
}
}
}
"""

@createSchema
Scenario: Get collection ordered by a non valid properties
When I send a "GET" request to "/dummies?unknown=0"
Expand Down
18 changes: 16 additions & 2 deletions src/Doctrine/Common/Filter/SearchFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use ApiPlatform\Metadata\IriConverterInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Uid\AbstractUid;

/**
* Trait for filtering the collection by given properties.
Expand Down Expand Up @@ -127,19 +128,32 @@
$item = $iriConverter->getResourceFromIri($value, ['fetch_data' => false]);

if (null === $this->identifiersExtractor) {
return $this->getPropertyAccessor()->getValue($item, 'id');
$id = $this->getPropertyAccessor()->getValue($item, 'id');

Check warning on line 131 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L131

Added line #L131 was not covered by tests

return $this->toUuidValue($id);

Check warning on line 133 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L133

Added line #L133 was not covered by tests
}

$identifiers = $this->identifiersExtractor->getIdentifiersFromItem($item);

return 1 === \count($identifiers) ? array_pop($identifiers) : $identifiers;
if (1 === \count($identifiers)) {
$id = array_pop($identifiers);

Check warning on line 139 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L138-L139

Added lines #L138 - L139 were not covered by tests

return $this->toUuidValue($id);

Check warning on line 141 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L141

Added line #L141 was not covered by tests
}

return array_map([$this, 'toUuidValue'], $identifiers);

Check warning on line 144 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L144

Added line #L144 was not covered by tests
} catch (InvalidArgumentException) {
// Do nothing, return the raw value
}

return $value;
}

private function toUuidValue(mixed $id): mixed

Check warning on line 152 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L152

Added line #L152 was not covered by tests
{
return ($id instanceof AbstractUid) ? $id->toBinary() : $id;

Check warning on line 154 in src/Doctrine/Common/Filter/SearchFilterTrait.php

View check run for this annotation

Codecov / codecov/patch

src/Doctrine/Common/Filter/SearchFilterTrait.php#L154

Added line #L154 was not covered by tests
}

/**
* Normalize the values array.
*/
Expand Down
14 changes: 14 additions & 0 deletions tests/Behat/DoctrineContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
use ApiPlatform\Tests\Fixtures\TestBundle\Document\SoMany as SoManyDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\Taxon as TaxonDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\ThirdLevel as ThirdLevelDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\UidBasedId as UidBasedIdDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\UrlEncodedId as UrlEncodedIdDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\User as UserDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\VideoGame as VideoGameDocument;
Expand Down Expand Up @@ -200,6 +201,7 @@
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Taxon;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\ThirdLevel;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\TreeDummy;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\UidBasedId;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\UrlEncodedId;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\User;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\UuidIdentifierDummy;
Expand All @@ -217,6 +219,7 @@
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Uid\Ulid;
use Symfony\Component\Uid\Uuid as SymfonyUuid;

/**
Expand Down Expand Up @@ -1436,6 +1439,17 @@ public function thereIsAUrlEncodedIdResource(): void
$this->manager->clear();
}

/**
* @Given there is a UidBasedId resource with id :id
*/
public function thereIsAUidBasedIdResource(string $id): void
{
$uidBasedIdResource = ($this->isOrm() ? new UidBasedId(Ulid::fromBase32($id)) : new UidBasedIdDocument(Ulid::fromBase32($id)));
$this->manager->persist($uidBasedIdResource);
$this->manager->flush();
$this->manager->clear();
}

/**
* @Given there is a Program
*/
Expand Down
42 changes: 42 additions & 0 deletions tests/Fixtures/TestBundle/Document/UidBasedId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?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\Document;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Uid\Ulid;

/**
* @author Beno!t POLASZEK <bpolaszek@gmail.com>
*
* Resource with an Uid-based ID
*/
#[ApiResource(operations: [new Get(), new Post(), new GetCollection()])]
#[ApiFilter(SearchFilter::class, properties: ['id' => 'exact'])]
#[ODM\Document]
class UidBasedId
{
#[ODM\Id(strategy: 'none')]
public Ulid $id;

public function __construct(?Ulid $id)
{
$this->id = $id ?? new Ulid();
}
}
44 changes: 44 additions & 0 deletions tests/Fixtures/TestBundle/Entity/UidBasedId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?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;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Ulid;

/**
* @author Beno!t POLASZEK <bpolaszek@gmail.com>
*
* Resource with an Uid-based ID
*/
#[ApiResource(operations: [new Get(), new Post(), new GetCollection()])]
#[ApiFilter(SearchFilter::class, properties: ['id' => 'exact'])]
#[ORM\Entity]
class UidBasedId
{
#[ORM\Column(type: 'ulid')]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'NONE')]
public Ulid $id;

public function __construct(?Ulid $id)
{
$this->id = $id ?? new Ulid();
}
}