【问题标题】:Symfony2-How to use access a service from outside of a controllerSymfony2-如何使用从控制器外部访问服务
【发布时间】:2016-09-08 00:03:54
【问题描述】:

在我的 Symfony2 控制器中,这可以正常工作:

$uploadManager = $this->get('upload.upload_manager');

但是当我将其移至自定义侦听器时:

use Doctrine\ORM\Event\LifecycleEventArgs;
use Acme\UploadBundle\Upload\UploadManager;

class PersonChange
{
    public function postRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        $uploadManager = $this->get('ep_upload.upload_manager');
        echo "the upload dir is " . $uploadManager->getUploadDir();
    }
}

我收到一个错误:

Fatal error: Call to undefined method Acme\MainBundle\Listener\PersonChange::get() in /home/frank/...

我知道我必须需要一个 use 语句,但不知道该使用什么。

【问题讨论】:

标签: symfony


【解决方案1】:

更新:Symfony 不再正式推荐将控制器定义为服务。

Controller 类中的get() 方法只是从容器中获取服务的辅助方法,它旨在让新的 Symfony2 开发人员更快上手。 一旦人们对框架和依赖注入感到满意,建议define controllers as services 并明确注入每个所需的服务。

由于您的 PersonChange 类不是控制器并且不扩展 Controller 类,因此您没有 get() 辅助方法。相反,您需要将您的类定义为服务并显式注入所需的服务。阅读Service Container chapter了解详情。

【讨论】:

  • 字面意思是第一句话:将控制器定义为服务是 Symfony 不正式推荐的。
  • 我的回答已经过去了 4 年。最佳实践不断发展。
  • 是的,但是在谷歌搜索时仍然很容易找到这个答案。应该更新它以符合当前的 Symfony 实践。
  • 那么 2016 年推荐的方法是什么?
【解决方案2】:

当我遇到完全相同的问题时,也许我可以提供帮助

Elnur 说的非常好,我将尝试弹出一个现实生活中的例子。

就我而言,我想访问

$lucenemanager = $this->get('ivory.lucene.manager')

即使通过扩展控制器,当控制器确实访问容器时,我也无法让它工作(我仍然不明白为什么)

在 config.yml 我的监听器 (searchindexer.listener) 声明如下:

   services:
    searchindexer.listener:
        class: ripr\WfBundle\Listener\SearchIndexer
        arguments:
              luceneSearch: "@ivory_lucene_search"
        tags:
            - { name: doctrine.event_listener, event: postPersist }

服务 (ivory.lucene.search) 在我的服务/侦听器中作为参数传递。

然后在我的课堂上

protected $lucenemanager;

        public function __construct($luceneSearch)
        {
            $this->lucenemanager = $luceneSearch;
        }

然后你可以对 $this 使用 get 方法

【讨论】:

    【解决方案3】:

    尽管不是 OO 中的最佳实践,但始终有效的方法

    global $kernel;
    $assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏
    

    【讨论】:

      【解决方案4】:

      如果你需要访问一个Service,在类构造函数中定义它:

      class PersonChange{
          protected $uploadManager;
          public function __construct(UploadManager $uploadManager){
              $this->uploadManager = $uploadManager;
          }
          // Now you can use $this->uploadManager.
      }
      

      现在您可以在调用类时将 Service 作为参数传递(示例 1)或将类本身定义为服务(推荐,示例 2)

      示例 1:

      use Acme\PersonChange;
      class appController{
          function buzzAction(){
              $uploadManager = $this->get('upload.upload_manager');
              $personChange = new PersonChange($uploadManager);
      

      示例 2(更好)

      PersonChange定义为Service本身,并将另一个Service定义为services.yml文件中的参数:

       # app/config/services.yml
      services:
          upload.upload_manager:
              class:     AppBundle\uploadManager
      
          PersonChange:
              class:     AppBundle\PersonChange
              arguments: ['@upload.upload_manager']
      

      通过这种方式,您不必为控制器中的upload_manager 服务而烦恼,因为它作为构造函数的参数隐式传递,因此您的控制器可以:

      class appController{
          function buzzAction(){
              $personChange = $this->get('PersonChange');
      

      【讨论】:

        猜你喜欢
        • 2011-09-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-30
        相关资源
        最近更新 更多