具有未与Symfony中的实体相关联的自定义存储库

时间:2018-10-31 19:17:45

标签: symfony doctrine-orm

我有一个DefaultRepository文件,可以在其中放置所有常规查询。

是否可以有一个不与Symfony中的实体相关联的自定义存储库?我想在其中添加一些不适用于其他存储库的本机SQL(它可能引用抽象或实体层次结构)。

控制器代码如何

$this->getDoctrine()->getRepositoty(/* ??? */) should be replaced?

3 个答案:

答案 0 :(得分:1)

您可以有一个自定义的通用“存储库”,但不会通过Doctrine EntityManager进行检索。而是直接将其注入Controller。

您的存储库可能看起来像这样:

class MyRepository implements RepositoryInterface
{
    private $entityManager;

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

    public function findFoo()
    {
        $builder = $this->entityManager->createQueryBuilder();

        $query = $builder->... // build query

        return $query->getResult();
    }

    // Implement the generic find-methods defined by the interface
}

当您直接使用存储库时,不是必须实施接口,而是会使它更加熟悉。通过注入entityManager,您可以调用其他存储库以获取数据或创建查询构建器来编写自己的查询。

然后在您的控制器中注入存储库或从容器中获取存储库,例如像这样:

class FooController extends Controller
{
    private $repository;

    public function __construct(MyRepository $repository)
    {
        $this->repository = $repository;
    }

    public function indexAction(Request $request)
    {
        $foo = $this->repository->findFoo();
    }
}

您还可以将您的存储库定义为服务:

# app/config/services.yml
services:
    app.my_repository:
        class: App\Repository\MyRepository
        arguments:
            - '@doctrine.orm.entity_manager'

,然后使用helper方法在控制器中检索您的存储库,而不是注入它:

$this->get('app.my_repository');

请注意,

  • 由于您实际上无法使用RepositoryInterface定义的方法,因为您不想使用单个实体,例如findOneBy很有道理,不实现该接口也很有意义。
  • 您也可以给这些类一个不同的名称。例如,您可以将每个查询放入自己的类中,并具有一个FindFooQuery类,您可以将其作为服务注入到控制器中。这样一来,更清楚的是,这实际上并不与实体相关,而是属于自己的事情。当您有很多查询时,这可能会使此方法更易于管理。

答案 1 :(得分:1)

您想要的不是存储库。存储库链接到Doctrine中的实体,并提供“ findOneBy”等功能。 从实体的上下文出发,这没有任何意义。 如果您需要存储自定义查询,您仍然可以添加服务并将其注入“ Doctrine Manager”(或仅注入所需的实体存储库)。 然后,您可以在控制器中轻松使用服务。

在您的services.yaml文件中,您将具有以下内容:

services:
    App\Services\QueriesManager:
        autowire: true

您的服务看起来像(App \ Services \ QueriesManager)

<?php

namespace App\Services;

use Doctrine\ORM\EntityManagerInterface;

class QueriesManager {
    protected $entityManager;

    __construct(EntityManagerInterface $entityManager) {
        $this->entityManager = $entityManager;
    }

    public function getSpecialQueryResult() {
        $qb = $this->entityManager->createQueryBuilder();
        $qb->select(...)
           ->where(...)
        return $qb->getQuery()->getResult();
    }
}

在您的控制器中,您可以仅在要使用它的方法上键入它的提示,例如:

class MyController {
    public function indexAction($param1, \App\Services\QueriesManager $queriesManager) {
        return $queriesManager->getSpecialQueryResult();
    }
}

答案 2 :(得分:0)

感谢您的回答。

这是我的解决方案:https://stackoverflow.com/a/53098008/2400373

使用symfony 3.3.x在这里,我对如何解决问题进行了总结

文件service.yml:

//service.yml
services:
     app.queriesmanager:
          class: AppBundle\Services\QueriesManager
          autowire: true

AppBundle \ Services \ QueriesManager.php文件

//AppBundle\Services\QueriesManager.php
<?php

namespace AppBundle\Services;

use Doctrine\ORM\EntityManagerInterface;

class QueriesManager  {
    protected $entityManager;

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

    public function searchAdvance($var,$var1,$var2,$var3)
    {
        $dql1 = "";
        $dql2 = "";
        $dql = "SELECT pl
                      FROM BackendBundle:Products p
                      JOIN BackendBundle:Pricelist pl
                      WITH p.peachitemid =  pl.peachitemid
                      WHERE p.hasimages =  1
                      AND p.active = 'FALSE'
                      AND p.imagesamazon1 = 1
                      AND p.imagesamazon2 = 1
                      AND (p.descriptionforsales like '%$var%' OR p.itemid like '%$var%')";

        if ($var1 != "select") {
            $dql1 = " AND p.newcategory='$var1' AND p.newsubcategory='$var2' ";
        }
        if ($var3 == "150") {
            $dql2 = " AND pl.retail < 150";
        }
        if ($var3 == "200") {
            $dql2 = " AND pl.retail > 150 AND pl.retail < 250 ";
        }
        if ($var3 == "250") {
            $dql2 = " AND pl.retail > 250 ";
        }

        $dql1 .= $dql2;
        $dql .= $dql1;
        $query=$this->entityManager->createQuery($dql);
        $query = $query->getResult();
        return $query;

    }
}

DefaultController.php文件

//Use the service in controller
$query=$this->get('app.queriesmanager')->searchAdvance($var,$var1,$var2,$var3);

更新

对于symfony 4.x,您需要更改服务中的行

app.queriesmanager:
        class: App\Services\QueriesManager
        public: true

谢谢,希望您能提供帮助。