在Sonata管理包中注入容器服务的正确方式


Right way to inject container service in Sonata Admin Bundle

我试图在我的索纳塔管理类中注入service container,以便在configureFormFields方法中使用它。这是我的文件:

配置。Yml (sonata服务定义)

services:
  tan.product.admin.product:
    class: Tan'ProductBundle'Admin'ProductAdmin
    tags:
      - { name: sonata.admin, manager_type: orm, group: Product, label: Product }
    arguments: [ null, Tan'ProductBundle'Entity'Product, @service_container]

ProductAdmin.php

class ProductAdmin extends Admin
{
    /** @var 'Symfony'Component'DependencyInjection'ContainerInterface */
    private $container;
    public $supportsPreviewMode = true;
    /**
     * @param string $code
     * @param string $class
     * @param string $baseControllerName
     */
    public function __construct($code, $class, $baseControllerName, $container = null)
    {
        parent::__construct($code, $class, $baseControllerName);
        $this->container = $container;
    }
    // other methods 
    protected function configureFormFields(FormMapper $form)
    {
        $helper = $this->container->get('oneup_uploader.templating.uploader_helper');
        $endpoint = $helper->endpoint('products');
        $form
                ->add('product_name', null, array('label' => 'Nombre'))
                ->add('product_description', null, array('label' => 'Descripción'));
    }
}

但是我得到这个错误:

contextroreexception: Catchable Fatal Error: Object of class无法将appDevDebugProjectContainer转换为字符串/var/cache/dev/classes.php第12979行

怎么了?

由于构造函数有4个参数,其中第4个是服务容器,因此需要传入第4个服务容器:

services:
  tan.product.admin.product:
  class: Tan'ProductBundle'Admin'ProductAdmin
  tags:
      - { name: sonata.admin, manager_type: orm, group: Product, label: Product }
  arguments: [ null, Tan'ProductBundle'Entity'Product, null, @service_container]

尝试添加第4个参数到Admin构造函数导致我错误:

"参数4传递给AppBundle'Admin'WebLabAbstractMessageAdmin::__construct()必须是Doctrine'ORM'EntityManager的一个实例,none given",无论我试图传递给参数的是什么服务。

所以我使用呼叫方法:

#services.yml
app.admin.twitter_message:
    class: AppBundle'Admin'WebLabAbstractMessageAdmin
    arguments: [~, AppBundle'Entity'Twitter'Message, SonataAdminBundle:CRUD]
    tags:
        - { name: sonata.admin, manager_type: orm, group: operator, label: Message, show_in_dashboard: false }
    calls:
        - ["setEntityManager", ['@doctrine.orm.entity_manager']]
        - ["setParentRepository", ['@app.doctrine.repository.twitter.conversation']]

与设置在admin类

#MessageAdmin.php
/**
 * @var EntityManager
 */
private $entityManager;
private $parentRepository;
/**
 * @param EntityManager $entityManager
 * @return self
 */
public function setEntityManager(EntityManager $entityManager): self
{
    $this->entityManager = $entityManager;
    return $this;
}
/**
 * @param $parentRepository
 * @return self
 */
public function setParentRepository($parentRepository): self
{
    $this->parentRepository = $parentRepository;
    return $this;
}

我的版本是:"symfony/symfony": "3.2。*", "sonata-project/admin-bundle": "^3.10".

希望对大家有所帮助。

如果你只想在admin类中访问容器,你可以简单地调用

$this->getConfigurationPool()->getContainer() 

将以一种正式的方式返回容器为你的bundle创建一个基管理类它将扩展sonata的管理类然后你可以在基管理类中定义函数来返回一个容器并在你的子管理类中使用它,产品基管理类将看起来像

use Sonata'AdminBundle'Admin'Admin;
class ProductBaseAdmin extends Admin
{
    public function __construct($code, $class, $baseControllerName)
    {
            parent::__construct($code, $class, $baseControllerName);
    }
    public function getContainer(){
        return $this->getConfigurationPool()->getContainer();
    }
}

现在在您的子类中,您可以通过$this->getContainer()访问容器,它将调用ProductBaseAdmin类的getContainer()函数

use Tan'ProductBundle'Admin'ProductBaseAdmin
class ProductAdmin extends ProductBaseAdmin
{
    protected function configureFormFields(FormMapper $form)
    {
        $helper = $this->getContainer()->get('oneup_uploader.templating.uploader_helper');
        $endpoint = $helper->endpoint('products');
        $form
                ->add('product_name', null, array('label' => 'Nombre'))
                ->add('product_description', null, array('label' => 'Descripción'));
    }
}