For a route versionning and a better separation between the entity and the api output I made a resource that is not an entity linked to that entity by a provider. A had like to add some filters and make a pagination but it seems I can't natively.
I have for example an entity:
<?php
namespace App\Entity;
use App\Repository\UserApiKeyRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Blameable\Traits\BlameableEntity;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
#[ORM\Entity(repositoryClass: TreasureRepository::class)]
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', timeAware: true, hardDelete: false)]
class Treasure
{
use BlameableEntity;
use TimestampableEntity;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private int $id;
#[ORM\ManyToOne(inversedBy: 'treasures')]
#[ORM\JoinColumn(referencedColumnName: 'owner_id', nullable: false)]
private Owner $owner;
#[ORM\Column(length: 255)]
private string $name;
#[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 2)]
private string $value;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $deletedAt = null;
I made a resource:
<?php
namespace App\ApiResource\V1;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use App\Entity\Owner;
#[ApiResource(
uriTemplate: '/owners/{owner_id}/treasures/{id}.{_format}',
shortName: 'Treasures',
operations: [
new Get(),
new Delete(
processor: TreasureProcessor::class
)
],
uriVariables: [
'owner_id' => new Link(
fromProperty: 'treasures',
fromClass: Owner::class
),
'id' => new Link(
fromClass: self::class
)
],
provider: TreasureProvider::class
)]
#[ApiResource(
uriTemplate: '/owners/{owner_id}/treasures.{_format}',
shortName: 'Treasures',
operations: [
new GetCollection(
normalizationContext: ['groups' => 'list']
),
new Post(
denormalizationContext: ['groups' => 'create'],
processor: TreasureProcessor::class,
)
],
uriVariables: [
'owner_id' => new Link(
fromProperty: 'treasures',
fromClass: Owner::class
)
],
provider: TreasureProvider::class
)]
class TreasureResource
{
#[Groups(['list'])]
private ?int $id;
#[Groups(['list', 'create'])]
private string $name;
#[Groups(['list', 'create'])]
private string $value;
private ?Owner $owner;
public function __construct(
string $name,
string $value,
?Owner $owner = null,
?int $id = null
)
{
$this->id = $id;
$this->name = $name;
$this->value = $value;
$this->owner = $owner;
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getValue(): string
{
return $this->value;
}
public function getOwner(): ?Owner
{
return $this->owner;
}
}
Like that I do not have pagination neither filters. If I add the filter attribute on name for example
#[ApiFilter(SearchFilter::class, strategy: 'partial')]
I have an error
Call to a member function getClassMetadata() on null
Also, I tried to add a pagination into my Provider that is not working well, I do not have the real result of "hydra:totalItems" that show the total of the current page and not all the results, and I do not have the previous, next, total pages informations provided by json-ld. I did not see a way to set the ApiPlatform pagination with data.
Here is a sample of my provider:
$owner = $this->ownerRepository->find($uriVariables['owner_id']);
/** ApiPlatform\State\Pagination\Pagination $this->pagination */
$page = $this->pagination->getPage($context);
$itemsPerPage = $this->pagination->getLimit($operation, $context);
$treasures = $this->treasureRepository->findByOwnerPaginated($owner, $page, $itemsPerPage);
return $this->collectionToResources($treasures); //returns an array
Anyone ran into theses issue and were able to solve or bypass them? I wish I could use ApiPlatform attributes out of the box even with this way of coding