在API Platform中为嵌套实体创建自定义筛选器端点

DDD
发布: 2025-10-01 17:04:19
原创
183人浏览过

在api platform中为嵌套实体创建自定义筛选器端点

本文详细介绍了如何在Symfony和API Platform项目中,为嵌套实体(如产品模型中的品牌和产品类型)创建自定义API端点,以获取所有独特的品牌和产品类型列表。通过配置自定义操作、编写仓库方法进行数据查询,并创建控制器动作来整合并返回所需格式的数据,实现前端筛选器功能。

1. 需求分析与问题背景

在构建API驱动的应用程序时,经常需要为前端提供数据筛选功能。例如,一个产品列表可能需要按品牌或产品类型进行筛选。当这些筛选条件(如品牌和产品类型)作为嵌套实体(例如,Product 实体通过 ProductModel 关联到 Brand 和 ProductType)存在时,直接通过API Platform的默认机制获取所有唯一的品牌和产品类型列表会比较复杂。本教程将指导您如何创建一个自定义端点,以返回一个包含所有独特品牌和产品类型的JSON对象,格式如下:

{
    "brands": [
        "Agilent",
        "Comtr",
        "Anot"
    ],
    "types": [
        "Accelerometer",
        "Sonometer",
        "Micro-amplifier"
    ]
}
登录后复制

我们将使用API Platform的自定义操作(Custom Operations)功能,结合Symfony控制器和Doctrine实体仓库来完成此任务。

2. 定义自定义API Platform操作

首先,我们需要在相关的实体上定义一个自定义的集合操作(collection operation)。由于品牌(idBrand)和产品类型(idProductType)都直接关联在 ProductModel 实体上,我们将把这个自定义操作添加到 ProductModel 实体对应的 ApiResource 注解中。

打开 App\Entity\ProductModel 类,修改其 ApiResource 注解,添加一个名为 filters 的自定义操作:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\ProductModelRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity(repositoryClass=ProductModelRepository::class)
 * @ApiResource(
 *     itemOperations={"get"},
 *     collectionOperations={
 *          "get",
 *          "filters"={
 *             "method"="GET",
 *             "path"="/product_models/filters",
 *             "controller"=App\Controller\Action\DistinctFiltersAction::class,
 *             "openapi_context"={
 *                 "summary"="获取所有产品模型中唯一的品牌和产品类型",
 *                 "parameters"={}
 *             },
 *             "read"=false, // 表示此操作不用于获取单个资源
 *          }
 *     },
 *     normalizationContext={
 *     "groups"={"read"}}
 * )
 */
class ProductModel
{
    // ... 实体属性和方法
}
登录后复制

关键点解释:

  • "filters": 这是我们自定义操作的名称,您可以根据实际情况命名。
  • "method"="GET": 指定这是一个HTTP GET请求。
  • "path"="/product_models/filters": 定义了此自定义端点的URL路径。
  • "controller"=App\Controller\Action\DistinctFiltersAction::class: 指定处理此请求的自定义控制器类。
  • "openapi_context": 用于OpenAPI/Swagger文档的配置,这里添加了一个摘要信息。
  • "read"=false: 这是一个重要设置,它告诉API Platform此操作不是为了检索单个资源实例,而是处理集合级别的逻辑。

3. 实现仓库方法获取独特数据

接下来,我们需要在 ProductModel 对应的仓库(ProductModelRepository)中添加方法,用于从数据库中查询所有独特的品牌名称和产品类型名称。

打开 App\Repository\ProductModelRepository.php,添加以下两个方法:

<?php

namespace App\Repository;

use App\Entity\ProductModel;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @method ProductModel|null find($id, $lockMode = null, $lockVersion = null)
 * @method ProductModel|null findOneBy(array $criteria, array $orderBy = null)
 * @method ProductModel[]    findAll()
 * @method ProductModel[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class ProductModelRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, ProductModel::class);
    }

    /**
     * 获取所有独特的品牌名称列表。
     * 假设 Brand 实体有一个 'name' 属性。
     *
     * @return array
     */
    public function getDistinctBrands(): array
    {
        return $this->createQueryBuilder('pm')
            ->select('b.name') // 选择 Brand 实体的名称属性
            ->join('pm.idBrand', 'b') // 通过 idBrand 关联到 Brand 实体
            ->groupBy('b.name') // 按品牌名称分组以获取唯一值
            ->getQuery()
            ->getSingleColumnResult(); // 返回一个简单的字符串数组
    }

    /**
     * 获取所有独特的产品类型名称列表。
     * 假设 ProductType 实体有一个 'name' 属性。
     *
     * @return array
     */
    public function getDistinctProductTypes(): array
    {
        return $this->createQueryBuilder('pm')
            ->select('pt.name') // 选择 ProductType 实体的名称属性
            ->join('pm.idProductType', 'pt') // 通过 idProductType 关联到 ProductType 实体
            ->groupBy('pt.name') // 按产品类型名称分组以获取唯一值
            ->getQuery()
            ->getSingleColumnResult(); // 返回一个简单的字符串数组
    }
}
登录后复制

代码说明:

百度文心百中
百度文心百中

百度大模型语义搜索体验中心

百度文心百中 22
查看详情 百度文心百中
  • 我们使用 createQueryBuilder 来构建Doctrine查询。
  • select('b.name') 和 select('pt.name') 假设您的 Brand 实体和 ProductType 实体都包含一个名为 name 的属性来存储其名称。如果您的实体使用其他属性(例如 title 或 brandName),请相应地修改。
  • join('pm.idBrand', 'b') 和 join('pm.idProductType', 'pt') 用于将 ProductModel 实体与其关联的 Brand 和 ProductType 实体连接起来。
  • groupBy('b.name') 和 groupBy('pt.name') 是获取唯一值的关键。在SQL中,通过 GROUP BY 子句可以对结果集进行分组,结合 SELECT 选定的列,可以有效地获取该列的所有唯一值。
  • getSingleColumnResult() 是一个便捷的方法,它会返回查询结果的第一个(也是唯一一个)列作为一个简单的索引数组。

4. 创建自定义控制器动作

最后,我们需要创建在 ApiResource 注解中指定的控制器类 App\Controller\Action\DistinctFiltersAction。这个控制器将负责调用仓库方法,并将结果格式化成所需的JSON结构。

在 src/Controller/Action/ 目录下创建 DistinctFiltersAction.php 文件(如果 Action 目录不存在,请创建):

<?php

namespace App\Controller\Action;

use App\Repository\ProductModelRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class DistinctFiltersAction
 * @Route(
 *     path="/product_models/filters",
 *     methods={"GET"},
 *     defaults={"_api_resource_class"=ProductModel::class, "_api_collection_operation_name"="filters"}
 * )
 */
final class DistinctFiltersAction extends AbstractController
{
    /**
     * 处理获取独特品牌和产品类型列表的请求。
     *
     * @param ProductModelRepository $productModelRepository
     * @return JsonResponse
     */
    public function __invoke(ProductModelRepository $productModelRepository): JsonResponse
    {
        // 调用仓库方法获取独特的品牌和产品类型
        $brands = $productModelRepository->getDistinctBrands();
        $types = $productModelRepository->getDistinctProductTypes();

        // 将结果格式化为所需的JSON结构并返回
        return new JsonResponse([
            'brands' => $brands,
            'types' => $types,
        ]);
    }
}
登录后复制

代码说明:

  • AbstractController: 继承自Symfony的抽象控制器,可以方便地访问服务容器。
  • __invoke(): 这是一个PHP的魔术方法,当对象被当作函数调用时会自动执行。API Platform会直接调用此方法。
  • ProductModelRepository $productModelRepository: 通过依赖注入,Symfony会自动将 ProductModelRepository 实例传递给控制器。
  • JsonResponse: Symfony提供的类,用于方便地返回JSON格式的响应。

注意事项:

  • 路由冲突: 在 ApiResource 注解中定义了 path,通常情况下不需要在控制器中再次使用 @Route 注解。但是,如果您希望在不依赖 ApiResource 注解的情况下也能访问此控制器(例如,作为常规Symfony路由),或者需要更细致的路由配置,可以添加。在本教程中,ApiResource 的定义已足够。
  • 命名空间: 确保控制器文件位于正确的命名空间 App\Controller\Action 下。

5. 测试与验证

完成以上步骤后,您可以通过以下方式验证您的自定义端点:

  1. 更新Composer和清除缓存:
    composer dump-autoload
    php bin/console cache:clear
    登录后复制
  2. 查看路由: 运行Symfony的路由调试命令,确认您的自定义路由已正确注册:
    php bin/console debug:router
    登录后复制

    您应该能看到类似 /product_models/filters 的路由。

  3. 访问端点: 使用您的API客户端(如Postman、Insomnia或浏览器)访问 GET /product_models/filters 端点(例如 http://localhost:8000/api/product_models/filters),您将获得一个包含独特品牌和产品类型列表的JSON响应。

6. 总结

通过结合API Platform的自定义操作、Doctrine实体仓库的强大查询能力以及Symfony控制器的灵活性,我们成功地为嵌套实体创建了一个高效且结构化的筛选器数据端点。这种方法不仅满足了前端对独特数据列表的需求,也保持了API的整洁和专业性。在实际项目中,您可以根据需要扩展这些仓库方法,例如添加分页、排序或更复杂的筛选逻辑,以适应不断变化的业务需求。

以上就是在API Platform中为嵌套实体创建自定义筛选器端点的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号