Here is a method signature in the controller :
public function myAction(Request $request, SessionInterface $session, LoggerInterface $logger)
This is what I wrote in services.yml :
AppBundle\Controller\:
resource: '../../Controller'
public: true
tags: ['controller.service_arguments']
Normally, all of the parameters (request, session and logger) are automatically injected.
I call this action of the controller using Ajax but there is a problem for logger (request and session are well injected):
Controller myAction requires that you provide a value for the "$logger" argument
This happens for one method only because the ajax calls to some other methods of the controller work perfectly.
The only difference I can see using some debug tools is that the one that does not work has connection : close though the others have connection: keep-alive.
I dont see why it is done differently.
When I erase the LoggerInterface parameter, it works good and connection is keep-alive like the others.
Can you help ?
Symfony 3 platform
services:
_defaults:
# automatically injects dependencies in your services
autowire: true
# automatically registers your services as commands, event subscribers, etc.
autoconfigure: true
# this means you cannot fetch services directly from the container via $container->get()
# if you need to do this, you can override this setting on individual services
public: false
Related
I'm trying to create a service, which can be injected anywhere. For this I am trying to pass as argument the HttpClient component of Symfony 4.3
I show you the service
https://i.stack.imgur.com/2384M.png
<?php
namespace App\Service\Callback;
use Symfony\Component\HttpClient\HttpClient;
class Back
{
private $client;
public function __construct(HttpClient $httpClient)
{
$this->client = $httpClient::create();
}
public function sendCallback ( $method, $urlCallback, $option)
{
$response = $this->client->request($method,$urlCallback,$option);
$statusCode = $response->getStatusCode();
return $statusCode;
}
}
Well, I'm trying to load it in the services.yml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: 'en'
base_url_front: '%env(BASE_URL_FRONT)%'
mobile_type: 2
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.
Nexy\Slack\Client: '#nexy_slack.client'
Symfony\Component\HttpClient\HttpClient: '#http.client'
# 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,Entity,Migrations,Tests,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']
App\Service\Models\:
resource: '../src/Service/Models'
tags: ['#doctrine.orm.entity_manager','#nexy_slack.client']
slack_client:
class: 'App\Service\SlackClient'
autowire : true
arguments: ['#nexy_slack.client','#kernel']
public : true
callback_client:
class: 'App\Service\Callback\Back'
autowire: true
arguments: ['#http.client']
public: true
App\Service\Apiclient\AteneaService:
arguments: ["%kernel.environment%"]
App\Service\Apiclient\UpmService:
arguments: ["%kernel.environment%"]
App\Service\Apiclient\HermesService:
arguments: ["%kernel.environment%"]
App\Service\Socket\:
resource: '../src/Service/Socket'
tags: ['#kernel','#nexy_slack.client']
The problem is that if I run php bin / console debug: autowiring in the terminal, to know if I created it, it returns the following error :
You have requested a non-existent service "http.client".
In the end what I want to achieve is something like this:
public function getClient(Back $back)
{
$back->sendCallback('GET','http://vro-back.localhost:8888/callback/test');
}
But I can not because I can not inject it.
At the end if you look at the services.yml, I'm trying to create an alias for an HttpClient component, so I can pass it as an argument to the constructor of the Back class
And the route that I'm trying to load, exists ...
Symfony \ Component \ HttpClient \ HttpClient;
This is the component with which I am trying to work
https://symfony.com/doc/current/components/http_client.html
I would appreciate any help.
You need to type-hint the interface instead
public function __construct(HttpClientInterface $httpClient)
{
$this->httpClient = $httpClient;
}
And remove service.yaml configuration
https://symfony.com/doc/current/components/http_client.html
I have a some Controllers, Twig Extensions and other classes that all need caching. I'm using Redis as a cache. Currently I setup a new RedisCache in each of these places, like so:
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
$this->cache = new RedisCache(RedisAdapter::createConnection(getenv('REDIS_URL')), 'ImageHelper');
}
But this creates many connections to the Redis backend, which I believe is not good for performance.
What is the best way to either share a RedisConnection/Client between my Controllers/extensions/classes, or even share the RedisCache, but keep namespacing ability?
I'm using Symfony 4.
You should make the Redis cache a service, and inject it into your controllers (or other dependents) later on. Refer to Symfony's dependency injection docs if needed.
Here's an example, you might need to fine-tune it later on:
# config/services.yaml
services:
redis_connection:
class: 'RedisConnection'
factory: ['RedisAdapter', createConnection]
arguments:
- '%env(REDIS_URL)%'
redis_cache:
class: 'RedisCache'
arguments:
- '#redis_connection'
Note that I don't know which namespaces your classes have, so you'd have to adjust the config accordingly.
And then you would also have to set up the framework to inject the service to your controllers (or other dependents):
# config/services.yaml
services:
# ...
App\Controller\ExampleController:
arguments:
- '#logger'
- '#redis_cache'
Also, you should update the controllers to accept the new argument in constructor, like so:
public function __construct(LoggerInterface $logger, RedisCache $cache)
{
$this->logger = $logger;
$this->cache = $cache;
}
Refer to the service container documentation if you have any questions.
I am trying to make a link that resends a confirmation token to a user after registering in Symfony3.
However, I get a deprecation message as follows:
User Deprecated: The "fos_user.mailer" service is private, getting it
from the container is deprecated since Symfony 3.2 and will fail in
4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.
Here is my controller:
public function resendActivationEmail($token, UserManagerInterface $userManager)
{
$user = $userManager->findUserByConfirmationToken($token);
if (is_null($user)) {return $this->redirectToRoute('fos_user_registration_register');}
$mailer = $this->get('fos_user.mailer');
$mailer->sendConfirmationEmailMessage($user);
return $this->redirectToRoute('fos_user_registration_check_email');
}
My services.yml:
services:
# default configuration for services in *this* file
_defaults:
autowire: truesubscribers, etc.
autoconfigure: true
public: false
I looked into the docs, it says that in Symfony3.4, services are private by default. I am using autowiring in my app, so how I get the fos_user.mailer without any deprecation warnings?
I tried setting Fosuserbundle services to public, doesnt help:
services.yml:
....
FOS\UserBundle:
public: true
Any help appreciated!
It's better to use DependencyInjection instead of call container directly. You should pass your mailer to your method:
public function resendActivationEmail($token, UserManagerInterface $userManager, \FOS\UserBundle\Mailer\MailerInterface $mailer)
{
$user = $userManager->findUserByConfirmationToken($token);
if (is_null($user)) {return $this->redirectToRoute('fos_user_registration_register');}
$mailer->sendConfirmationEmailMessage($user);
return $this->redirectToRoute('fos_user_registration_check_email');
}
For more informations about dependencyInjection : https://symfony.com/doc/3.4/service_container/injection_types.html
Use $mailer = $this->container->get('fos_user.mailer');
instead of $mailer = $this->get('fos_user.mailer');
I am starting to work with services in Symfony and therefore created the example service from the symfony documentation:
namespace AppBundle\Service;
use Psr\Log\LoggerInterface;
class MessageGenerator
{
private $logger;
public function __construct(LoggerInterface $logger){
}
public function getMessage()
{
$this->logger->info('Success!');
}
}
I call that service in my controller (I also have the use Statement:
: use AppBundle\Service\MessageGenerator;
$messageGenerator = $this->get(MessageGenerator::class);
$message = $messageGenerator->getMessage();
$this->addFlash('success', $message);
My service is defined in the services.yml file:
app.message_generator:
class: AppBundle\Service\MessageGenerator
public: true
so in my eyes I did everything exactly as described in the documentation and when calling:
php app/console debug:container app.message_generator
in my commandline I get my service:
Option Value
------------------ ------------------------------------
Service ID app.message_generator
Class AppBundle\Service\MessageGenerator
Tags -
Scope container
Public yes
Synthetic no
Lazy no
Synchronized no
Abstract no
Autowired no
Autowiring Types -
Now when I execute the controller function where I call my service I still get the error:
You have requested a non-existent service "appbundle\service\messagegenerator".
Any ideas?
Symfony is a bit confusing at naming: you retrieve the service by requesting it by its defined name: app.message_generator.
$messageGenerator = $this->get('app.message_generator');
Symfony has recently suggested switching from a give-name (app.message_generator) that you are defining the service as, to the class name (AppBundle\Service\MessageGenerator). They are both just 'a name' to call the service.
You are trying to use both, when only the given name is defined.
In the long term, it's suggested to use the ::class based name, and quite possibly allow the framework to find the classes itself, and configure them itself too. This means that, by default, all services are private, and are handled by the framework & it's service container.
In the meantime, while you are learning, you can either:
$messageGenerator = $this->get('app.message_generator');
or define explicitly define the service, and make it public, so it can be fetched with ->get(...) from the container.
# services.yml
AppBundle\Service\MessageGenerator:
class: AppBundle\Service\MessageGenerator
public: true
# php controller
$messageGenerator = $this->get(MessageGenerator::class);
or just injected automatically into the controller, when that is requested
public function __construct(LoggerInterface $logger, MessageGenerator $msgGen)
{
$this->messageGenerator = $msgGen;
}
public function getMessage()
{
$result = $this->messageGenerator->do_things(....);
$this->logger->info('Success!');
}
In the definition of my services, I'd like to pass as a service argument constructor an object not a service.
From config.yml:
services:
acme.services.exampleservice:
class: Acme\ExampleBundle\Services\ExampleService
arguments:
entityManager: "#doctrine.orm.entity_manager"
httpClient: \Example\Http\Client\Client
Note the httpClient argument. This must be an instance of the \Example\Http\Client\Client class.
The above does not work - the string "\Example\Http\Client\Client" is passed as the httpClient argument to the service.
What is the syntax for achieving the above by means of passing an instance of \Example\Http\Client\Client to the service constructor?
Create a private service. Here's what's written in the documentation:
If you use a private service as an argument to more than one other service, this will result in two different instances being used as the instantiation of the private service is done inline (e.g. new PrivateFooBar()).
services:
acme.services.exampleservice:
class: Acme\ExampleBundle\Services\ExampleService
arguments:
entityManager: "#doctrine.orm.entity_manager"
httpClient: acme.services.httpClient
acme.services.httpClient:
class: Example\Http\Client\Client
public: false
You will not be able to retrieve a private service from the container. From the outside it looks just as if you passed a regular object to the constructor of your service.