Как получить доступ к сервисному контейнеру в глобальной вспомогательной функции (сервисе) symfony2?

47

Этот вопрос начался со мной, не понимая, почему я не мог передавать переменные в глобальную вспомогательную функцию symfony2 (service), но благодаря людям, более ярким, чем я, я понял, что моя ошибка заключалась в попытке использовать security_context изнутри класс, который его не вводил так...

Это конечный результат, код, который работает. Я не нашел лучшего способа сделать это полезным для общения.

Вот как вы можете получить пользовательские и другие данные из security_context из глобальной функции или вспомогательной функции в symfony2.

У меня есть следующий класс и функция:

<?php
namespace BizTV\CommonBundle\Helper;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class globalHelper {    

private $container;

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

    //This is a helper function that checks the permission on a single container
    public function hasAccess($container)
    {
        $user = $this->container->get('security.context')->getToken()->getUser();

        //do my stuff
    }     
}

... определяется как служба (в app/config/config.yml), как это...

#Registering my global helper functions            
services:
  biztv.helper.globalHelper:
    class: BizTV\CommonBundle\Helper\globalHelper
    arguments: ['@service_container']

Теперь в моем контроллере я вызываю эту функцию следующим образом:

public function createAction($id) {

    //do some stuff, transform $id into $entity of my type...

    //Check if that container is within the company, and if user has access to it.
    $helper = $this->get('biztv.helper.globalHelper');
    $access = $helper->hasAccess($entity);
  • 1
    Вы определенно можете передавать переменные из вашего контроллера в службу, если вам это нужно. У вас также есть возможность передать материал в сервис (Dependency Injection) в вашем config.yml. Что ты пытаешься получить? В __construct это был контейнер $, но в hasAccess это был $ entity.
  • 1
    В контроллере переменная называется $ entity, как только она попадает в сервисную функцию, я люблю называть ее $ container, насколько я понимаю, между именами аргументов нет связи, php знает их только по аргументу аргумент1, аргумент2. и т.д. перешел в функцию? Не уверен, что понимаю ваш вопрос "что я получаю?"
Показать ещё 4 комментария
Теги:
service

5 ответов

74
Лучший ответ

Я предполагаю, что первая ошибка (свойство undefined) произошла до того, как вы добавили свойство и конструктор. Затем вы получили вторую ошибку. Эта другая ошибка означает, что ваш конструктор ожидает получить объект Container, но ничего не получил. Это связано с тем, что, когда вы определили свой сервис, вы не сказали менеджеру по взысканию зависимостей, что вы хотите получить контейнер. Измените определение сервиса следующим образом:

services:
  biztv.helper.globalHelper:
    class: BizTV\CommonBundle\Helper\globalHelper
    arguments: ['@service_container']

Затем конструктор должен ожидать объект типа Symfony\Component\DependencyInjection\ContainerInterface;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class globalHelper {    

    private $container;

    public function __construct(Container $container) {
        $this->container = $container;
    }
  • 0
    Возможно, я запутал вас своей переменной $ container, это не служебный контейнер, а моя собственная сущность ... Я добавил service_container, как вы сказали здесь выше (чтобы иметь возможность доступа к security_context из моего вспомогательного класса. .. все еще получаю эту ошибку ... Исправляемая фатальная ошибка: аргумент 1, передаваемый в BizTV \ CommonBundle \ Helper \ globalHelper :: __ construct (), должен быть экземпляром BizTV \ ContainerManagementBundle \ Entity \ Container, ни один не указан
  • 0
    ОК, я не заметил, что вы определили контейнер как BizTV \ ContainerManagementBundle \ Entity \ Container. Итак, у нас есть два контейнера, объект $ container, который является объектом-сущностью, который вы можете передать в качестве параметра своей вспомогательной функции, нет необходимости передавать его конструктору и контейнеру службы, которые вам нужны для получения security_context, и который вы можно вводить через конструктор. Я отредактирую свой ответ
Показать ещё 5 комментариев
20

Подход, который всегда работает, несмотря на то, что он не является лучшей практикой в ​​OO

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏
  • 13
    иногда Symfony заставляет ОО-подход Слишком много работать для того, что вы пытаетесь сделать. Спасибо за это!
  • 0
    Но остерегайтесь таких вещей, как $kernel = null ... Но спасибо за это.
7

Другой вариант - расширить ContainerAware:

use Symfony\Component\DependencyInjection\ContainerAware;

class MyService extends ContainerAware
{
    ....
}

который позволяет вам вызвать setContainer в объявлении сервиса:

foo.my_service:
    class: Foo\Bundle\Bar\Service\MyService
    calls:
        - [setContainer, [@service_container]]

Затем вы можете ссылаться на контейнер в своей службе следующим образом:

$container = $this->container;
  • 1
    Обратите внимание, что в Symfony> = 3.0 больше нет класса ContainerAware который могут расширять другие классы. Скорее классы могут реализовать ContainerAwareInterface в сочетании с использованием черты ContainerAwareTrait
  • 1
    Также рассмотрите недостатки этого подхода: qafoo.com/blog/057_containeraware_considered_harmful.html
Показать ещё 1 комментарий
1

Вы не должны вводить service_container в свои службы. В вашем примере вам следует вместо этого добавить старый security.context или более поздний security.token_storage. См., Например, раздел "Избегание использования кода в зависимости от контейнера" http://symfony.com/doc/current/components/dependency_injection.html.

Пример:

<?php
namespace BizTV\CommonBundle\Helper;

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class globalHelper {    

    private $securityTokenStorage;

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


    public function hasAccess($container)
    {
        $user = $this->securityTokenStorage->getToken()->getUser();

        //do my stuff
    }     
}

приложение/Config/config.yml:

services:
  biztv.helper.globalHelper:
    class: BizTV\CommonBundle\Helper\globalHelper
    arguments: ['@security.token_storage']

Ваш контроллер:

public function createAction($id) {

    $helper = $this->get('biztv.helper.globalHelper');
    $access = $helper->hasAccess($entity);
1

Может быть, это не лучший способ, но то, что я делаю, это передать контейнер классу, поэтому я получаю его каждый раз, когда мне это нужно.

$helpers = new Helpers();
or
$helpers = new Helpers($this->container);

/* My Class */
class Helpers
{
    private $container;

    public function __construct($container = null) {
        $this->container = $container;
    }
    ...
}

Работает каждый раз для меня.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню