4

我试图 getDoctrine() 在控制器之外。我创建了这个服务:

配置/服务.yml

services:
  update_command:
    class: project\projBundle\Command\Update
    arguments: ['@doctrine.orm.entity_manager']

在我的 app/config/config.yml

imports:
    - { resource: "@projectprojBundle/Resources/config/services.yml" }

所以和我想使用的类:

namespace project\projBundle\Command;
use Doctrine\ORM\EntityManager;

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

但每次我想这样做时:(我这样做对吗?

$up = new Update();

我收到了这个错误:

Catchable Fatal Error: Argument 1 passed to ...\Update::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in .../Update.php line 7  
4

3 回答 3

7

简单的解决方案

如果您正在实现一个 Symfony 命令(可以在 cron 选项卡中执行),您可以从该命令访问服务容器。

<?php
namespace MyProject\MyBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Doctrine\ORM\EntityManager;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class UpdateCommand extends ContainerAwareCommand
{
    protected $em;

    protected function configure()
    {
        $this->setName('myproject:mybundle:update') ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->em = $this->getContainer()->get('doctrine.orm.entity_manager');
    }
}

这样,您可以从命令中获取实体管理器,而无需将此类声明为服务。因此,您可以删除您在services.yml文件中添加的配置。

另一种解决方案(清洁剂)

这个解决方案可以更好地分离关注点,因此可以很容易地在 Symfony 应用程序的其他部分进行单元测试和重用(不仅仅是作为命令)。

将“更新”命令的所有逻辑部分移动到您将声明为服务的专用类:

<?php
namespace MyProject\MyBundle\Service;

use Doctrine\ORM\EntityManager;

class MyUpdater
{
    protected $em;

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

    public function runUpdate()
    {
        // All your logic code here
    }
}

services.yml在您的文件中将其声明为服务:

services:
    myproject.mybundle.myupdater:
        class: MyProject\MyBundle\Service\MyUpdater
        arguments: ['@doctrine.orm.entity_manager']

只需从您的命令调用您的服务:

<?php
namespace MyProject\MyBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class UpdateCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this->setName('myproject:mybundle:update') ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $myUpdater = $this->getContainer()->get('myproject.mybundle.myupdater');
        $myUpdater->runUpdate();
    }
}
于 2013-11-08T09:57:43.233 回答
2

您必须注入新创建的@update_command服务或从容器中获取它才能@doctrine.orm.entity_manager自动注入服务。

您只是在创建没有参数的对象,而不是服务。更新期望检索实体管理器实例,但您不提供它。

$up = new Update();

ContainerAware像控制器这样的类中,得到你的服务是这样的:

 $up = $this->container->get('update_command');

否则,将您要使用的类也转换为服务,并像在服务本身中使用实体管理器一样update_command注入。@update_command

于 2013-11-08T09:30:53.007 回答
0

删除 app/config/config.yml 中的以下代码,您的 services.yml 将自动加载...

imports:
    - { resource: "@projectprojBundle/Resources/config/services.yml" }

在 Action new a 实例中,您可以执行以下操作:

  $up = $this->get('update_command');
于 2013-11-08T09:30:11.910 回答