Syfmony - 启动时加载服务

时间:2015-10-14 19:06:35

标签: php symfony inversion-of-control

我发布了另一个question试图找到一种方法来静态访问自定义"帮助器"中控制器之外的存储库类。类。

到目前为止,我已经想出如何实现这一目标的唯一方法是使用下面的代码。如果有人想要提及另一个关于"最佳实践"或"设计模式"请做。

我打开这个问题,寻求在symfony启动时加载单件服务(?)的最佳方法,以便其他类可以静态访问它而不需要任何依赖注入。我找不到任何官方文档或常规做法,我没有多少运气。我知道单身是反实践,但是方法是最好的方法,还是有更理想的解决方案?

services.yml

parameters:
    entity.device: Asterisk\DbBundle\Entity\Device
services:
    asterisk.repository.device:
    class: Asterisk\DbBundle\Entity\Repositories\DeviceRepository
    factory: ["@doctrine.orm.asterisk_entity_manager", getRepository]
    arguments:
        - %entity.device%
    tags:
        - {name: kernel.event_listener, event: kernel.request, method: onKernelRequest}

DeviceRepository

class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
    /** @var  ExtendedEntityRepository */
    protected static $instance;

    public function __construct(EntityManager $entityManager, ClassMetadata $class)
    {
        parent::__construct($entityManager, $class);

        if(static::$instance instanceof static == false)
            static::$instance = $this;
    }

    public static function getInstance()
    {
        return static::$instance;
    }

    public function onKernelRequest($event)
    {
        return;
    }
}

2 个答案:

答案 0 :(得分:1)

很高兴看到你不再跑来跑去。

除非有人先将容器从容器中取出,否则你的方法不会起作用,因此初始化了self :: $ instance。但是你真的不想这样做。超级hacky。

您希望将存储库服务注入内核侦听器。尝试使存储库充当内核侦听器并不是一个好的设计。因此,只需为您的存储库提供服务,然后为侦听器提供第二个服务。起初看起来有点奇怪,但它在实践中确实很有效,而且它是S2的设计方式。

如果出于某种原因你仍然坚持你必须能够全局访问容器的概念,那么请注意你的内核是全局定义的(看看app.php)并且它有一个getContainer方法

$repo = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');

但同样,应该没有必要这样做。

==============================

更新 - 看起来您正在尝试使用侦听器功能来设置单例。你应该尽量避免单身,但如果你真的认为你需要它们,那么可以使用对内核的全局访问:

class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
  /** @var  ExtendedEntityRepository */
  protected static $instance;

  public static function getInstance()
  {
    if (!static::$instance) {
        static::$instance = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');
    }
    return static::$instance;
  }

糟糕的设计,但至少它可以摆脱听众的攻击,并避免在实际需要之前创建存储库。它也意味着您可以从命令访问存储库(调用命令时不会设置侦听器)。

答案 1 :(得分:0)

我不明白这种方法的利润是多少。 servicecontainer的想法是只为每个类创建一个实例,并向任何要求使用此相同实例的方法提供引用(或指针,如果您愿意)。让我来证明一下:

服务定义:

// app/config.yml
services:
    app.test:
        class: Vendor\AppBundle\Service\Test

和自定义类:

// src/AppBundle/Service/Test.php
namespace AppBundle/Service;

class Test {
    public $test = 0;
}

和控制器:

// src/AppBundle/Controller/DefaultController
namespace AppBundle/Controller;

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()
    {
        $instance1 = $this->get('app.test');
        $instance2 = $this->get('app.test');

        $instance1->test = 1;

        echo $instance2->test; // RETURNS 1 !!!
        exit;
    }