Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 316277e

Browse files
committed
[translation][framework-bundle] Deprecated DiffOperation
The ``DiffOperation`` class has been deprecated and ``TargetOperation`` should be used instead, because ``DiffOperation`` has nothing to do with 'diff', thus its class name is misleading. Also added detailed documents for all operation interface and classes. The following names should have consistent meanings for all operations: The name of ``intersection`` is temporarily introduced here to explain this issue. * [x] ``intersection`` = source ∩ target = {x: x ∈ source ∧ x ∈ target} * [x] ``all`` = **result of the operation, depends on the operation.** * [x] ``new`` = all ∖ source = {x: x ∈ all ∧ x ∉ source} * [x] ``obsolete`` = source ∖ all = {x: x ∈ source ∧ x ∉ all} The following analysis explains why ``DiffOperation`` should be deprecated. * [x] ``all`` = source ∪ target = {x: x ∈ source ∨ x ∈ target} * [x] ``new`` = all ∖ source = {x: x ∈ target ∧ ∉ source} * [x] ``obsolete`` = source ∖ all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅ This absolutely makes sense. * [ ] ``all`` = intersection ∪ (target ∖ intersection) = target * [x] ``new`` = all ∖ source = {x: x ∈ target ∧ x ∉ source} * [x] ``obsolete`` = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target} The ``all`` part is confusing because 'diff' should either mean 'relative complement' or 'symmetric difference' operation: * ``all`` = source ∖ target = {x: x ∈ source ∧ x ∉ target} * ``all`` = (source ∖ target) ∪ (target ∖ source) = {x: x ∈ source ∧ x ∉ target ∨ x ∈ target ∧ x ∉ source} * ``all`` = intersection ∪ (target ∖ intersection) = target So the name of ``DiffOperation`` is misleading and inappropriate. Unfortunately, there is no corresponding set operation for this class, so it's hard to give it an apppriate name. From my point of view, I believe the most accurate name for this class should be ``TargetOperation`` because its result is same as the target set. | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | n/a
1 parent e777272 commit 316277e

File tree

10 files changed

+378
-50
lines changed

10 files changed

+378
-50
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Command;
1313

1414
use Symfony\Component\Console\Style\SymfonyStyle;
15-
use Symfony\Component\Translation\Catalogue\DiffOperation;
15+
use Symfony\Component\Translation\Catalogue\TargetOperation;
1616
use Symfony\Component\Translation\Catalogue\MergeOperation;
1717
use Symfony\Component\Console\Input\InputInterface;
1818
use Symfony\Component\Console\Output\OutputInterface;
@@ -139,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
139139

140140
// process catalogues
141141
$operation = $input->getOption('clean')
142-
? new DiffOperation($currentCatalogue, $extractedCatalogue)
142+
? new TargetOperation($currentCatalogue, $extractedCatalogue)
143143
: new MergeOperation($currentCatalogue, $extractedCatalogue);
144144

145145
// Exit if no messages found.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
13+
14+
use Symfony\Component\Console\Application;
15+
use Symfony\Component\Console\Tester\CommandTester;
16+
use Symfony\Bundle\FrameworkBundle\Command\TranslationUpdateCommand;
17+
use Symfony\Component\Filesystem\Filesystem;
18+
19+
class TranslationUpdateCommandTest extends \PHPUnit_Framework_TestCase
20+
{
21+
private $fs;
22+
private $translationDir;
23+
24+
public function testDumpMessagesAndClean()
25+
{
26+
$tester = $this->createCommandTester($this->getContainer(array('foo' => 'foo')));
27+
$tester->execute(array('locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true));
28+
$this->assertRegExp('/OK/', $tester->getDisplay());
29+
}
30+
31+
protected function setUp()
32+
{
33+
$this->fs = new Filesystem();
34+
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
35+
$this->fs->mkdir($this->translationDir.'/Resources/translations');
36+
$this->fs->mkdir($this->translationDir.'/Resources/views');
37+
}
38+
39+
protected function tearDown()
40+
{
41+
$this->fs->remove($this->translationDir);
42+
}
43+
44+
/**
45+
* @return CommandTester
46+
*/
47+
private function createCommandTester($container)
48+
{
49+
$command = new TranslationUpdateCommand();
50+
$command->setContainer($container);
51+
52+
$application = new Application();
53+
$application->add($command);
54+
55+
return new CommandTester($application->find('translation:update'));
56+
}
57+
58+
private function getContainer($extractedMessages = array(), $loadedMessages = array(), $kernel = null)
59+
{
60+
$translator = $this->getMockBuilder('Symfony\Component\Translation\Translator')
61+
->disableOriginalConstructor()
62+
->getMock();
63+
64+
$translator
65+
->expects($this->any())
66+
->method('getFallbackLocales')
67+
->will($this->returnValue(array('en')));
68+
69+
$extractor = $this->getMock('Symfony\Component\Translation\Extractor\ExtractorInterface');
70+
$extractor
71+
->expects($this->any())
72+
->method('extract')
73+
->will(
74+
$this->returnCallback(function ($path, $catalogue) use ($extractedMessages) {
75+
$catalogue->add($extractedMessages);
76+
})
77+
);
78+
79+
$loader = $this->getMock('Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader');
80+
$loader
81+
->expects($this->any())
82+
->method('loadMessages')
83+
->will(
84+
$this->returnCallback(function ($path, $catalogue) use ($loadedMessages) {
85+
$catalogue->add($loadedMessages);
86+
})
87+
);
88+
89+
$writer = $this->getMock('Symfony\Component\Translation\Writer\TranslationWriter');
90+
$writer
91+
->expects($this->any())
92+
->method('getFormats')
93+
->will(
94+
$this->returnValue(array('xlf', 'yml'))
95+
);
96+
97+
if (null === $kernel) {
98+
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
99+
$kernel
100+
->expects($this->any())
101+
->method('getBundle')
102+
->will($this->returnValueMap(array(
103+
array('foo', true, $this->getBundle($this->translationDir)),
104+
array('test', true, $this->getBundle('test')),
105+
)));
106+
}
107+
108+
$kernel
109+
->expects($this->any())
110+
->method('getRootDir')
111+
->will($this->returnValue($this->translationDir));
112+
113+
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
114+
$container
115+
->expects($this->any())
116+
->method('get')
117+
->will($this->returnValueMap(array(
118+
array('translation.extractor', 1, $extractor),
119+
array('translation.loader', 1, $loader),
120+
array('translation.writer', 1, $writer),
121+
array('translator', 1, $translator),
122+
array('kernel', 1, $kernel),
123+
)));
124+
125+
return $container;
126+
}
127+
128+
private function getBundle($path)
129+
{
130+
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
131+
$bundle
132+
->expects($this->any())
133+
->method('getPath')
134+
->will($this->returnValue($path))
135+
;
136+
137+
return $bundle;
138+
}
139+
}

src/Symfony/Component/Translation/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ CHANGELOG
66

77
* deprecated Translator::getMessages(), use TranslatorBagInterface::getCatalogue() instead.
88
* added options 'as_tree', 'inline' to YamlFileDumper
9+
* [DEPRECATION] The `DiffOperation` class has been deprecated and
10+
will be removed in Symfony 3.0, since its operation has nothing to do with 'diff',
11+
so the class name is misleading. The `TargetOperation` class should be used for
12+
this use-case instead.
13+
914

1015
2.7.0
1116
-----

src/Symfony/Component/Translation/Catalogue/AbstractOperation.php

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,69 @@
1717
/**
1818
* Base catalogues binary operation class.
1919
*
20+
* A catalogue binary operation performs operation on
21+
* source (the left argument) and target (the right argument) catalogues and
22+
* stores the following results:
23+
*
24+
* Messages: also called 'all', are valid messages for the given domain after the operation is performed.
25+
*
26+
* New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}).
27+
*
28+
* Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}).
29+
*
30+
* Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.
31+
*
2032
* @author Jean-François Simon <[email protected]>
2133
*/
2234
abstract class AbstractOperation implements OperationInterface
2335
{
2436
/**
25-
* @var MessageCatalogueInterface
37+
* @var MessageCatalogueInterface The source catalogue
2638
*/
2739
protected $source;
2840

2941
/**
30-
* @var MessageCatalogueInterface
42+
* @var MessageCatalogueInterface The target catalogue
3143
*/
3244
protected $target;
3345

3446
/**
35-
* @var MessageCatalogue
47+
* @var MessageCatalogue The result catalogue
3648
*/
3749
protected $result;
3850

3951
/**
40-
* @var null|array
52+
* @var null|array The domains affected by this operation
4153
*/
4254
private $domains;
4355

4456
/**
45-
* @var array
57+
* This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
58+
*
59+
* The data structure of this array is as follows:
60+
* ```php
61+
* array(
62+
* 'domain 1' => array(
63+
* 'all' => array(...),
64+
* 'new' => array(...),
65+
* 'obsolete' => array(...)
66+
* ),
67+
* 'domain 2' => array(
68+
* 'all' => array(...),
69+
* 'new' => array(...),
70+
* 'obsolete' => array(...)
71+
* ),
72+
* ...
73+
* )
74+
* ```
75+
*
76+
* @var array The array that stores 'all', 'new' and 'obsolete' messages
4677
*/
4778
protected $messages;
4879

4980
/**
50-
* @param MessageCatalogueInterface $source
51-
* @param MessageCatalogueInterface $target
81+
* @param MessageCatalogueInterface $source The source catalogue
82+
* @param MessageCatalogueInterface $target The target catalogue
5283
*
5384
* @throws \LogicException
5485
*/
@@ -140,7 +171,10 @@ public function getResult()
140171
}
141172

142173
/**
143-
* @param string $domain
174+
* Performs operation on source and target catalogues for the given domain and
175+
* stores the results.
176+
*
177+
* @param string $domain The domain which the operation will be performed for
144178
*/
145179
abstract protected function processDomain($domain);
146180
}

src/Symfony/Component/Translation/Catalogue/DiffOperation.php

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,23 @@
1111

1212
namespace Symfony\Component\Translation\Catalogue;
1313

14+
@trigger_error('The '.__NAMESPACE__.'\DiffOperation class is deprecated since version 2.8 and will be removed in 3.0. Use the TargetOperation class in the same namespace instead.', E_USER_DEPRECATED);
15+
1416
/**
1517
* Diff operation between two catalogues.
1618
*
19+
* The name of 'Diff' is misleading because the operation
20+
* has nothing to do with diff:
21+
*
22+
* intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}
23+
* all = intersection ∪ (target ∖ intersection) = target
24+
* new = all ∖ source = {x: x ∈ target ∧ x ∉ source}
25+
* obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target}
26+
*
1727
* @author Jean-François Simon <[email protected]>
28+
*
29+
* @deprecated since version 2.8, to be removed in 3.0. Use TargetOperation instead.
1830
*/
19-
class DiffOperation extends AbstractOperation
31+
class DiffOperation extends TargetOperation
2032
{
21-
/**
22-
* {@inheritdoc}
23-
*/
24-
protected function processDomain($domain)
25-
{
26-
$this->messages[$domain] = array(
27-
'all' => array(),
28-
'new' => array(),
29-
'obsolete' => array(),
30-
);
31-
32-
foreach ($this->source->all($domain) as $id => $message) {
33-
if ($this->target->has($id, $domain)) {
34-
$this->messages[$domain]['all'][$id] = $message;
35-
$this->result->add(array($id => $message), $domain);
36-
if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
37-
$this->result->setMetadata($id, $keyMetadata, $domain);
38-
}
39-
} else {
40-
$this->messages[$domain]['obsolete'][$id] = $message;
41-
}
42-
}
43-
44-
foreach ($this->target->all($domain) as $id => $message) {
45-
if (!$this->source->has($id, $domain)) {
46-
$this->messages[$domain]['all'][$id] = $message;
47-
$this->messages[$domain]['new'][$id] = $message;
48-
$this->result->add(array($id => $message), $domain);
49-
if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
50-
$this->result->setMetadata($id, $keyMetadata, $domain);
51-
}
52-
}
53-
}
54-
}
5533
}

src/Symfony/Component/Translation/Catalogue/MergeOperation.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
namespace Symfony\Component\Translation\Catalogue;
1313

1414
/**
15-
* Merge operation between two catalogues.
15+
* Merge operation between two catalogues as follows:
16+
* all = source ∪ target = {x: x ∈ source ∨ x ∈ target}
17+
* new = all ∖ source = {x: x ∈ target ∧ x ∉ source}
18+
* obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅
19+
* Basically, the result contains messages from both catalogues.
1620
*
1721
* @author Jean-François Simon <[email protected]>
1822
*/

src/Symfony/Component/Translation/Catalogue/OperationInterface.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@
1616
/**
1717
* Represents an operation on catalogue(s).
1818
*
19+
* An instance of this interface performs an operation on one or more catalogues and
20+
* stores intermediate and final results of the operation.
21+
*
22+
* The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and
23+
* the following results are stored:
24+
*
25+
* Messages: also called 'all', are valid messages for the given domain after the operation is performed.
26+
*
27+
* New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}).
28+
*
29+
* Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}).
30+
*
31+
* Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.
32+
*
1933
* @author Jean-François Simon <[email protected]>
2034
*/
2135
interface OperationInterface
@@ -28,7 +42,7 @@ interface OperationInterface
2842
public function getDomains();
2943

3044
/**
31-
* Returns all valid messages after operation.
45+
* Returns all valid messages ('all') after operation.
3246
*
3347
* @param string $domain
3448
*
@@ -37,7 +51,7 @@ public function getDomains();
3751
public function getMessages($domain);
3852

3953
/**
40-
* Returns new messages after operation.
54+
* Returns new messages ('new') after operation.
4155
*
4256
* @param string $domain
4357
*
@@ -46,7 +60,7 @@ public function getMessages($domain);
4660
public function getNewMessages($domain);
4761

4862
/**
49-
* Returns obsolete messages after operation.
63+
* Returns obsolete messages ('obsolete') after operation.
5064
*
5165
* @param string $domain
5266
*
@@ -55,7 +69,7 @@ public function getNewMessages($domain);
5569
public function getObsoleteMessages($domain);
5670

5771
/**
58-
* Returns resulting catalogue.
72+
* Returns resulting catalogue ('result').
5973
*
6074
* @return MessageCatalogueInterface
6175
*/

0 commit comments

Comments
 (0)