Jak uzyskać dostęp do kontenera usług w globalnej funkcji pomocniczej symfony2 (service)?

To pytanie zaczęło się od tego, że nie rozumiałem, dlaczego nie mogłem przekazać zmiennych do globalnej funkcji pomocniczej symfony2 (usługi), ale dzięki ludziom jaśniejszym ode mnie, zdałem sobie sprawę, że mój błąd polegał na próbie użycia security_context z klasy, która nie miała go tak wstrzykiwanego...

To jest ostateczny wynik, kod, który działa. Nie znalazłem lepszego sposobu na uczynienie tego pomocnym dla wspólnoty.

W ten sposób można uzyskać dane użytkownika i inne dane z security_context z poziomu funkcji globalnej lub funkcji pomocniczej w symfony2.

Mam następującą klasę i funkcję:

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

...zdefiniowana jako usługa (w app / config / config.yml) w ten sposób...

#Registering my global helper functions            
services:
  biztv.helper.globalHelper:
    class: BizTV\CommonBundle\Helper\globalHelper
    arguments: ['@service_container']
Teraz w moim kontrolerze wywołuję tę funkcję w ten sposób...
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);
Author: Matt Welander, 2012-08-21

5 answers

Zakładam, że pierwszy błąd (niezdefiniowana właściwość) wystąpił przed dodaniem właściwości i konstruktora. Potem masz drugi błąd. Ten drugi błąd oznacza, że konstruktor oczekuje otrzymania obiektu kontenera, ale nie otrzymał niczego. Dzieje się tak dlatego, że podczas definiowania usługi nie powiedziałeś menedżerowi Dependency Injection manager, że chcesz uzyskać kontener. Zmień definicję usługi na tę:

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

Konstruktor powinien wtedy oczekiwać obiektu o type Symfony\Component\DependencyInjection\ContainerInterface;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class globalHelper {    

    private $container;

    public function __construct(Container $container) {
        $this->container = $container;
    }
 81
Author: Carlos Granados,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-21 14:45:58

Podejście, które zawsze działa, mimo że nie jest najlepszą praktyką w OO

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏
 20
Author: Guilherme Viebig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-01 21:40:57

Inną opcją jest rozszerzenie kontenera:

use Symfony\Component\DependencyInjection\ContainerAware;

class MyService extends ContainerAware
{
    ....
}

Który pozwala na wywołanie setContainer w deklaracji serwisowej:

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

Następnie możesz odwołać się do kontenera w swojej usłudze w następujący sposób:

$container = $this->container;
 7
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-27 12:05:16

Może to nie jest najlepszy sposób, ale to, co robię, to przekazuję kontener do klasy, więc mam go za każdym razem, gdy go potrzebuję.

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

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

    public function __construct($container = null) {
        $this->container = $container;
    }
    ...
}
Dla mnie działa za każdym razem.
 1
Author: Strabek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-08 10:22:15

Nie należy wstrzykiwać service_container w swoje usługi. W twoim przykładzie powinieneś raczej wstrzyknąć starą security.context lub nowszą security.token_storage. Zobacz na przykład sekcję "unikanie uzależnienia kodu od kontenera" http://symfony.com/doc/current/components/dependency_injection.html .

Ex:

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

App / config / config.yml:

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

Twój kontroler:

public function createAction($id) {

    $helper = $this->get('biztv.helper.globalHelper');
    $access = $helper->hasAccess($entity);
 1
Author: Tsounabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-27 14:59:21