John Davidson

php - symfony5 service - how to inject session and user without the ContainerInterface

0 comments
Message:


I have this deprecation message:



Since symfony/dependency-injection 5.1: The
"Symfony\Component\DependencyInjection\ContainerInterface" autowiring
alias is deprecated. Define it explicitly in your app if you want to
keep using it.



From threads such as this Symfony: Explicit define Container in Service I understand that the long-term solution is to stop using the ContainerInterface all together in my services.


My services.yaml looks like this:


parameters:
#locale: en
basepath: '%env(basepath)%'

services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'

# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']


# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
globalHelper:
class: App\Service\globalHelper
public: false

The service in question (globalHelper) looks like this:


<?php
namespace App\Service;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Doctrine\ORM\EntityManagerInterface as EntityManager;

class globalHelper {

private $container;
private $em;

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

I only user the container to fetch session variables like this


$this->container->get('session')->getFlashBag()->add($type, $message);

And to get the current user (security context) like this


$this->container->get('security.context')->getToken()->getUser();

Can I get these sub-components of the container separately instead? What component then would I inject to access these two parts (session and user) respectively?


--------------- Addition --------------


According to Alexis' suggestion below I modified the head of the file with


<?php
namespace App\Service;

//use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Security;
use Doctrine\ORM\EntityManagerInterface as EntityManager;

class globalHelper {

//private $container;
private $requestStack;
private $security;
private $em;

//public function __construct(Container $container, RequestStack $requestStack, Security $security, EntityManager $em) {
public function __construct(RequestStack $requestStack, Security $security, EntityManager $em) {
//$this->container = $container;
$this->requestStack = $requestStack;
$this->security = $security;
$this->em = $em;
}

then replaced


$this->container->get('session')->getFlashBag()->add($type, $message);

with


$this->requestStack->getSession()->getFlashBag()->add($type, $message);

and get this error:



Attempted to call an undefined method named "getSession" of class
"Symfony\Component\HttpFoundation\RequestStack".



if I instead to this:


$this->requestStack->get('session')->getFlashBag()->add($type, $message);


Attempted to call an undefined method named "get" of class
"Symfony\Component\HttpFoundation\RequestStack". Did you mean to call
e.g. "getCurrentRequest", "getMasterRequest" or "getParentRequest"?




My Answer:
recommended way to inject services into your classes is by using constructor injection. This means that you should define your services as dependencies in the constructor of your class, rather than using the ContainerInterface to retrieve them.

Here's an example of how you can inject the session and user services into a class using constructor injection in Symfony 5:

php
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Security;

class MyClass
{
private $session;
private $user;

public function __construct(SessionInterface $session, Security $security)
{
$this->session = $session;
$this->user = $security->getUser();
}

// Your class methods here
}


In this example, we are injecting the SessionInterface and Security services into the constructor of the MyClass class. This allows us to access the session and user services within the class without needing to use the ContainerInterface.

Make sure to update your service definition to reflect the new constructor dependencies:

yaml
services:
App\MyClass:
arguments:
$session: '@session'
$security: '@security.helper'


By following this approach, you can avoid using the ContainerInterface and ensure that your classes are more testable and maintainable.

Rate this post

3 of 5 based on 9989 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us