1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the PHP Translation package. |
5
|
|
|
* |
6
|
|
|
* (c) PHP Translation team <[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 Translation\Bundle\Catalogue\Operation; |
13
|
|
|
|
14
|
|
|
use Symfony\Component\Translation\Catalogue\AbstractOperation; |
15
|
|
|
use Symfony\Component\Translation\MetadataAwareInterface; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* This will merge and replace all values in $target with values from $source. |
19
|
|
|
* It is the equivalent of running array_merge($target, $source). When in conflict, |
20
|
|
|
* always take values from $source. |
21
|
|
|
* |
22
|
|
|
* This operation is metadata aware. It will do the same recursive merge on metadata. |
23
|
|
|
* |
24
|
|
|
* all = source ∪ target = {x: x ∈ source ∨ x ∈ target} |
25
|
|
|
* new = all ∖ target = {x: x ∈ source ∧ x ∉ target} |
26
|
|
|
* obsolete = target ∖ all = {x: x ∈ target ∧ x ∉ source} |
27
|
|
|
* |
28
|
|
|
* @author Tobias Nyholm <[email protected]> |
29
|
|
|
*/ |
30
|
|
|
final class ReplaceOperation extends AbstractOperation |
31
|
|
|
{ |
32
|
5 |
|
protected function processDomain($domain) |
33
|
|
|
{ |
34
|
5 |
|
$this->messages[$domain] = [ |
35
|
5 |
|
'all' => [], |
36
|
5 |
|
'new' => [], |
37
|
5 |
|
'obsolete' => [], |
38
|
|
|
]; |
39
|
5 |
|
$sourceMessages = $this->source->all($domain); |
40
|
|
|
|
41
|
5 |
View Code Duplication |
foreach ($this->target->all($domain) as $id => $message) { |
|
|
|
|
42
|
4 |
|
$this->messages[$domain]['all'][$id] = $message; |
43
|
|
|
|
44
|
|
|
// If $id is NOT defined in source. |
45
|
4 |
|
if (!array_key_exists($id, $sourceMessages)) { |
46
|
4 |
|
$this->messages[$domain]['obsolete'][$id] = $message; |
47
|
4 |
|
} |
48
|
5 |
|
} |
49
|
|
|
|
50
|
5 |
View Code Duplication |
foreach ($sourceMessages as $id => $message) { |
|
|
|
|
51
|
4 |
|
$this->messages[$domain]['all'][$id] = $message; |
52
|
4 |
|
if (!$this->target->has($id, $domain)) { |
53
|
4 |
|
$this->messages[$domain]['new'][$id] = $message; |
54
|
4 |
|
} |
55
|
5 |
|
} |
56
|
|
|
|
57
|
5 |
|
$this->result->add($this->messages[$domain]['all'], $domain); |
58
|
|
|
|
59
|
5 |
|
$targetMetadata = $this->target instanceof MetadataAwareInterface ? $this->target->getMetadata('', $domain) : []; |
60
|
5 |
|
$sourceMetadata = $this->source instanceof MetadataAwareInterface ? $this->source->getMetadata('', $domain) : []; |
61
|
5 |
|
$resultMetadata = $this->mergeMetaData($sourceMetadata, $targetMetadata); |
62
|
|
|
|
63
|
|
|
// Write back metadata |
64
|
5 |
|
foreach ($resultMetadata as $id => $data) { |
|
|
|
|
65
|
2 |
|
$this->result->setMetadata($id, $data, $domain); |
66
|
5 |
|
} |
67
|
5 |
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @param array|null $source |
71
|
|
|
* @param array|null $target |
72
|
|
|
* |
73
|
|
|
* @return array |
74
|
|
|
*/ |
75
|
5 |
|
private function mergeMetadata($source, $target) |
76
|
|
|
{ |
77
|
5 |
|
if (empty($source) && empty($target)) { |
78
|
3 |
|
return []; |
79
|
|
|
} |
80
|
|
|
|
81
|
2 |
|
if (empty($source)) { |
82
|
|
|
return $target; |
83
|
|
|
} |
84
|
|
|
|
85
|
2 |
|
if (empty($target)) { |
86
|
|
|
return $source; |
87
|
|
|
} |
88
|
|
|
|
89
|
2 |
|
if (!is_array($source) || !is_array($target)) { |
90
|
|
|
return $source; |
91
|
|
|
} |
92
|
|
|
|
93
|
2 |
|
$result = $this->doMergeMetadata($source, $target); |
94
|
|
|
|
95
|
2 |
|
return $result; |
96
|
|
|
} |
97
|
|
|
|
98
|
2 |
|
private function doMergeMetadata(array $source, array $target) |
99
|
|
|
{ |
100
|
2 |
|
$isTargetArrayAssociative = $this->isArrayAssociative($target); |
101
|
2 |
|
foreach ($target as $key => $value) { |
102
|
2 |
|
if ($isTargetArrayAssociative) { |
103
|
2 |
|
if (isset($source[$key]) && $source[$key] !== $value) { |
104
|
2 |
|
if (is_array($source[$key]) && is_array($value)) { |
105
|
|
|
// If both arrays, do recursive call |
106
|
1 |
|
$source[$key] = $this->doMergeMetadata($source[$key], $value); |
107
|
1 |
|
} |
108
|
|
|
// Else, use value form $source |
|
|
|
|
109
|
2 |
|
} else { |
110
|
|
|
// Add new value |
111
|
2 |
|
$source[$key] = $value; |
112
|
|
|
} |
113
|
|
|
// if sequential |
114
|
2 |
|
} elseif (!in_array($value, $source)) { |
115
|
1 |
|
$source[] = $value; |
116
|
1 |
|
} |
117
|
2 |
|
} |
118
|
|
|
|
119
|
2 |
|
return $source; |
120
|
|
|
} |
121
|
|
|
|
122
|
2 |
|
public function isArrayAssociative(array $arr) |
123
|
|
|
{ |
124
|
2 |
|
if ([] === $arr) { |
125
|
|
|
return false; |
126
|
|
|
} |
127
|
|
|
|
128
|
2 |
|
return array_keys($arr) !== range(0, count($arr) - 1); |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.