How to access service container in symfony2 global helper function (service)?

PhpServiceSymfony

Php Problem Overview


This question started out with me not understanding why I couldn't pass variables to a symfony2 global helper function (service), but thanks to people brighter than I, I realized my error was about trying to use the security_context from within a class that didn't have it injected so...

This is the final result, the code that works. I found no better way of making this helpful to the comunity.

This is how you can get the user and other data from security_context from within a global function or helper function in symfony2.

I have the following class and function:

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

...defined as a service (in app/config/config.yml) like this...

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

Now, in my controller I call on this function like this...

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);

Php Solutions


Solution 1 - Php

I assume that the first error (undefined property) happened before you added the property and the constructor. Then you got the second error. This other error means that your constructor expects to receive a Container object but it received nothing. This is because when you defined your service, you did not tell the Dependency Injection manager that you wanted to get the container. Change your service definition to this:

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

The constructor should then expect an object of type Symfony\Component\DependencyInjection\ContainerInterface;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class globalHelper {    

    private $container;

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

Solution 2 - Php

An approach that always works, despite not being the best practice in OO

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏

Solution 3 - Php

Another option is to extend ContainerAware:

use Symfony\Component\DependencyInjection\ContainerAware;

class MyService extends ContainerAware
{
    ....
}

which allows you to call setContainer in the service declaration:

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

You can then reference the container in your service like this:

$container = $this->container;

Solution 4 - Php

Maybe it's not the best way but what I do is I pass container to the class so I have it every time I need it.

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

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

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

Works every time for me.

Solution 5 - Php

You should not inject the service_container in your services. In your example you should rather inject the old security.context or the more recent security.token_storage instead. See for example the "Avoiding your Code Becoming Dependent on the Container" section of 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']

Your controller:

public function createAction($id) {

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt WelanderView Question on Stackoverflow
Solution 1 - PhpCarlos GranadosView Answer on Stackoverflow
Solution 2 - PhpGuilherme ViebigView Answer on Stackoverflow
Solution 3 - PhpJonathanView Answer on Stackoverflow
Solution 4 - PhpStrabekView Answer on Stackoverflow
Solution 5 - PhpTsounabeView Answer on Stackoverflow