你如何在 Symfony3 控制器之外调用服务?以及来自 Repository 的查询

How do you call a Service outside of a Symfony3 controller? And queries from Repository

我今天有两个问题。说的很详细,因为其他太多的回复都是靠假设,不够详细。我希望这很详细并且能够帮助很多开发人员。

第一。下面的代码指出了我的真正问题。由于 $this->get() 方法仅在控制器内部,您如何在控制器外部调用服务?这不在任何文档或 KNP 大学的服务教程中。

第二。从我读到的内容来看,根据一些(不是全部),如果您从任何地方调用存储库,它应该自动实例化实体存储库。我不认为是这样。告诉我我是对还是错。

见下文....

我的默认控制器,直接调用 class 让它做一些工作。例如,我用一个服务和一个传统的 OO 方法调用它:

<?php
//  src/AppBundle/Controller/DefaultController.php
//  Here is where I am starting.  There is a service 
//  and there is a conventional OO call.
//  Both should invoke the same thing.

namespace AppBundle\Controller;

use AppBundle\Service;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction(Request $request)
    {

        //  Step 1.... Do a little of this.
        //  Step 2.... Do some of that.
        //  Step 3.... Call another class to do some logic and it will
        //  eventually call a query...

        //  Invoking my service
        $obj_via_service = $this->get('app.services.process_question');
        $result1 = $obj_via_service->submitQuestion();

        //  Invoking via Namespace and Call
        $obj_via_new = new Service\ProcessQuestion();
        $result2 = $obj_via_new->submitQuestion();

        dump($result1);
        dump($result2);
        die();
    }
}

我的 Service.yml 文件。

#   src/app/config/services.yml
parameters:

services:
    app.services.process_question:
        class: AppBundle\Service\ProcessQuestion

    app.rep.geo_state:
        class: AppBundle\Entity\GeoStateRepository
        arguments: ['@doctrine.orm.entity_manager']

这是我的 class 正在为我完成工作。我希望能够调用第二个服务 ^^ 以上 ^^ 但我不能,因为我不能在控制器之外使用 $this->get()

<?php
//  src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;

class ProcessQuestion
{
    public function submitQuestion()
    {
        //  Step 1.... Do this.
        //  Step 2.... Do that.
        //  Step 3.... Query for some data...

        //  Invoke my repository class via a Service Call....
        //  but I cannot do that because 'get' is a part of the
        //  controller...
        $obj_via_service = $this->get('app.rep.geo_state');
                           **^^                         ^^**
                           **^^ This is what won't work ^^**

        $results = $obj_via_service->selectStates();

        return $results;
    }
}

我的存储库Class...请记住,我还不能到达这个class,但我把它扔在这里,以便其他新的 Symfony 3 开发人员可以看到这个.

<?php
//  src/AppBundle/Repository/GeoState.php
//  My Repository Class where I want to do some queries...
namespace AppBundle\Repository;

use Doctrine\ORM\EntityRepository;

class GeoStateRepository extends EntityRepository
{
    /**
     * @Mapping\Column(type="string")
     */
    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function selectStates()
    {
        $sql = "SELECT * FROM geo_state";
        return $this->getEntityManager()->createQuery($sql)->getResult();
    }
}

为什么这么难找到一个例子?此外,我遵循了一堆 Symfony 2.x 文档,有时很难将细微差别移植到 Symfony 3 中。

我认为 Fabian 为 2.x 重新设计了太多文档以进入 3.x 并且没有任何关于新开发人员级别和硬核开发人员之间的编码的好例子等级。如果您在 Sensio 阅读本文,请记住,我们需要考虑一个中间地带,大部分截屏视频和很多更好的文档都不是英文的。

你真的应该阅读更多关于 Dependency Injection.

Symfony 非常擅长这一点。

关于您关于在 app.services.process_question 服务中使用 app.rep.geo_state 服务的问题。

在 Symfony/DI 术语中,它可以被称为将一个服务注入另一个服务。

documentation 关于如何做到这一点非常好。

这是可以做到的。

services:
    app.services.process_question:
        class: AppBundle\Service\ProcessQuestion
        arguments: ['@app.rep.geo_state']

    app.rep.geo_state:
        class: AppBundle\Entity\GeoStateRepository
        arguments: ['@doctrine.orm.entity_manager']

并且在 class

<?php
//  src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
use AppBundle\Entity\GeoStateRepository;

class ProcessQuestion
{

    private $geoRepository;

    public function __construct(GeoStateRepository $geoRepository)
    {
        $this->geoRepository = $geoRepository;
    }

    public function submitQuestion()
    {
        //now you can call $this->geoRepository 
    }
}

另请注意,$this->get()只是Symfony基础控制器class提供的访问容器的快捷函数。

想了解更多关于 DI 的知识,你可以在 his blog 阅读 Fabian 关于这方面的优秀文章。