Skip to content

Commit 9a6d3e5

Browse files
committed
feature symfony#22382 [config] Add abbitily to deprecate a node (Nyholm, fabpot, sanpii)
This PR was merged into the 4.0-dev branch. Discussion ---------- [config] Add abbitily to deprecate a node | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes | BC breaks? | maybe | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | symfony/symfony-docs#7794 For BC breaks, I don’t know if modifying the Xml and Yaml dumper output is considering as a BC break (it’s just a comment). Commits ------- 31d2250 [config] Add abbitily to deprecate a node 3b6442f feature symfony#23947 [Translation] Adding the ability do load <notes> in xliff2.0 (Nyholm) b0cdb53 [Translation] Adding the ability do load <notes> in xliff2.0
2 parents 3a9653d + 31d2250 commit 9a6d3e5

15 files changed

+152
-1
lines changed

src/Symfony/Component/Config/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
3.4.0
5+
-----
6+
7+
* added `setDeprecated()` method to indicate a deprecated node
8+
49
3.3.0
510
-----
611

src/Symfony/Component/Config/Definition/ArrayNode.php

+4
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ protected function finalizeValue($value)
234234
}
235235

236236
foreach ($this->children as $name => $child) {
237+
if ($child->isDeprecated()) {
238+
@trigger_error($child->getDeprecationMessage($name, $this->getPath()), E_USER_DEPRECATED);
239+
}
240+
237241
if (!array_key_exists($name, $value)) {
238242
if ($child->isRequired()) {
239243
$msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());

src/Symfony/Component/Config/Definition/BaseNode.php

+37
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ abstract class BaseNode implements NodeInterface
2929
protected $finalValidationClosures = array();
3030
protected $allowOverwrite = true;
3131
protected $required = false;
32+
protected $deprecationMessage = null;
3233
protected $equivalentValues = array();
3334
protected $attributes = array();
3435

@@ -141,6 +142,19 @@ public function setRequired($boolean)
141142
$this->required = (bool) $boolean;
142143
}
143144

145+
/**
146+
* Sets this node as deprecated.
147+
*
148+
* You can use %node% and %path% placeholders in your message to display,
149+
* respectively, the node name and its complete path.
150+
*
151+
* @param string|null $message Deprecated message
152+
*/
153+
public function setDeprecated($message)
154+
{
155+
$this->deprecationMessage = $message;
156+
}
157+
144158
/**
145159
* Sets if this node can be overridden.
146160
*
@@ -181,6 +195,29 @@ public function isRequired()
181195
return $this->required;
182196
}
183197

198+
/**
199+
* Checks if this node is deprecated.
200+
*
201+
* @return bool
202+
*/
203+
public function isDeprecated()
204+
{
205+
return null !== $this->deprecationMessage;
206+
}
207+
208+
/**
209+
* Returns the deprecated message.
210+
*
211+
* @param string $node the configuration node name
212+
* @param string $path the path of the node
213+
*
214+
* @return string
215+
*/
216+
public function getDeprecationMessage($node, $path)
217+
{
218+
return strtr($this->deprecationMessage, array('%node%' => $node, '%path%' => $path));
219+
}
220+
184221
/**
185222
* Returns the name of this node.
186223
*

src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php

+18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ abstract class NodeDefinition implements NodeParentInterface
2727
protected $defaultValue;
2828
protected $default = false;
2929
protected $required = false;
30+
protected $deprecationMessage = null;
3031
protected $merge;
3132
protected $allowEmptyValue = true;
3233
protected $nullEquivalent;
@@ -168,6 +169,23 @@ public function isRequired()
168169
return $this;
169170
}
170171

172+
/**
173+
* Sets the node as deprecated.
174+
*
175+
* You can use %node% and %path% placeholders in your message to display,
176+
* respectively, the node name and its complete path.
177+
*
178+
* @param string $message Deprecation message
179+
*
180+
* @return $this
181+
*/
182+
public function setDeprecated($message = 'The child node "%node%" at path "%path%" is deprecated.')
183+
{
184+
$this->deprecationMessage = $message;
185+
186+
return $this;
187+
}
188+
171189
/**
172190
* Sets the equivalent value used when the node contains null.
173191
*

src/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ protected function createNode()
5454
$node->addEquivalentValue(true, $this->trueEquivalent);
5555
$node->addEquivalentValue(false, $this->falseEquivalent);
5656
$node->setRequired($this->required);
57+
$node->setDeprecated($this->deprecationMessage);
5758

5859
if (null !== $this->validation) {
5960
$node->setFinalValidationClosures($this->validation->rules);

src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php

+4
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $name
153153
$comments[] = 'Required';
154154
}
155155

156+
if ($child->isDeprecated()) {
157+
$comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $child->getPath()));
158+
}
159+
156160
if ($child instanceof EnumNode) {
157161
$comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
158162
}

src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php

+5
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ private function writeNode(NodeInterface $node, $depth = 0, $prototypedArray = f
123123
$comments[] = 'Required';
124124
}
125125

126+
// deprecated?
127+
if ($node->isDeprecated()) {
128+
$comments[] = sprintf('Deprecated (%s)', $node->getDeprecationMessage($node->getName(), $node->getPath()));
129+
}
130+
126131
// example
127132
if ($example && !is_array($example)) {
128133
$comments[] = 'Example: '.$example;

src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ private function getConfigurationAsString()
3838
return str_replace("\n", PHP_EOL, <<<'EOL'
3939
<!-- Namespace: http://example.org/schema/dic/acme_root -->
4040
<!-- scalar-required: Required -->
41+
<!-- scalar-deprecated: Deprecated (The child node "scalar_deprecated" at path "acme_root.scalar_deprecated" is deprecated.) -->
42+
<!-- scalar-deprecated-with-message: Deprecated (Deprecation custom message for "scalar_deprecated_with_message" at "acme_root.scalar_deprecated_with_message") -->
4143
<!-- enum-with-default: One of "this"; "that" -->
4244
<!-- enum: One of "this"; "that" -->
4345
<config
@@ -50,6 +52,8 @@ private function getConfigurationAsString()
5052
scalar-array-empty=""
5153
scalar-array-defaults="elem1,elem2"
5254
scalar-required=""
55+
scalar-deprecated=""
56+
scalar-deprecated-with-message=""
5357
node-with-a-looong-name=""
5458
enum-with-default="this"
5559
enum=""

src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ private function getConfigurationAsString()
9898
- elem1
9999
- elem2
100100
scalar_required: ~ # Required
101+
scalar_deprecated: ~ # Deprecated (The child node "scalar_deprecated" at path "acme_root.scalar_deprecated" is deprecated.)
102+
scalar_deprecated_with_message: ~ # Deprecated (Deprecation custom message for "scalar_deprecated_with_message" at "acme_root.scalar_deprecated_with_message")
101103
node_with_a_looong_name: ~
102104
enum_with_default: this # One of "this"; "that"
103105
enum: ~ # One of "this"; "that"

src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public function getConfigTreeBuilder()
3535
->scalarNode('scalar_array_empty')->defaultValue(array())->end()
3636
->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end()
3737
->scalarNode('scalar_required')->isRequired()->end()
38+
->scalarNode('scalar_deprecated')->setDeprecated()->end()
39+
->scalarNode('scalar_deprecated_with_message')->setDeprecated('Deprecation custom message for "%node%" at "%path%"')->end()
3840
->scalarNode('node_with_a_looong_name')->end()
3941
->enumNode('enum_with_default')->values(array('this', 'that'))->defaultValue('this')->end()
4042
->enumNode('enum')->values(array('this', 'that'))->end()

src/Symfony/Component/Translation/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ CHANGELOG
1313
* Added `TranslationExtractorPass`
1414
* Added `TranslatorPass`
1515
* Added <notes> section to the Xliff 2.0 dumper.
16+
* Improved Xliff 2.0 loader to load <notes> section.
1617
* Added `TranslationWriterInterface`
1718
* Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write`
1819

src/Symfony/Component/Translation/Loader/XliffFileLoader.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, $
127127

128128
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');
129129

130-
foreach ($xml->xpath('//xliff:unit/xliff:segment') as $segment) {
130+
foreach ($xml->xpath('//xliff:unit') as $unit) {
131+
$segment = $unit->segment;
131132
$source = $segment->source;
132133

133134
// If the xlf file has another encoding specified, try to convert it because
@@ -144,6 +145,18 @@ private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, $
144145
}
145146
}
146147

148+
if (isset($unit->notes)) {
149+
$metadata['notes'] = array();
150+
foreach ($unit->notes->note as $noteNode) {
151+
$note = array();
152+
foreach ($noteNode->attributes() as $key => $value) {
153+
$note[$key] = (string) $value;
154+
}
155+
$note['content'] = (string) $noteNode;
156+
$metadata['notes'][] = $note;
157+
}
158+
}
159+
147160
$catalogue->setMetadata((string) $source, $metadata, $domain);
148161
}
149162
}

src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php

+5
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,17 @@ public function testFormatCatalogueWithNotesMetadata()
9393
$catalogue = new MessageCatalogue('en_US');
9494
$catalogue->add(array(
9595
'foo' => 'bar',
96+
'baz' => 'biz',
9697
));
9798
$catalogue->setMetadata('foo', array('notes' => array(
9899
array('category' => 'state', 'content' => 'new'),
99100
array('category' => 'approved', 'content' => 'true'),
100101
array('category' => 'section', 'content' => 'user login', 'priority' => '1'),
101102
)));
103+
$catalogue->setMetadata('baz', array('notes' => array(
104+
array('id' => 'x', 'content' => 'x_content'),
105+
array('appliesTo' => 'target', 'category' => 'quality', 'content' => 'Fuzzy'),
106+
)));
102107

103108
$dumper = new XliffFileDumper();
104109

src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php

+40
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,44 @@ public function testLoadVersion2()
188188
// target attributes
189189
$this->assertEquals(array('target-attributes' => array('order' => 1)), $catalogue->getMetadata('bar', 'domain1'));
190190
}
191+
192+
public function testLoadVersion2WithNoteMeta()
193+
{
194+
$loader = new XliffFileLoader();
195+
$resource = __DIR__.'/../fixtures/resources-notes-meta.xlf';
196+
$catalogue = $loader->load($resource, 'en', 'domain1');
197+
198+
$this->assertEquals('en', $catalogue->getLocale());
199+
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
200+
$this->assertSame(array(), libxml_get_errors());
201+
202+
// test for "foo" metadata
203+
$this->assertTrue($catalogue->defines('foo', 'domain1'));
204+
$metadata = $catalogue->getMetadata('foo', 'domain1');
205+
$this->assertNotEmpty($metadata);
206+
$this->assertCount(3, $metadata['notes']);
207+
208+
$this->assertEquals('state', $metadata['notes'][0]['category']);
209+
$this->assertEquals('new', $metadata['notes'][0]['content']);
210+
211+
$this->assertEquals('approved', $metadata['notes'][1]['category']);
212+
$this->assertEquals('true', $metadata['notes'][1]['content']);
213+
214+
$this->assertEquals('section', $metadata['notes'][2]['category']);
215+
$this->assertEquals('1', $metadata['notes'][2]['priority']);
216+
$this->assertEquals('user login', $metadata['notes'][2]['content']);
217+
218+
// test for "baz" metadata
219+
$this->assertTrue($catalogue->defines('baz', 'domain1'));
220+
$metadata = $catalogue->getMetadata('baz', 'domain1');
221+
$this->assertNotEmpty($metadata);
222+
$this->assertCount(2, $metadata['notes']);
223+
224+
$this->assertEquals('x', $metadata['notes'][0]['id']);
225+
$this->assertEquals('x_content', $metadata['notes'][0]['content']);
226+
227+
$this->assertEquals('target', $metadata['notes'][1]['appliesTo']);
228+
$this->assertEquals('quality', $metadata['notes'][1]['category']);
229+
$this->assertEquals('Fuzzy', $metadata['notes'][1]['content']);
230+
}
191231
}

src/Symfony/Component/Translation/Tests/fixtures/resources-notes-meta.xlf

+10
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,15 @@
1212
<target>bar</target>
1313
</segment>
1414
</unit>
15+
<unit id="uqWglk0">
16+
<notes>
17+
<note id="x">x_content</note>
18+
<note appliesTo="target" category="quality">Fuzzy</note>
19+
</notes>
20+
<segment>
21+
<source>baz</source>
22+
<target>biz</target>
23+
</segment>
24+
</unit>
1525
</file>
1626
</xliff>

0 commit comments

Comments
 (0)