Inject Container in Entity Repository - symfony

I want to get Current locale in my Repository.That's why I am injecting the Container into my Repository but I am getting error that I am unable to figure it out.
This is my service.yml code
survey.repository.container_aware:
class: Demo\SurveyBundle\Repository\SurveyRepository
calls:
- [ setContainer, [ #service_container ] ]
and this is my repository class code
.......
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
.......
protected $container;
public function __construct(Container $container) {
$this->container = $container;
}
After that I am getting below error
ContextErrorException: Catchable Fatal Error: Argument 1 passed to
Demo\SurveyBundle\Entity\SurveyRepository::__construct() must implement
interface Symfony\Component\DependencyInjection\ContainerInterface, instance of
Doctrine\ORM\EntityManager given
What I am missing in my construct or in service?

You are passing the container with the Setter Injection (in the yml) but you define it in the constructor class.
BTW the entity manager already have a constructor class with arguments so don't take the Constructor Injection and simply change your method in the class as:
public function setContainer(Container $container) {
$this->container = $container;
}

You actually have another major issue here. From the error message it's obvious that you are trying to access your doctrine repository using the entity manager. Something like:
$repo = $em->getRepository('whatever');
The service container code is never being used and it really does not matter what you do, you still won't get your container injected. Creating a repository as a service requires using the entity manager as a factory and takes some additional lines in your services.yml file.
Something like:
# services.yml
cerad_person.person_repository.doctrine:
class: Cerad\Bundle\PersonBundle\Entity\PersonRepository
factory_service: 'doctrine.orm.default_entity_manager'
factory_method: 'getRepository'
arguments:
- 'Cerad\Bundle\PersonBundle\Entity\Person'
calls:
- [ setContainer, [#container] ]
// controller
$personRepo = $this->get('cerad_person.person_repository.doctrine');
That will give you a repository with the container injected.
#devilciuos - %locale% will only give you the default locale and not whatever is passed as _locale in the request. Unfortunately it seems to take a listener to access the request local via a service: https://github.com/symfony/symfony/issues/5486

You're not passing the container to the constructor, but to setContainer. So you shouuld declare a public method setContainer in SurveyRepository:
Demo/SurveyBundle/Entity/SurveyRepository.php
protected $container;
public function setContainer(Container $container) {
$this->container = $container;
}
or pass the container to the constructor:
DemoSurveyBundle/Resources/Config/services.yml
survey.repository.container_aware:
class: Demo\SurveyBundle\Repository\SurveyRepository
arguments: [#service_container]
Edit:
By the way, if you only need the locale, wouldn't be enough to pass the %locale% parameter instead of the whole container?
survey.repository.container_aware:
class: Demo\SurveyBundle\Repository\SurveyRepository
calls:
- [ setLocale, [ %locale%] ]
protected $locale;
public function setLocale($locale) {
$this->locale = $locale;
}

Related

Symfony 3.0.9 can't access getUser() from my service

I am trying to access my user from a service in symfony 3.0.9 with the following:
in my service.yaml:
seal_service:
class: FrontBundle\Service\SealService
public: true
arguments:
- "#service_container"
and my service is like this:
class SealService
{
protected $container = null;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getAvailableSeals($sn = null){
$user = $this->container->get('fos_user.user_manager')->getUser();
...
}
but I am getting the following error:
Attempted to call an undefined method named "getUser"
I also tried $this->container->get('fos_user.user_manager')
if I use $this->container->get('fos_user.security.controller') I get Call to protected method Symfony\Bundle\FrameworkBundle\Controller\Controller::getUser() from context 'FrontBundle\Service\SealService'
What am I doing wrong please ?
Don't inject container in service:
inject token storage instead.
seal_service:
class: FrontBundle\Service\SealService
public: true
arguments:
- ["#security.token_storage","#doctrine.orm.entity_manager"]
here is the answer:
$tokenStorage = $this->container->get('security.token_storage')->getToken();
$user = $tokenStorage->getUser();
Use the following:
$this->container->get('security.token_storage')->getToken()->getUser();
Anyway, avoid injecting the whole container, if you only need security context.
https://symfony.com/doc/current/security.html#b-fetching-the-user-from-a-service

How to inject Doctrine Entity Manager into Symfony 4 Service

I have a controller
use Doctrine\ORM\EntityManagerInterface:
class ExampleController{
public function someFunction(ExampleService $injectedService){
$injectedService->serviceFunction();
}
}
With a Service
use Doctrine\ORM\EntityManagerInterface;
class ExampleService{
public function __construct(EntityManagerInterface $em){
...
}
}
However, calls to someFunction() fail due to 0 parameters being passed (the EntityManagerInterface is not being injected). I am attempting to use the EntityManager from the Service. Autowiring is on. I've tried the solutions for Symfony3 but they don't seem to work unless I'm missing something.
Edit: Here is my services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
Use only in Symfony 4.
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Name; //if you use entity for example Name
class ExampleService{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
function newName($code) // for example with a entity
{
$name = new Name();
$name->setCode($code); // use setter for entity
$this->em->persist($name);
$this->em->flush();
}
}
I know it's an old post, but just in case somebody struggles with this, there's a typo in the use statment:
use Doctrine\ORM\EntityManagerInterface: //<- see that's a colon, not a semicolon
Agree with Yarimadam. Service container, dependency injection and autowiring is not a story about injecting into methods. Dependencies injected into objects we are calling "services".
When application is up, service container is built injecting one services into another ones via class constructor or "set" method invocation.
Your ExampleController::someFunction is intended to be called only by you, so only way how this method will receive $injectedService as an argument, is that you will pass it evidently. This is the wrong way.
A classic symfony service with autowiring uses constructor injection method to inject dependencies. In your case, you don't have a constructor.
You may consider to add a constructor method and set dependency to a private class property. And use accordingly.
Or you can utilize setter injection.
Service Configuration:
services:
app.example_controller:
class: Your\Namespace\ExampleController
calls:
- [setExampleService, ['#exampleService']]
Controller Class:
class ExampleController
{
private $exampleService;
public function someFunction() {
$this->exampleService->serviceFunction();
}
public function setExampleService(ExampleService $exampleService) {
$this->exampleService = $exampleService;
}
}

#mailer and #twig in argument of a service error ServiceCircularReferenceException

I'm trying to put twig like argument of my service but i have always the same error :
ServiceCircularReferenceException in bootstrap.php.cache line 2129
Circular reference detected for service "doctrine.orm.default_entity_manager",path: "doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> wh.participant_listener -> wh.participant_notification -> twig -> security.authorization_checker -> security.authentication.manager -> fos_user.user_provider.username -> fos_user.user_manager".`
This is my service.yml file
wh.participant_notification:
class: WH\TrainingBundle\Notification\Notification
arguments: [#mailer, #twig]
wh.participant_listener:
class: WH\TrainingBundle\EventListener\ParticipantListener
arguments: [#wh.participant_notification]
tags:
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: postPersist }
My PartcicipantListenerFile
namespace WH\TrainingBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use WH\TrainingBundle\Notification\Notification;
class ParticipantListener
{
protected $notification;
public function __construct(Notification $notification)
{
$this->notification = $notification;
}
}
This probleme exist only when i pass #wh.participant_notificationin arguments of my second service
Any body has an idea ?
Thank's a lot
I've find a solution, not pretty, but it works :
First i pass the service container in argument of my service
services:
wh.participant_notification:
class: WH\TrainingBundle\Notification\Notification
arguments: ['#service_container']
wh.participant_listener:
class: WH\TrainingBundle\EventListener\ParticipantListener
arguments: ['#wh.participant_notification']
tags:
- { name: doctrine.event_listener, event: postPersist }
then in my Notification.php class :
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
private $container;
public function __construct(Container $container) {
$this->container = $container;
}
public function subscribValidation ($participant) {
$templating = $this->container->get('templating');
$mailer = $this->container->get('mailer');
...
I can't create protected var $twig because the probleme persiste.
I repeat, its only with twig service (or template).
Maybe another one find a better solution ...
The circular message, while unclear, should guide you.
Doctrine entity manager loads its listeners,wh.participant_notification among them. Your service requires twig which in turns requires a chain of other things, doctrine entity manager among them. This causes the exception above.
One solution to this issue could be to use setter injection
So you can just define your service as:
wh.participant_notification:
class: WH\TrainingBundle\Notification\Notification
calls:
- [setMailer, ["#mailer"]]
- [setTemplating, ["#templating"]]
and add to your Notification class the setter methods
class Notification
{
private $mailer;
private $templating;
public function setMailer(\Mailer $mailer)
{
$this->mailer = $mailer;
}
public function setTemplating(\Symfony\Bundle\TwigBundle\TwigEngine $templating)
{
$this->templating= $templating;
}
...your code...

How to use a controller as service with #Route annotation in Symfony 2?

I've a controller which is configuered as a service. I'd like to use #Route annotations to define the route.
When I try to access the route I get:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Galexis\RequestDispatcherBundle\Controller\RequestDispatcherController::__construct() must implement interface Psr\Log\LoggerInterface, none given, called in /Users/ugxnbpluse/development/git/integrationPHP/symfony2/app/cache/dev/classes.php on line 2282 and defined in /Users/ugxnbpluse/development/git/integrationPHP/symfony2/src/Galexis/RequestDispatcherBundle/Controller/RequestDispatcherController.php line 29
From the error message I understand, that symfony doesn't know, that it should not call new for the controller but take it from the DI container.
The symfony docs (last section) tell me to add something like
#Route(service="my_post_controller_service")
but it seams that symfony does not really support the service property:
BadMethodCallException: Unknown property 'service' on annotation 'Symfony\Component\Routing\Annotation\Route'.
Any ideas?
Controller:
class RequestDispatcherController
{
// ...
public function __construct(
LoggerInterface $logger,
RequestDispatcherService $requestDispatcherService)
{
$this->logger = $logger;
$this->requestDispatcherService = $requestDispatcherService;
}
/**
* #Route("requestDispatcher/{applicationName}")
* #return Response
*/
public function dispatch(Request $request)
{
// ...
}
}
routing.yml:
_request_dispatcher:
resource: "#FooRequestDispatcherBundle/Controller/RequestDispatcherController.php"
type: annotation
service.yml:
parameters:
request_dispatcher.class: Foo\RequestDispatcherBundle\Service\RequestDispatcherService
request_dispatcher_controller.class: Foo\RequestDispatcherBundle\Controller\RequestDispatcherController
services:
request_dispatcher_service:
class: "%request_dispatcher.class%"
arguments: ["#foo.integration.application", "#buzz.multi.client" ]
request_dispatcher_controller:
class: "%request_dispatcher_controller.class%"
arguments: ["#logger", "#request_dispatcher_service"]
I think you should use use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; instead of use Symfony\Component\Routing\Annotation\Route;.

How do I get services (dependencies) in a custom class

In the controller, I could do
$this->get('service.name')
But in a custom class, how can I do that?
Define your custom class as a service, and then inject dependencies into it.
Ex:
// services.yml
services:
my.custom.service.id:
class: My\Custom\Class
arguments:
- #service.name
- #doctrine.orm.entity_manager
Your custom class' constructor would then get those services as arguments.
Be sure to read up on the Service Container in the official docs. It goes over all this in great detail.
You were on the right track with ContainerAware.
$this->get('id') is actually a shortcut to $this->container->get('id'). And getting container into your class is as simple as implementing ContainerAwareInterface - putting this snippet into your class:
public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null)
{
$this->container = $container;
}
If you do not know the full list of dependencies that you need at the moment when the service is created, you can pass the container as the argument http://symfony.com/doc/current/book/service_container.html#using-the-expression-language
services:
service_name:
class: AppBundle\Class
arguments: ['#=container']
Accessing the service container in a custom class (not in a service defined class)
This is not best practice to do, but it works. If your custom class is not set to be a service then you can access the service container using global variable $kernel:
class Helper {
private $container;
/**
* Constructor assigns service container to private container.
*/
public function __construct() {
global $kernel;
$this->container = $kernel->getContainer();
}
function doSOmething() {
$someService = $this->container->get('service.name');
// do something with someService ...
}
}
OK I suppose #Arms answer is a possible solution, I found by looking at the source to Controller, I could extend ContainerAware

Resources