API Platform: Extensions reference
In a nutshell
API Platform lets you implement extensions to conditionally extend queries on items and collections. For example, suppose you have a User
and Offer
entity, and you want to restrict queries to Offer
to return only those that belong to the currently authenticated user. You can use extensions to do this.
Example entities
<?php
// api/src/Entity/User.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
#[ApiResource]
class User
{
// ...
}
<?php
// api/src/Entity/Offer.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
#[ApiResource]
class Offer
{
#[ORM\ManyToOne]
public User $user;
//...
}
Example extension
When querying for offers, you want to limit the results to offers that belong to the currently authenticated user (i.e., Offer->user
=== current user). You can do this by implementing an extension like so:
<?php
// api/src/Doctrine/CurrentUserExtension.php
namespace App\Doctrine;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Offer;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Security;
final class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
{
$this->addWhere($queryBuilder, $resourceClass);
}
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []): void
{
$this->addWhere($queryBuilder, $resourceClass);
}
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
{
if ($resourceClass !== Offer::class|| $this->security->isGranted('ROLE_ADMIN') || $user = $this->security->getUser() === null) {
return;
}
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere(sprintf('%s.user = :current_user', $rootAlias));
$queryBuilder->setParameter('current_user', $user->getId());
}
}
Now, when there’s a request for the Offer
collection (e.g., GET /v1/offers
), the CurrentUserExtension#applyToCollection
method will be applied and the results will be limited to offers where offer.user = <current-user-id>
Other notes
In the example above, the WHERE
clause is only applied when an authenticated user without ROLE_ADMIN
tries to access a resource. You’ll typically want to ensure that an access control rule is in place that restricts access to unauthenticated users. Something like:
# app/config/package/security.yaml
security:
# ...
access_control:
# ...
- { path: ^/offers, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/users, roles: IS_AUTHENTICATED_FULLY }
Sources
Thanks for your comment 🙏. Once it's approved, it will appear here.
Leave a comment