- a few cases exist when an argument to a service cannot be autowired
- examples:
- configurable admin email in the constructor of a service
- configurable text message for a greeting service
- examples:
- Add a string argument to the constructor of Greeting service
# src/Service/Greeting.php
namespace App\Service;
use Psr\Log\LoggerInterface;
class Greeting
{
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var string
*/
private $message;
/**
* Greeting constructor.
*/
public function __construct(LoggerInterface $logger, string $message)
{
$this->logger = $logger;
$this->message = $message;
}
public function greet(string $name): string
{
$this->logger->info("Greeted $name");
return "{$this->message} $name";
}
}
- Refresh the page (/?name=Siven)
- Error
Cannot autowire service "App\Service\Greeting": argument "$message" of method "__construct()" is type-hinted "string", you should configure its value explicitly.
- Define the service manually
- In
services.yaml
, add an entry for the service and pass a value for the argument$message
- In
App\Service\Greeting:
arguments:
$message: 'Hello from service'
Note
-
by default
autowire
is already set totrue
inservices.yaml
- not necessary to specify the arguments for autowired services
-
Refresh the page
- Success: the page will now show
Hello from service Siven
- Success: the page will now show
- the container also holds configuration, called
parameters
, in addition to service objects - to create a parameter:
- add it under the
parameters
key - reference it with the
%parameter_name%
- it can be referenced in any other configuration file
- many are defined in the
config/services.yaml
file
- add it under the
Example 1
# config/services.yaml
parameters:
admin_email: manager@example.com
services:
# ...
App\Updates\SiteUpdateManager:
arguments:
$adminEmail: '%admin_email%'
The parameter can be fetched in the service as follows:
class SiteUpdateManager
{
// ...
private $adminEmail;
public function __construct($adminEmail)
{
$this->adminEmail = $adminEmail;
}
}
Parameters can also be fetched directly from the container:
public function new()
{
// ...
// this shortcut ONLY works if you extend the base AbstractController
$adminEmail = $this->getParameter('admin_email');
// this is the equivalent code of the previous shortcut:
// $adminEmail = $this->container->get('parameter_bag')->get('admin_email');
}
Example 2
- Define a parameter for the string
- In the
services.yaml
file, add the following line underparameters
- In the
parameters:
locale: 'en'
hello_message: 'Hello from service'
- Change the service definition to use the defined parameter
App\Service\Greeting:
arguments:
$message: '%hello_message%'
- Refresh the page
- Success: the page still works
- the
bind
keyword can also be used to bind specific arguments by name or type
Example
# config/services.yaml
services:
_defaults:
bind:
# pass this value to any $adminEmail argument for any service
# that's defined in this file (including controller arguments)
$adminEmail: 'manager@example.com'
# pass this service to any $requestLogger argument for any
# service that's defined in this file
$requestLogger: '@monolog.logger.request'
# pass this service for any LoggerInterface type-hint for any
# service that's defined in this file
Psr\Log\LoggerInterface: '@monolog.logger.request'
# optionally you can define both the name and type of the argument to match
string $adminEmail: 'manager@example.com'
Psr\Log\LoggerInterface $requestLogger: '@monolog.logger.request'
# ...
bind
key under_defaults
- specify the value of any argument for any service defined in that file
- bind arguments
- by name (e.g.
$adminEmail
), - by type (e.g..
Psr\Log\LoggerInterface
), or - both (e.g.
Psr\Log\LoggerInterface $requestLogger
)
- by name (e.g.