Skip to content

Commit

Permalink
feat(search filter): native uid support
Browse files Browse the repository at this point in the history
  • Loading branch information
bpolaszek committed Jun 26, 2023
1 parent 4ef0ef8 commit 61be694
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
39 changes: 39 additions & 0 deletions features/doctrine/search_filter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,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
5 changes: 4 additions & 1 deletion src/Doctrine/Common/Filter/SearchFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use ApiPlatform\Exception\InvalidArgumentException;
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 @@ -124,7 +125,9 @@ protected function getIdFromValue(string $value): mixed
$iriConverter = $this->getIriConverter();
$item = $iriConverter->getResourceFromIri($value, ['fetch_data' => false]);

return $this->getPropertyAccessor()->getValue($item, 'id');
$id = $this->getPropertyAccessor()->getValue($item, 'id');

return ($id instanceof AbstractUid) ? $id->toBinary() : $id;
} catch (InvalidArgumentException) {
// Do nothing, return the raw value
}
Expand Down
14 changes: 14 additions & 0 deletions tests/Behat/DoctrineContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,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 @@ -174,6 +175,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 @@ -191,6 +193,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 @@ -1369,6 +1372,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();
}
}
45 changes: 45 additions & 0 deletions tests/Fixtures/TestBundle/Entity/UidBasedId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?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\AbstractUid;
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();
}
}

0 comments on commit 61be694

Please sign in to comment.