无法弄清楚如何制定我需要的正确存储库方法

时间:2019-10-29 23:03:22

标签: symfony doctrine repository relation

我正在尝试使用实体产品和实体商店之间的联接来创建QueryBuilder。我想展示所有与OneStore相关的产品。他们有多对多的关系。我不知道如何获取ID。请哭。预先感谢!

这是我的product_store表的屏幕截图:

https://imgur.com/a/wUZMEEn

因此,如果我很清楚我的英语能力,那么您了解我只想显示与一个商店ID相关的产品。

让我们举个例子。如果我在/ store / detail / {1}页面上,我想显示产品ID 1,3,6,8,10,13,因为它们与store.id = 1相关。

因此,按照我的建议,我进行了更新,但是它不起作用,并且我没有发现错误所在。我在哪里弄错了? (控制器已更新)

这是我得到的错误: https://imgur.com/a/q3Uun3E

----------------------我的存储库功能---------------------- -------


public function getProductsForStore($sid)
    {
        return $this->createQueryBuilder('s')
            ->join('s.product', 'p')
            ->addSelect('p')
            ->andWhere('s.id = :sid')
            ->orderBy('p.name', 'ASC')
            ->setParameter('sid', $sid)
            ->getQuery()
            ->getResult();
    }

商店实体中的$ produt:


/**
     *
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="App\Entity\Product", mappedBy="store")
     * * @ORM\JoinTable(name="product_store",
     *   joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")},
     *   inverseJoinColumns={@ORM\JoinColumn(name="store_id", referencedColumnName="id")}
     * )
     */
    private $product;

$ store在产品实体中:


/**
     * * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="App\Entity\Store", inversedBy="product")
     * * @ORM\JoinTable(name="product_store",
     *   joinColumns={@ORM\JoinColumn(name="store_id", referencedColumnName="id")},
     *   inverseJoinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")}
     * )
     */
    private $store;

我的控制器功能:


/**
     * @Route("stores/detail/{id}", name="detail_store"))
     */
    public function getOneStore(StoreRepository $repository, Store $store): Response
    {
        $store = $repository->findOneBy(array(
            'id' => $store->getId(),
        ));
        $products_store = $repository->getProductsForStore(':id');

        return $this->render('store.html.twig', array(
            'store' => $store,
            'product' => $products_store,
        ));
    }

2 个答案:

答案 0 :(得分:0)

我确实想知道为什么要从一个商店获取所有产品,为什么要进行自定义查询。

建立多对多关系(希望与制造商捆绑销售)时,还应该在Store实体中添加一个吸气剂($store->getProducts()),以获取该商店的所有产品。

无论如何,这是您的查询...

public function getAllProductsFromOneStore(Store $store) {
    $qb=$this->createQueryBuilder('store');

    $qb->addSelect('product')
       ->join('store.product', 'product')
       ->andWhere('store.id = :storeId')
       ->setParameters(array(
           'storeId'=>$store->getId();
       ));

    return $qb->getQuery->getResult();
}

以上查询应返回一家商店的所有产品。
另外,永远不要使用where(),永远不要使用andWhere()Read more about it here.

[编辑]

响应您的编辑。正如Frank B所说,您可以做得更好。
首先,正如我所说,您不需要自定义查询。
相反,请在StoreProduct实体中进行吸气。

src / Entity / Store.php

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

class Store {
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Product", inversedBy="stores")
     */
    private $products;

    public function __construct() {
        $this->products=new ArrayCollection();
    }


    /**
     * GETTER
     * 
     * @return Collection|Product[]
     */
    public function getProducts(): Collection {
        return $this->products;
    }

    /**
     * ADD A PRODUCT TO A STORE
     */
    public function addProduct(Product $product): self {
        if(!$this->products->contains($product)) {
            $this->products[]=$product;
        }

        return $this;
    }

    /**
     * REMOVE A PRODUCT FROM A STORE
     */
    public function removeProduct(Product $product): self {
        if($this->products->contains($product)) {
            $this->products->removeElement($product);
        }

        return $this;
    }
}

src / Entity / Product.php

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

class Product {
    private $stores;

    public function __construct() {
        $this->stores=new ArrayCollection();
    }

    /**
     * GETTER
     * 
     * @return Collection|Store[]
     */
    public function getStores(): Collection {
        return $this->stores;
    }
    /**
     * ADD A STORE TO A PRODUCT
     */
    public function addStore(Store $store): self {
        if(!$this->stores->contains($store)) {
            $this->stores[]=$store;
            $store->addProduct($this);
        }

        return $this;
    }

    /**
     * REMOVE A STORE FROM A PRODUCT
     */
    public function removeStore(Store $store): self {
        if($this->stores->contains($store)) {
            $this->stores->removeElement($store);
            $store->removeProduct($this);
        }

        return $this;
    }
}

现在在您的控制器中,您要做的就是调用您的吸气剂。
教义将为您处理查询:

/**
 * @Route("stores/store-{id}", name="index_store"))
 */
public function index(Store $store): Response {
    $products=$store->getProducts();

    return $this->render('store.html.twig', array(
        'store'=>$store,
        'products'=>$products,
    ));
}

然后在您的树枝视图中:

{% for product in store.products %}
    // Your code here
{% endfor %}

就是这样。在实体中使用吸气剂后,就不需要自定义查询。

请注意,您可以对Product$product->getStores())进行相同操作,以了解可以在哪家商店中找到您的产品。

答案 1 :(得分:0)

您最好将属性称为$ stores和$ products,而不是单数版本,以明确说明我们所讨论的数组或集合可能包含多个商店或产品。您确实不需要注释的第二至第四条规则。只是

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Product", mappedBy="store")
 */

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Store", inversedBy="product")
 */

可以。它告诉我们您使用双向的ManyToMany关系。 “商店”和“产品”实体都拥有相反实体的列表。因此,您可以查询具有产品集合的商店或具有商店集合的产品。

  

在控制器中使用$ store-> getProducts()的正确方法是什么?

因此在第一个答案中交换产品,反之亦然:

    public function getStore($sid)
    {
        return $this->createQueryBuilder('s')
            ->join('s.product', 'p')
            ->addSelect('p')
            ->andWhere('s.id = :sid')
            ->orderBy('p.name', 'ASC')
            ->setParameter('sid', $sid);
            ->getQuery()
            ->getResult()
        ;
    }

控制器:

    /**
     * @Route("/{id}", name="store_show", methods={"GET"})
     */

    public function show($id): Response
    {
        $em = $this->getDoctrine()->getManager();
        $em->getRepository('App:Store')->getStore($id);

        if(null === $store) {
            throw $this->createNotFoundException('Store not found.');
        }

        return $this->render('store/show.html.twig', [
            'store' => $store,
        ]);
    }

嫩枝:

{% extends 'base.html.twig' %}

{% block title %}Store{% endblock %}

{% block body %}
    <h1>{{ store.name }}</h1>

    <table class="table">
        <thead>
            <tr>
                <th>ProductId</th>
                <th>ProductName</th>
            </tr>
        </thead>
        <tbody>
        {% for product in store.products %}  {# loop through all products in store #}
            <tr>
                <td>{{ product.id }}</td>
                <td>{{ product.name }}</td>
            </tr>
        {% else %}
            <tr>
                <td colspan="4">no records found</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}