You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在API Platform中设置路径变量

在API Platform中配置带路径变量的集合操作路径

看起来你已经在正确的方向上配置了带路径变量的集合操作,但要让{shop}变量真正生效并正确过滤数据,还需要补充几个关键步骤。以下是完整的实现方案:


1. 完善XML配置细节

首先先补全你的XML配置,添加路径变量的验证规则和Swagger文档配置,确保API文档能正确识别这个参数:

<collectionOperations>
    <collectionOperation name="get">
        <attribute name="method">GET</attribute>
        <attribute name="path">/{shop}/books</attribute>
        <attribute name="normalization_context">
            <attribute name="groups">
                <attribute>books_list</attribute>
                <attribute>list</attribute>
            </attribute>
        </attribute>
        <!-- 限制{shop}的格式,避免非法字符 -->
        <attribute name="requirements">
            <attribute name="shop">[\w-]+</attribute>
        </attribute>
        <!-- 配置Swagger文档显示路径参数 -->
        <attribute name="swagger_context">
            <attribute name="parameters">
                <attribute>
                    <attribute name="name">shop</attribute>
                    <attribute name="in">path</attribute>
                    <attribute name="required">true</attribute>
                    <attribute name="type">string</attribute>
                    <attribute name="description">店铺唯一标识符(如slug或ID)</attribute>
                </attribute>
            </attribute>
        </attribute>
    </collectionOperation>
</collectionOperations>

2. 处理路径变量的数据过滤

API Platform默认的集合数据提供者不会自动识别并使用{shop}变量过滤数据,你可以选择以下两种常用方案:

方案A:自定义数据提供者

创建一个自定义数据提供者,获取路径中的shop参数并过滤书籍数据:

// src/BooksBundle/DataProvider/BookCollectionDataProvider.php
namespace App\BooksBundle\DataProvider;

use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\BooksBundle\Entity\Book;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class BookCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
    private $entityManager;
    private $requestStack;

    public function __construct(EntityManagerInterface $entityManager, RequestStack $requestStack)
    {
        $this->entityManager = $entityManager;
        $this->requestStack = $requestStack;
    }

    // 指定该数据提供者仅作用于Book实体的get集合操作
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Book::class === $resourceClass && 'get' === $operationName;
    }

    // 实现数据查询逻辑
    public function getCollection(string $resourceClass, string $operationName = null, array $context = []): iterable
    {
        $request = $this->requestStack->getCurrentRequest();
        $shopIdentifier = $request->get('shop');

        // 根据shop标识符查询对应书籍
        return $this->entityManager->getRepository(Book::class)
            ->createQueryBuilder('b')
            ->where('b.shop = :shop')
            ->setParameter('shop', $shopIdentifier)
            ->getQuery()
            ->getResult();
    }
}

然后在services.yaml中注册这个数据提供者:

# config/services.yaml
App\BooksBundle\DataProvider\BookCollectionDataProvider:
    arguments:
        $entityManager: '@doctrine.orm.default_entity_manager'
        $requestStack: '@request_stack'
    tags:
        - { name: api_platform.data_provider }

方案B:使用自定义控制器

如果更倾向于用控制器直接处理逻辑,可以给集合操作指定自定义控制器:
先在XML配置中添加controller属性:

<collectionOperation name="get">
    <!-- 其他已有配置 -->
    <attribute name="controller">App\BooksBundle\Controller\BookCollectionController::getBooksByShop</attribute>
</collectionOperation>

然后创建控制器类:

// src/BooksBundle/Controller/BookCollectionController.php
namespace App\BooksBundle\Controller;

use App\BooksBundle\Entity\Book;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use ApiPlatform\Core\Serializer\SerializerInterface;

class BookCollectionController
{
    private $entityManager;
    private $serializer;

    public function __construct(EntityManagerInterface $entityManager, SerializerInterface $serializer)
    {
        $this->entityManager = $entityManager;
        $this->serializer = $serializer;
    }

    public function getBooksByShop(Request $request): Response
    {
        $shop = $request->get('shop');
        $books = $this->entityManager->getRepository(Book::class)->findBy(['shop' => $shop]);

        // 应用normalization_context中配置的序列化组
        $json = $this->serializer->serialize($books, 'json', [
            'groups' => ['books_list', 'list']
        ]);

        return new Response($json, Response::HTTP_OK, [
            'Content-Type' => 'application/json'
        ]);
    }
}

3. 可选:验证店铺存在性

如果需要确保{shop}对应的店铺真实存在,可以使用参数转换器自动加载Shop实体,不存在时自动返回404:
在控制器方法中添加参数转换器注解:

use App\BooksBundle\Entity\Shop;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @ParamConverter("shop", options={"mapping": {"shop": "slug"}})
 */
public function getBooksByShop(Shop $shop): Response
{
    $books = $this->entityManager->getRepository(Book::class)->findBy(['shop' => $shop]);
    // 后续序列化逻辑
}

完成以上配置后,启动服务器访问类似/my-shop/books的路径,就能获取对应店铺的书籍列表了。

内容的提问来源于stack exchange,提问作者Ivan Vulović

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:50:26