Description
Q | A |
---|---|
Bug report? | no |
Feature request? | yes |
BC Break report? | no |
RFC? | yes |
Symfony version | 3.3 |
Context
One of the goals of Symfony 3.3 is to make the DependencyInjection configuration simpler for newcomers. In Symfony we already have service autowiring and soon we could also have getter injection.
Proposal
However, in my opinion they are missing something. They try to reduce the config needed to define services ... but maybe we should instead remove the config needed to define services. We've done this multiple times in Symfony:
@Route
removes the need forrouting.yml | .xml | .php
@Assert
removes the need forvalidation.yml | .xml | .php
@ORM
removes the need forEntity.orm.yml | .xml
So, why not define a new @Service
annotation to remove the need for services.yml | .xml
.
In practice
It would be very similar to JMSDiExtraBundle. You can configure the services in the PHP file of the related class, without having to define any file.
Alternative 1
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
/** @Service('app.manager.newsletter') */
class NewsletterManager
{
private $logger;
private $em;
/** @InjectParams */
public function __construct(LoggerInterface $logger, EntityManager $em)
{
$this->logger = $logger;
$this->em = $em;
}
// ...
}
Alternative 2
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
/** @Service('app.manager.newsletter') */
class NewsletterManager
{
/** Inject('logger') */
private $logger;
/** Inject('doctrine.orm.entity_manager') */
private $em;
// ...
}
Alternative 3 (PHP 7+)
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
/** @Service('app.manager.newsletter') */
class NewsletterManager
{
/** Inject */
protected function getLogger(): LoggerInterface;
/** Inject */
protected function getEm(): EntityManager;
// ...
}
Alternative 3 (PHP 5)
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
/** @Service('app.manager.newsletter') */
class NewsletterManager
{
/** Inject('logger') */
protected function getLogger();
/** Inject('doctrine.orm.entity_manager') */
protected function getEm();
// ...
}
Comparison
For comparison purposes, this is the traditional Symfony service configuration (which requires 1 PHP file + 1 config file):
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
class NewsletterManager
{
private $logger;
private $em;
public function __construct(LoggerInterface $logger, EntityManager $em)
{
$this->logger = $logger;
$this->em = $em;
}
// ...
}
services:
app.manager.newsletter:
class: AppBundle\Manager\NewsletterManager
arguments: ['@logger', '@doctrine.orm.entity_manager']
# ...
And this is the autowiring configuration, which also requires 1 PHP file + 1 config file and the work to do is almost the same as before:
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
class NewsletterManager
{
private $logger;
private $em;
public function __construct(LoggerInterface $logger, EntityManager $em)
{
$this->logger = $logger;
$this->em = $em;
}
// ...
}
services:
app.manager.newsletter:
class: AppBundle\Manager\NewsletterManager
autowire: true
# ...
Mandatory reminder for anything related to autowiring: this feature would be 100% optional and it won't have any impact in your application if you don't want to.