diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index 4ef4e625ba..ffa347dbf4 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.4.0 +----- + + * added `setDeprecated()` method to indicate a deprecated node + 3.3.0 ----- diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php index 457e7a8c92..2ffa2a2137 100644 --- a/src/Symfony/Component/Config/Definition/ArrayNode.php +++ b/src/Symfony/Component/Config/Definition/ArrayNode.php @@ -234,6 +234,10 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface } foreach ($this->children as $name => $child) { + if ($child->isDeprecated()) { + @trigger_error($child->getDeprecationMessage($name, $this->getPath()), E_USER_DEPRECATED); + } + if (!array_key_exists($name, $value)) { if ($child->isRequired()) { $msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath()); diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php index dbf36335b6..6e6ac1fdb4 100644 --- a/src/Symfony/Component/Config/Definition/BaseNode.php +++ b/src/Symfony/Component/Config/Definition/BaseNode.php @@ -29,6 +29,7 @@ abstract class BaseNode implements NodeInterface protected $finalValidationClosures = array(); protected $allowOverwrite = true; protected $required = false; + protected $deprecationMessage = null; protected $equivalentValues = array(); protected $attributes = array(); @@ -141,6 +142,19 @@ abstract class BaseNode implements NodeInterface $this->required = (bool) $boolean; } + /** + * Sets this node as deprecated. + * + * You can use %node% and %path% placeholders in your message to display, + * respectively, the node name and its complete path. + * + * @param string|null $message Deprecated message + */ + public function setDeprecated($message) + { + $this->deprecationMessage = $message; + } + /** * Sets if this node can be overridden. * @@ -181,6 +195,29 @@ abstract class BaseNode implements NodeInterface return $this->required; } + /** + * Checks if this node is deprecated. + * + * @return bool + */ + public function isDeprecated() + { + return null !== $this->deprecationMessage; + } + + /** + * Returns the deprecated message. + * + * @param string $node the configuration node name + * @param string $path the path of the node + * + * @return string + */ + public function getDeprecationMessage($node, $path) + { + return strtr($this->deprecationMessage, array('%node%' => $node, '%path%' => $path)); + } + /** * Returns the name of this node. * diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php index 1b712a3150..eb212caa44 100644 --- a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php @@ -27,6 +27,7 @@ abstract class NodeDefinition implements NodeParentInterface protected $defaultValue; protected $default = false; protected $required = false; + protected $deprecationMessage = null; protected $merge; protected $allowEmptyValue = true; protected $nullEquivalent; @@ -168,6 +169,23 @@ abstract class NodeDefinition implements NodeParentInterface return $this; } + /** + * Sets the node as deprecated. + * + * You can use %node% and %path% placeholders in your message to display, + * respectively, the node name and its complete path. + * + * @param string $message Deprecation message + * + * @return $this + */ + public function setDeprecated($message = 'The child node "%node%" at path "%path%" is deprecated.') + { + $this->deprecationMessage = $message; + + return $this; + } + /** * Sets the equivalent value used when the node contains null. * diff --git a/src/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php index a46b7ea61d..26565e1771 100644 --- a/src/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php @@ -54,6 +54,7 @@ class VariableNodeDefinition extends NodeDefinition $node->addEquivalentValue(true, $this->trueEquivalent); $node->addEquivalentValue(false, $this->falseEquivalent); $node->setRequired($this->required); + $node->setDeprecated($this->deprecationMessage); if (null !== $this->validation) { $node->setFinalValidationClosures($this->validation->rules); diff --git a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php index ec5460f2f5..44cc9ea9ab 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php @@ -153,6 +153,10 @@ class XmlReferenceDumper $comments[] = 'Required'; } + if ($child->isDeprecated()) { + $comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $child->getPath())); + } + if ($child instanceof EnumNode) { $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues())); } diff --git a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php index 16076354db..a470e5f9fb 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php @@ -123,6 +123,11 @@ class YamlReferenceDumper $comments[] = 'Required'; } + // deprecated? + if ($node->isDeprecated()) { + $comments[] = sprintf('Deprecated (%s)', $node->getDeprecationMessage($node->getName(), $node->getPath())); + } + // example if ($example && !is_array($example)) { $comments[] = 'Example: '.$example; diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php index fd5f9c8cde..3123c9740a 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php @@ -38,6 +38,8 @@ class XmlReferenceDumperTest extends TestCase return str_replace("\n", PHP_EOL, <<<'EOL' + + scalarNode('scalar_array_empty')->defaultValue(array())->end() ->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end() ->scalarNode('scalar_required')->isRequired()->end() + ->scalarNode('scalar_deprecated')->setDeprecated()->end() + ->scalarNode('scalar_deprecated_with_message')->setDeprecated('Deprecation custom message for "%node%" at "%path%"')->end() ->scalarNode('node_with_a_looong_name')->end() ->enumNode('enum_with_default')->values(array('this', 'that'))->defaultValue('this')->end() ->enumNode('enum')->values(array('this', 'that'))->end() diff --git a/src/Symfony/Component/Translation/CHANGELOG.md b/src/Symfony/Component/Translation/CHANGELOG.md index 4ff932812c..f9de2dd2f4 100644 --- a/src/Symfony/Component/Translation/CHANGELOG.md +++ b/src/Symfony/Component/Translation/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * Added `TranslationExtractorPass` * Added `TranslatorPass` * Added section to the Xliff 2.0 dumper. + * Improved Xliff 2.0 loader to load section. * Added `TranslationWriterInterface` * Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write` diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 1603dc0b04..72f7216729 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -127,7 +127,8 @@ class XliffFileLoader implements LoaderInterface $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0'); - foreach ($xml->xpath('//xliff:unit/xliff:segment') as $segment) { + foreach ($xml->xpath('//xliff:unit') as $unit) { + $segment = $unit->segment; $source = $segment->source; // If the xlf file has another encoding specified, try to convert it because @@ -144,6 +145,18 @@ class XliffFileLoader implements LoaderInterface } } + if (isset($unit->notes)) { + $metadata['notes'] = array(); + foreach ($unit->notes->note as $noteNode) { + $note = array(); + foreach ($noteNode->attributes() as $key => $value) { + $note[$key] = (string) $value; + } + $note['content'] = (string) $noteNode; + $metadata['notes'][] = $note; + } + } + $catalogue->setMetadata((string) $source, $metadata, $domain); } } diff --git a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php index 30ca4d3d24..738d4b3b2f 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php @@ -93,12 +93,17 @@ class XliffFileDumperTest extends TestCase $catalogue = new MessageCatalogue('en_US'); $catalogue->add(array( 'foo' => 'bar', + 'baz' => 'biz', )); $catalogue->setMetadata('foo', array('notes' => array( array('category' => 'state', 'content' => 'new'), array('category' => 'approved', 'content' => 'true'), array('category' => 'section', 'content' => 'user login', 'priority' => '1'), ))); + $catalogue->setMetadata('baz', array('notes' => array( + array('id' => 'x', 'content' => 'x_content'), + array('appliesTo' => 'target', 'category' => 'quality', 'content' => 'Fuzzy'), + ))); $dumper = new XliffFileDumper(); diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index 32351d34e1..a06b7c0990 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -188,4 +188,44 @@ class XliffFileLoaderTest extends TestCase // target attributes $this->assertEquals(array('target-attributes' => array('order' => 1)), $catalogue->getMetadata('bar', 'domain1')); } + + public function testLoadVersion2WithNoteMeta() + { + $loader = new XliffFileLoader(); + $resource = __DIR__.'/../fixtures/resources-notes-meta.xlf'; + $catalogue = $loader->load($resource, 'en', 'domain1'); + + $this->assertEquals('en', $catalogue->getLocale()); + $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); + $this->assertSame(array(), libxml_get_errors()); + + // test for "foo" metadata + $this->assertTrue($catalogue->defines('foo', 'domain1')); + $metadata = $catalogue->getMetadata('foo', 'domain1'); + $this->assertNotEmpty($metadata); + $this->assertCount(3, $metadata['notes']); + + $this->assertEquals('state', $metadata['notes'][0]['category']); + $this->assertEquals('new', $metadata['notes'][0]['content']); + + $this->assertEquals('approved', $metadata['notes'][1]['category']); + $this->assertEquals('true', $metadata['notes'][1]['content']); + + $this->assertEquals('section', $metadata['notes'][2]['category']); + $this->assertEquals('1', $metadata['notes'][2]['priority']); + $this->assertEquals('user login', $metadata['notes'][2]['content']); + + // test for "baz" metadata + $this->assertTrue($catalogue->defines('baz', 'domain1')); + $metadata = $catalogue->getMetadata('baz', 'domain1'); + $this->assertNotEmpty($metadata); + $this->assertCount(2, $metadata['notes']); + + $this->assertEquals('x', $metadata['notes'][0]['id']); + $this->assertEquals('x_content', $metadata['notes'][0]['content']); + + $this->assertEquals('target', $metadata['notes'][1]['appliesTo']); + $this->assertEquals('quality', $metadata['notes'][1]['category']); + $this->assertEquals('Fuzzy', $metadata['notes'][1]['content']); + } } diff --git a/src/Symfony/Component/Translation/Tests/fixtures/resources-notes-meta.xlf b/src/Symfony/Component/Translation/Tests/fixtures/resources-notes-meta.xlf index 04f9a0a06e..e9995fa847 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/resources-notes-meta.xlf +++ b/src/Symfony/Component/Translation/Tests/fixtures/resources-notes-meta.xlf @@ -12,5 +12,15 @@ bar + + + x_content + Fuzzy + + + baz + biz + +