Extensions

API Platform provides a system to extend queries on items and collections.

API プラットフォームは、アイテムとコレクションに対するクエリを拡張するシステムを提供します。

Extensions are specific to Doctrine and Elasticsearch-PHP, and therefore, the Doctrine ORM / MongoDB ODM support or the Elasticsearch reading support must be enabled to use this feature. If you use custom providers it's up to you to implement your own extension system or not.

拡張機能は Doctrine および Elasticsearch-PHP に固有であるため、この機能を使用するには、Doctrine ORM / MongoDB ODM サポートまたは Elasticsearchreading サポートを有効にする必要があります。カスタム プロバイダーを使用する場合、独自の拡張システムを実装するかどうかはユーザー次第です。

You can find a working example of a custom extension using a pagination in the API Platform's demo application.

API プラットフォームのデモ アプリケーションで、ページネーションを使用したカスタム拡張機能の実際の例を見つけることができます。

Custom Doctrine ORM Extension

Custom extensions must implement the ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface and / or the ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface interfaces, to be run when querying for a collection of items and when querying for an item respectively.

カスタム拡張機能は、ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface および/または ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface インターフェイスを実装する必要があります。これは、アイテムのコレクションをクエリする場合とアイテムをクエリする場合にそれぞれ実行されます。

If you use custom state providers, they must support extensions and be aware of active extensions to work properly.

カスタム状態プロバイダーを使用する場合、それらは拡張機能をサポートし、アクティブな拡張機能を認識して正しく機能する必要があります。

Example

In the following example, we will see how to always get the offers owned by the current user. We will set up an exception, whenever the user has the ROLE_ADMIN.

次の例では、現在のユーザーが所有するオファーを常に取得する方法を示します。ユーザーが ROLE_ADMIN を持っている場合は常に、例外を設定します。

Given these two entities:

次の 2 つのエンティティがあるとします。

<?php
// api/src/Entity/User.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;

#[ApiResource]
class User
{
    // ...
}
<?php
// api/src/Entity/Offer.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;

#[ApiResource]
class Offer
{
    #[ORM\ManyToOne] 
    public User $user;

    //...
}
<?php
// api/src/Doctrine/CurrentUserExtension.php

namespace App\Doctrine;

use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
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, Operation $operation = null, array $context = []): void
    {
        $this->addWhere($queryBuilder, $resourceClass);
    }

    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void
    {
        $this->addWhere($queryBuilder, $resourceClass);
    }

    private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
    {
        if (Offer::class !== $resourceClass || $this->security->isGranted('ROLE_ADMIN') || null === $user = $this->security->getUser()) {
            return;
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere(sprintf('%s.user = :current_user', $rootAlias));
        $queryBuilder->setParameter('current_user', $user->getId());
    }
}

Finally, if you're not using the autoconfiguration, you have to register the custom extension with either of those tags:

最後に、自動構成を使用していない場合は、カスタム拡張機能をこれらのタグのいずれかに登録する必要があります。

# api/config/services.yaml
services:

    # ...

    'App\Doctrine\CurrentUserExtension':
        tags:
            - { name: api_platform.doctrine.orm.query_extension.collection }
            - { name: api_platform.doctrine.orm.query_extension.item }

The api_platform.doctrine.orm.query_extension.collection tag will register this service as a collection extension. The api_platform.doctrine.orm.query_extension.item does the same thing for items.

api_platform.doctrine.orm.query_extension.collection タグは、このサービスをコレクション拡張として登録します。api_platform.doctrine.orm.query_extension.item はアイテムに対して同じことを行います。

Note that your extensions should have a positive priority if defined. Internal extensions have negative priorities, for reference:

定義されている場合、拡張機能には正の優先度が必要であることに注意してください。参考までに、内部拡張機能には負の優先度があります。

Service name Priority Class
api_platform.doctrine.orm.query_extension.eager_loading (collection) -8 ApiPlatform\Doctrine\Orm\Extension\EagerLoadingExtension
api_platform.doctrine.orm.query_extension.eager_loading (item) -8 ApiPlatform\Doctrine\Orm\Extension\EagerLoadingExtension
api_platform.doctrine.orm.query_extension.filter -16 ApiPlatform\Doctrine\Orm\Extension\FilterExtension
api_platform.doctrine.orm.query_extension.filter_eager_loading -17 ApiPlatform\Doctrine\Orm\Extension\FilterEagerLoadingExtension
api_platform.doctrine.orm.query_extension.order -32 ApiPlatform\Doctrine\Orm\Extension\OrderExtension
api_platform.doctrine.orm.query_extension.pagination -64 ApiPlatform\Doctrine\Orm\Extension\PaginationExtension

Blocking Anonymous Users

This example adds a WHERE clause condition only when a fully authenticated user without ROLE_ADMIN tries to access a resource. It means that anonymous users will be able to access all data. To prevent this potential security issue, the API must ensure that the current user is authenticated.

この例では、ROLE_ADMIN を持たない完全に認証されたユーザーがリソースにアクセスしようとした場合にのみ、WHERE 句の条件を追加します。これは、匿名ユーザーがすべてのデータにアクセスできることを意味します。この潜在的なセキュリティの問題を防ぐために、API は現在のユーザーが認証されていることを確認する必要があります。

To secure the access to endpoints, use the following access control rule:

エンドポイントへのアクセスを保護するには、次のアクセス コントロール ルールを使用します。

# app/config/package/security.yaml
security:
    # ...
    access_control:
        # ...
        - { path: ^/offers, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/users, roles: IS_AUTHENTICATED_FULLY }

Custom Doctrine MongoDB ODM Extension

Creating custom extensions is the same as with Doctrine ORM.

カスタム拡張機能の作成は、Doctrine ORM と同じです。

The interfaces are:

インターフェイスは次のとおりです。

  • ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface and ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface to add stages to the aggregation builder.
    ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface および ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface を使用して、集約ビルダーにステージを追加します。
  • ApiPlatform\Doctrine\Odm\Extension\AggregationResultItemExtensionInterface and ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface to return a result.
    ApiPlatform\Doctrine\Odm\Extension\AggregationResultItemExtensionInterface および ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface を使用して結果を返します。

The tags are api_platform.doctrine_mongodb.odm.aggregation_extension.item and api_platform.doctrine_mongodb.odm.aggregation_extension.collection.

タグは api_platform.doctrine_mongodb.odm.aggregation_extension.item と api_platform.doctrine_mongodb.odm.aggregation_extension.collection です。

The custom extensions receive the aggregation builder, used to execute complex operations on data.

カスタム拡張機能は、データに対して複雑な操作を実行するために使用される集計ビルダーを受け取ります。

Custom Elasticsearch Extension

Currently only extensions querying for a collection of items through a search request are supported. So your custom extensions must implement the RequestBodySearchCollectionExtensionInterface. Register your custom extensions as services and tag them with the api_platform.elasticsearch.request_body_search_extension.collection tag.

現在、検索リクエストを通じてアイテムのコレクションをクエリする拡張機能のみがサポートされています。したがって、カスタム拡張機能は RequestBodySearchCollectionExtensionInterface を実装する必要があります。カスタム拡張機能をサービスとして登録し、api_platform.elasticsearch.request_body_search_extension.collection タグでタグ付けします。