如何获取我的产品实体的所有品牌的列表?

Posted

技术标签:

【中文标题】如何获取我的产品实体的所有品牌的列表?【英文标题】:How to get a list of all the brands of my product entity? 【发布时间】:2021-12-25 17:33:30 【问题描述】:

我是 Symfony 和 API 平台的新手,并试图了解如何将我的产品的所有独特品牌和产品类型放在一个列表中,以便我以后可以使用它们来显示要在我的前端使用的过滤器列表。

我对如何做到这一点有点迷茫。我想要一个自定义端点产品/过滤器,它会返回列表。

我想要这种形式:


brands: [
    "Agilent",
    "Comtr"
    "Anot
    ],
types:[
     "Accelerometer",
     "Sonometer",
     "Micro-amplifier"
]

brand 和 type 都是我的实体 Product 的嵌套属性,它们来自我的实体 ProductModel。我正在为我的 api 使用 Api 平台,这就是为什么有很多注释。

class Product

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("product_get", "product_list")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=ProductModel::class, cascade="persist")
     * @ORM\JoinColumn(nullable=false)
     * @Groups("product_get", "product_list")
     */
    private $idProductModel;

    /**
     * @ORM\Column(type="string", length=50)
     * @Groups("product_get", "product_list")
     * @Assert\NotBlank(message="The field serial number is mandatory.")
     */
    private $serialNumber;

    /**
     * @ORM\Column(type="text", nullable=true)
     * @Groups("product_get")
     */
    private $comment;

    /**
     * @ORM\Column(type="datetime")
     * @Groups("product_get", "product_list")
     */
    private $createdAt;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups("product_get", "product_list")
     */
    private $updatedAt;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups("product_get")
     *
     */
    private $deletedAt;

    /**
     * @ORM\Column(type="boolean")
     * @Groups("product_get", "product_list")
     * @Assert\NotBlank(message="The field confidential is mandatory.")
     *
     */
    private $confidential;

    /**
     * @ORM\ManyToOne(targetEntity=Storage::class, cascade="persist")
     * @Groups("product_get", "product_list")
     */
    private $idStorage;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, cascade="persist")
     * @ORM\JoinColumn(nullable=false)
     * @Groups("product_get", "product_list")
     */
    private $idUser;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, cascade="persist")
     * @Groups("product_get")
     */
    private $idUserDelete;

    /**
     * Many products can have many products
     * @ORM\ManyToMany(targetEntity=Product::class, mappedBy="myProducts")
     */
    private $partOfthisProduct;

    /**
     * Many products can have many products
     * @ORM\ManyToMany(targetEntity=Product::class, inversedBy="partOfthisProduct")
     * @JoinTable(name="product_has_product",
     *      joinColumns=@JoinColumn(name="product_id", referencedColumnName="id"),
     *      inverseJoinColumns=@JoinColumn(name="related_product_id", referencedColumnName="id")
     *      )
     * @Groups("product_get", "product_list")
     */
    private $myProducts;

    /**
     * @ORM\OneToMany(targetEntity=Sensor::class, mappedBy="product", cascade="persist")
     * @Groups("product_get", "product_list")
     * @ApiSubresource()
     */
    private $sensors;



<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use App\Repository\ProductModelRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ManyToMany;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\JoinColumn;

/**
 * @ORM\Entity(repositoryClass=ProductModelRepository::class)
 * @ApiResource(
 *     itemOperations="get",
 *     collectionOperations="get",
 *     normalizationContext=
 *     "groups"="read"
 * )
 */
class ProductModel

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("read", "product_get", "product_list")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=50)
     * @Groups("read", "product_get", "product_list")
     */
    private $modelName;

    /**
     * @ORM\ManyToOne(targetEntity=ProductType::class, cascade="persist")
     * @ORM\JoinColumn(nullable=false)
     * @Groups("read", "product_get", "product_list")
     */
    private $idProductType;

    /**
     * @ORM\ManyToOne(targetEntity=Unit::class)
     */
    private $idInputUnit;

    /**
     * @ORM\ManyToOne(targetEntity=Unit::class)
     */
    private $idOutputUnit;


    /**
     * @ORM\ManyToOne(targetEntity=Brand::class, cascade="persist")
     * @ORM\JoinColumn(nullable=false)
     * @Groups("read", "sensor_get", "product_list")
     */
    private $idBrand;

    /**
     * @ORM\ManyToMany(targetEntity=TestType::class)
     * @Groups("read", "sensor_get",  "product_get")
     */
    private $idTestsTypes;

    /**
     * @ORM\Column(type="integer", nullable=true)
     * @Groups("read", "sensor_get")
     */
    private $periodicity;

    /**
     * @ORM\Column(type="float", nullable=true)
     * @Groups("read", "sensor_get", "product_get")
     */
    private $nominalSensitivity;

    /**
     * @ORM\ManyToOne(targetEntity=TestType::class)
     * @Groups("read", "sensor_get",  "product_get")
     */
    private $periodicityTest;


    /**
     * Many ProductModel have Many SensorModel.
     * @ManyToMany(targetEntity="SensorModel")
     * @JoinTable(name="productModel_sensorModels",
     *      joinColumns=@JoinColumn(name="Product_model_id", referencedColumnName="id"),
     *      inverseJoinColumns=@JoinColumn(name="Sensor_Model_id", referencedColumnName="id", unique=true)
     *      )
     * @Groups("read", "sensor_get",  "product_get")
     */
    private $sensorModels;


这样做的方法是什么?感谢您的帮助。

【问题讨论】:

【参考方案1】:

认为最好的方法是使用从实体存储库调用方法的自定义操作。

首先,您将自定义操作添加到您的 @ApiResource 定义中,在本例中为 collectionOperations 部分。

/**
 * @ApiResource(
 *     itemOperations="get","put","delete",
 *     collectionOperations=
 *          "get","post",
 *          "types"=
 *             "method"="GET",
 *             "path"="/product_models/brands",
 *             "controller"=DistinctBrandsAction::class,
 *             "openapi_context"=
 *                 "parameters"=
 *             ,
 *             "read"=false,
 *          
 *     
 * )
 * @ORM\Entity(repositoryClass=Repository::class)
 */

然后您将一个方法添加到实体的存储库(在您的情况下为 ProductModelRepository)。

此方法将查询集合并获取所需列的不同值。您必须稍微修改一下才能获得您想要的确切输出(添加产品类型等):

//..blah blah.. use statements etc.

class ProductModelRepository extends ServiceEntityRepository

    public function __construct(ManagerRegistry $registry)
    
        parent::__construct($registry, Report::class);
    

    //this is the method you're adding:
    //for symfony 3+ you use groupBy() instead of distinct() to get distinct values for a column
    public function getDistinctBrands() 
        return $this->createQueryBuilder('r')
            ->select('r.idBrand')
            ->groupBy('r.idBrand')
            ->getQuery()
            ->getResult();
    

然后您需要为您配置的操作创建一个控制器,该控制器调用您添加到存储库的方法,然后将其输出。 (如果您使用自动装配,这将进入 src/Controller/Action/DistinctBrandsAction.php)

<?php
namespace App\Controller\Action;

use App\Entity\Report;
use App\Repository\ProductModelRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

/**
 * Class DistinctBrandsAction
 */
final class DistinctBrandsAction extends AbstractController

    /**
     * @param ProductModelRepository $productRepository
     * @return Array
     */
    public function __invoke(ProductModelRepository $productRepository): Array
    
        return $productRepository->getDistinctBrands();
    

您可以使用控制台查看生成的路由是什么。运行php bin/console debug:router时,它应该与您的 ProductModel 路由分组

进一步阅读: https://api-platform.com/docs/core/pagination/#custom-controller-action

【讨论】:

以上是关于如何获取我的产品实体的所有品牌的列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取亚马逊 MWS 的所有产品列表

如何从核心数据中的实体中获取所有项目的列表,每个项目只出现一次?

如何从核心数据中获取最多计数的字符串值

如何使用谓词过滤子实体集合?

如何通过后端基于过滤器获取计数

如何初始化通过远程方法调用获取的 Hibernate 实体?