[DI] Allow to change the deprecation message in Definition

This commit is contained in:
Baptiste Clavié 2015-08-10 14:35:12 +02:00
parent 954247d550
commit 0b3d0a0bd9
14 changed files with 85 additions and 21 deletions

View File

@ -932,7 +932,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
} }
if ($definition->isDeprecated()) { if ($definition->isDeprecated()) {
@trigger_error(sprintf('The service %s relies on a deprecated definition. You should avoid using it.', $id), E_USER_DEPRECATED); @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
} }
if ($tryProxy && $definition->isLazy()) { if ($tryProxy && $definition->isLazy()) {

View File

@ -30,6 +30,8 @@ class Definition
private $factoryMethod; private $factoryMethod;
private $factoryService; private $factoryService;
private $shared = true; private $shared = true;
private $deprecated = false;
private $deprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.';
private $scope = ContainerInterface::SCOPE_CONTAINER; private $scope = ContainerInterface::SCOPE_CONTAINER;
private $properties = array(); private $properties = array();
private $calls = array(); private $calls = array();
@ -38,7 +40,6 @@ class Definition
private $public = true; private $public = true;
private $synthetic = false; private $synthetic = false;
private $abstract = false; private $abstract = false;
private $deprecated = false;
private $synchronized = false; private $synchronized = false;
private $lazy = false; private $lazy = false;
private $decoratedService; private $decoratedService;
@ -834,14 +835,29 @@ class Definition
* Whether this definition is deprecated, that means it should not be called * Whether this definition is deprecated, that means it should not be called
* anymore. * anymore.
* *
* @param bool $status * @param bool $status
* @param string $template Template message to use if the definition is deprecated
* *
* @return Definition the current instance * @return Definition the current instance
* *
* @throws InvalidArgumentException When the message template is invalid.
*
* @api * @api
*/ */
public function setDeprecated($status = true) public function setDeprecated($status = true, $template = null)
{ {
if (null !== $template) {
if (preg_match('#[\r\n]|\*/#', $template)) {
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
}
if (false === strpos($template, '%service_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
}
$this->deprecationTemplate = $template;
}
$this->deprecated = (bool) $status; $this->deprecated = (bool) $status;
return $this; return $this;
@ -860,6 +876,20 @@ class Definition
return $this->deprecated; return $this->deprecated;
} }
/**
* Message to use if this definition is deprecated.
*
* @param string $id Service id relying on this definition
*
* @return string
*
* @api
*/
public function getDeprecationMessage($id)
{
return str_replace('%service_id%', $id, $this->deprecationTemplate);
}
/** /**
* Sets a configurator to call after the service is fully initialized. * Sets a configurator to call after the service is fully initialized.
* *

View File

@ -597,7 +597,7 @@ class PhpDumper extends Dumper
$return[] = ''; $return[] = '';
} }
$return[] = '@deprecated'; $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
} }
$return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return)); $return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return));
@ -661,7 +661,7 @@ EOF;
$code .= sprintf(" throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n }\n", $id); $code .= sprintf(" throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n }\n", $id);
} else { } else {
if ($definition->isDeprecated()) { if ($definition->isDeprecated()) {
$code .= sprintf(" @trigger_error('The service %s has been marked as deprecated. You should stop using it.', E_USER_DEPRECATED);\n\n", $id); $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true));
} }
$code .= $code .=

View File

@ -148,9 +148,6 @@ class XmlDumper extends Dumper
if ($definition->isLazy()) { if ($definition->isLazy()) {
$service->setAttribute('lazy', 'true'); $service->setAttribute('lazy', 'true');
} }
if ($definition->isDeprecated()) {
$service->setAttribute('deprecated', 'true');
}
if (null !== $decorated = $definition->getDecoratedService()) { if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId, $priority) = $decorated; list($decorated, $renamedId, $priority) = $decorated;
$service->setAttribute('decorates', $decorated); $service->setAttribute('decorates', $decorated);
@ -204,6 +201,13 @@ class XmlDumper extends Dumper
$service->appendChild($factory); $service->appendChild($factory);
} }
if ($definition->isDeprecated()) {
$deprecated = $this->document->createElement('deprecated');
$deprecated->appendChild($this->document->createTextNode($definition->getDeprecationMessage('%service_id%')));
$service->appendChild($deprecated);
}
if ($callable = $definition->getConfigurator()) { if ($callable = $definition->getConfigurator()) {
$configurator = $this->document->createElement('configurator'); $configurator = $this->document->createElement('configurator');

View File

@ -105,7 +105,7 @@ class YamlDumper extends Dumper
} }
if ($definition->isDeprecated()) { if ($definition->isDeprecated()) {
$code .= " deprecated: true\n"; $code .= sprintf(" deprecated: %s\n", $definition->getDeprecationMessage('%service_id%'));
} }
if ($definition->getFactoryClass(false)) { if ($definition->getFactoryClass(false)) {

View File

@ -147,7 +147,7 @@ class XmlFileLoader extends FileLoader
$definition = new Definition(); $definition = new Definition();
} }
foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract', 'deprecated') as $key) { foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
if ($value = $service->getAttribute($key)) { if ($value = $service->getAttribute($key)) {
if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) { if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
@trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED); @trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
@ -181,6 +181,10 @@ class XmlFileLoader extends FileLoader
$definition->setFile($files[0]->nodeValue); $definition->setFile($files[0]->nodeValue);
} }
if ($deprecated = $this->getChildren($service, 'deprecated')) {
$definition->setDeprecated(true, $deprecated[0]->nodeValue);
}
$definition->setArguments($this->getArgumentsAsPhp($service, 'argument')); $definition->setArguments($this->getArgumentsAsPhp($service, 'argument'));
$definition->setProperties($this->getArgumentsAsPhp($service, 'property')); $definition->setProperties($this->getArgumentsAsPhp($service, 'property'));

View File

@ -196,8 +196,8 @@ class YamlFileLoader extends FileLoader
$definition->setAbstract($service['abstract']); $definition->setAbstract($service['abstract']);
} }
if (isset($service['deprecated'])) { if (array_key_exists('deprecated', $service)) {
$definition->setDeprecated($service['deprecated']); $definition->setDeprecated(true, $service['deprecated']);
} }
if (isset($service['factory'])) { if (isset($service['factory'])) {

View File

@ -81,6 +81,7 @@
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" /> <xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="factory" type="callable" minOccurs="0" maxOccurs="1" /> <xsd:element name="factory" type="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="deprecated" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
@ -94,7 +95,6 @@
<xsd:attribute name="synchronized" type="boolean" /> <xsd:attribute name="synchronized" type="boolean" />
<xsd:attribute name="lazy" type="boolean" /> <xsd:attribute name="lazy" type="boolean" />
<xsd:attribute name="abstract" type="boolean" /> <xsd:attribute name="abstract" type="boolean" />
<xsd:attribute name="deprecated" type="boolean" />
<xsd:attribute name="factory-class" type="xsd:string" /> <xsd:attribute name="factory-class" type="xsd:string" />
<xsd:attribute name="factory-method" type="xsd:string" /> <xsd:attribute name="factory-method" type="xsd:string" />
<xsd:attribute name="factory-service" type="xsd:string" /> <xsd:attribute name="factory-service" type="xsd:string" />

View File

@ -73,7 +73,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
set_error_handler(function ($errno, $errstr) use ($that, &$wasTriggered) { set_error_handler(function ($errno, $errstr) use ($that, &$wasTriggered) {
$that->assertSame(E_USER_DEPRECATED, $errno); $that->assertSame(E_USER_DEPRECATED, $errno);
$that->assertSame('The service deprecated_foo relies on a deprecated definition. You should avoid using it.', $errstr); $that->assertSame('The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.', $errstr);
$wasTriggered = true; $wasTriggered = true;
}); });

View File

@ -236,6 +236,8 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
/** /**
* @covers Symfony\Component\DependencyInjection\Definition::setDeprecated * @covers Symfony\Component\DependencyInjection\Definition::setDeprecated
* @covers Symfony\Component\DependencyInjection\Definition::isDeprecated * @covers Symfony\Component\DependencyInjection\Definition::isDeprecated
* @covers Symfony\Component\DependencyInjection\Definition::hasCustomDeprecationTemplate
* @covers Symfony\Component\DependencyInjection\Definition::getDeprecationMessage
*/ */
public function testSetIsDeprecated() public function testSetIsDeprecated()
{ {
@ -243,6 +245,28 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default'); $this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default');
$this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface'); $this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface');
$this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.'); $this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.');
$this->assertSame('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', $def->getDeprecationMessage('deprecated_service'), '->getDeprecationMessage() should return a formatted message template');
}
/**
* @dataProvider invalidDeprecationMessageProvider
* @covers Symfony\Component\DependencyInjection\Definition::setDeprecated
* @expectedException Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
*/
public function testSetDeprecatedWithInvalidDeprecationTemplate($message)
{
$def = new Definition('stdClass');
$def->setDeprecated(false, $message);
}
public function invalidDeprecationMessageProvider()
{
return array(
"With \rs" => array("invalid \r message %service_id%"),
"With \ns" => array("invalid \n message %service_id%"),
'With */s' => array('invalid */ message %service_id%'),
'message not containing require %service_id% variable' => array('this is deprecated'),
);
} }
/** /**

View File

@ -152,11 +152,11 @@ class ProjectServiceContainer extends Container
* *
* @return \stdClass A stdClass instance. * @return \stdClass A stdClass instance.
* *
* @deprecated * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.
*/ */
protected function getDeprecatedServiceService() protected function getDeprecatedServiceService()
{ {
@trigger_error('The service deprecated_service has been marked as deprecated. You should stop using it.', E_USER_DEPRECATED); @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED);
return $this->services['deprecated_service'] = new \stdClass(); return $this->services['deprecated_service'] = new \stdClass();
} }

View File

@ -153,11 +153,11 @@ class ProjectServiceContainer extends Container
* *
* @return \stdClass A stdClass instance. * @return \stdClass A stdClass instance.
* *
* @deprecated * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.
*/ */
protected function getDeprecatedServiceService() protected function getDeprecatedServiceService()
{ {
@trigger_error('The service deprecated_service has been marked as deprecated. You should stop using it.', E_USER_DEPRECATED); @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED);
return $this->services['deprecated_service'] = new \stdClass(); return $this->services['deprecated_service'] = new \stdClass();
} }

View File

@ -87,7 +87,9 @@
<service id="decorated" class="stdClass"/> <service id="decorated" class="stdClass"/>
<service id="decorator_service" class="stdClass" decorates="decorated"/> <service id="decorator_service" class="stdClass" decorates="decorated"/>
<service id="decorator_service_with_name" class="stdClass" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/> <service id="decorator_service_with_name" class="stdClass" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/>
<service id="deprecated_service" class="stdClass" deprecated="true"/> <service id="deprecated_service" class="stdClass">
<deprecated>The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.</deprecated>
</service>
<service id="new_factory" class="FactoryClass" public="false"> <service id="new_factory" class="FactoryClass" public="false">
<property name="foo">bar</property> <property name="foo">bar</property>
</service> </service>

View File

@ -78,7 +78,7 @@ services:
decoration_inner_name: decorated.pif-pouf decoration_inner_name: decorated.pif-pouf
deprecated_service: deprecated_service:
class: stdClass class: stdClass
deprecated: true deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.
new_factory: new_factory:
class: FactoryClass class: FactoryClass
public: false public: false