ReplaceOperation::processDomain()   C
last analyzed

Complexity

Conditions 14
Paths 204

Size

Total Lines 61
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 14.0049

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 39
c 1
b 0
f 0
nc 204
nop 1
dl 0
loc 61
ccs 33
cts 34
cp 0.9706
crap 14.0049
rs 5.3833

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\MessageCatalogueInterface;
16
use Symfony\Component\Translation\MetadataAwareInterface;
17
18
/**
19
 * This will merge and replace all values in $target with values from $source.
20
 * It is the equivalent of running array_merge($target, $source). When in conflict,
21
 * always take values from $source.
22
 *
23
 * This operation is metadata aware. It will do the same recursive merge on metadata.
24
 *
25
 * all = source ∪ target = {x: x ∈ source ∨ x ∈ target}
26
 * new = all ∖ target = {x: x ∈ source ∧ x ∉ target}
27
 * obsolete = target ∖ all = {x: x ∈ target ∧ x ∉ source}
28
 *
29
 * @author Tobias Nyholm <[email protected]>
30
 */
31
final class ReplaceOperation extends AbstractOperation
32
{
33 5
    protected function processDomain($domain): void
34
    {
35 5
        $this->messages[$domain] = [
36
            'all' => [],
37
            'new' => [],
38
            'obsolete' => [],
39
        ];
40 5
        if (\defined(\sprintf('%s::INTL_DOMAIN_SUFFIX', MessageCatalogueInterface::class))) {
41 5
            $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
42
        } else {
43
            $intlDomain = $domain;
44
        }
45
46 5
        foreach ($this->source->all($domain) as $id => $message) {
47 5
            $messageDomain = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
48
49 5
            if (!$this->target->has($id, $domain)) {
50
                // No merge required
51 5
                $translation = $message;
52 5
                $this->messages[$domain]['new'][$id] = $message;
53 5
                $resultMeta = $this->getMetadata($this->source, $messageDomain, $id);
54
            } else {
55
                // Merge required
56 5
                $translation = $message ?? $this->target->get($id, $domain);
57 5
                $resultMeta = null;
58 5
                $sourceMeta = $this->getMetadata($this->source, $messageDomain, $id);
59 5
                $targetMeta = $this->getMetadata($this->target, $this->target->defines($id, $intlDomain) ? $intlDomain : $domain, $id);
60 5
                if (\is_array($sourceMeta) && \is_array($targetMeta)) {
61
                    // We can only merge meta if both is an array
62 1
                    $resultMeta = $this->mergeMetadata($sourceMeta, $targetMeta);
63 4
                } elseif (!empty($sourceMeta)) {
64 1
                    $resultMeta = $sourceMeta;
65
                } else {
66
                    // Assert: true === empty($sourceMeta);
67 3
                    $resultMeta = $targetMeta;
68
                }
69
            }
70
71 5
            $this->messages[$domain]['all'][$id] = $translation;
72 5
            $this->result->add([$id => $translation], $messageDomain);
73
74 5
            if (!empty($resultMeta)) {
75 2
                $this->result->setMetadata($id, $resultMeta, $messageDomain);
76
            }
77
        }
78
79 5
        foreach ($this->target->all($domain) as $id => $message) {
80 5
            if ($this->result->has($id, $domain)) {
81
                // We've already merged this
82
                // That message was in source
83 5
                continue;
84
            }
85
86 5
            $messageDomain = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
87 5
            $this->messages[$domain]['all'][$id] = $message;
88 5
            $this->messages[$domain]['obsolete'][$id] = $message;
89 5
            $this->result->add([$id => $message], $messageDomain);
90
91 5
            $resultMeta = $this->getMetadata($this->target, $messageDomain, $id);
92 5
            if (!empty($resultMeta)) {
93 2
                $this->result->setMetadata($id, $resultMeta, $messageDomain);
94
            }
95
        }
96 5
    }
97
98
    /**
99
     * @param MessageCatalogueInterface|MetadataAwareInterface $catalogue
100
     *
101
     * @return array|string|mixed|null Can return anything..
102
     */
103 5
    private function getMetadata($catalogue, string $domain, string $key = '')
104
    {
105 5
        if (!$this->target instanceof MetadataAwareInterface) {
106
            return [];
107
        }
108
109 5
        return $catalogue->getMetadata($key, $domain);
110
    }
111
112 1
    private function mergeMetadata(?array $source, ?array $target): array
113
    {
114 1
        if (empty($source) && empty($target)) {
115
            return [];
116
        }
117
118 1
        if (empty($source)) {
119
            return $target;
120
        }
121
122 1
        if (empty($target)) {
123
            return $source;
124
        }
125
126 1
        if (!\is_array($source) || !\is_array($target)) {
127
            return $source;
128
        }
129
130 1
        return $this->doMergeMetadata($source, $target);
131
    }
132
133 1
    private function doMergeMetadata(array $source, array $target): array
134
    {
135 1
        $isTargetArrayAssociative = $this->isArrayAssociative($target);
136 1
        foreach ($target as $key => $value) {
137 1
            if ($isTargetArrayAssociative) {
138 1
                if (isset($source[$key]) && $source[$key] !== $value) {
139 1
                    if (\is_array($source[$key]) && \is_array($value)) {
140
                        // If both arrays, do recursive call
141 1
                        $source[$key] = $this->doMergeMetadata($source[$key], $value);
142
                    }
143
                    // Else, use value form $source
144
                } else {
145
                    // Add new value
146 1
                    $source[$key] = $value;
147
                }
148
                // if sequential
149 1
            } elseif (!\in_array($value, $source, true)) {
150 1
                $source[] = $value;
151
            }
152
        }
153
154 1
        return $source;
155
    }
156
157 1
    public function isArrayAssociative(array $arr): bool
158
    {
159 1
        if ([] === $arr) {
160
            return false;
161
        }
162
163 1
        return \array_keys($arr) !== \range(0, \count($arr) - 1);
164
    }
165
}
166