启动时的同步加载服务


Syfmony - load service on boot

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

到目前为止,我所知道的实现这一点的唯一方法是使用下面的代码。如果有人想回答关于"最佳实践"或"设计模式"的其他问题,请回答。

我打开这个问题是为了寻求在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;
    }
}

很高兴看到你不再到处乱跑了。

你的方法是不会工作的,除非有人先从容器中抓取存储库,所以self::$instance被初始化。但你真的不想这么做。超级出租汽车司机。

您希望将存储库服务注入内核侦听器。试图让存储库充当内核侦听器并不是一个好的设计。因此,只需为存储库创建一个服务,然后为侦听器创建第二个服务。一开始看起来可能有点奇怪,但在实践中确实很有效,这就是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;
  }

糟糕的设计,但至少它摆脱了侦听器hack,它避免创建存储库,直到它真正需要。它还意味着您可以通过命令访问存储库(调用命令时不会设置侦听器)。

我不明白这种方法有什么利润。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;
    }