Symfony2 getdoctrine outside of Model/Controller

2019-03-21 13:54发布

问题:

I'm trying to getDoctrine() outside of the controller. I've created this service:

config/services.yml

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

and in my app/config/config.yml

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

so and the class that I want to use:

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

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

but every time I want to do this: (I'm doing this right?)

$up = new Update();

i got this error:

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  

回答1:

Simple solution

If you're implementing a Symfony command (that can be executed in a cron tab), you can access the service container from the command.

<?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');
    }
}

That way, you get the entity manager from a command and don't need to declare this class as a service. You can therefore remove the configuration you added in the services.yml file.

An other solution (cleaner)

This solution allows better separation of concerns and can therefore be easily unit tested and reused in other parts of your Symfony application (not only as a command).

Move all the logic part of your "update" command to a dedicated class that you will declare as a service:

<?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
    }
}

Declare it as a service in your services.yml file:

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

Simply call your service from your command :

<?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();
    }
}


回答2:

You have to either inject your newly created @update_command service or get it from the container in order to have the @doctrine.orm.entity_manager service injected automatically.

You're just creating the object with no argument, not a service. Update expects to retrieve an entity manager instance but you don't provide it.

$up = new Update();

In a ContainerAware class like a controller get your service like this:

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

Otherwise turn the class where you want to use the update_command into a service aswell and inject @update_command as you did with the entity manager in the service itself.



回答3:

remove below codes in app/config/config.yml, your services.yml will be autoload...

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

in a Action new a instance you can do:

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