Completed
Push — EZP-30006 ( ccc002...bed72d )
by André
20:27
created

MaskGenerator   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 216
Duplicated Lines 2.78 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 6
loc 216
rs 10
c 0
b 0
f 0
wmc 26
lcom 1
cbo 3

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A generateLanguageMask() 3 20 5
A generateLanguageMaskFromLanguageIds() 0 11 3
A generateLanguageIndicator() 0 4 2
A isLanguageAlwaysAvailable() 0 6 2
A isAlwaysAvailable() 0 4 1
A removeAlwaysAvailableFlag() 0 4 1
A extractLanguageIdsFromMask() 0 16 3
A extractLanguageCodesFromMask() 0 12 2
A isLanguageMaskComposite() 0 13 2
A generateLanguageMaskFromLanguageCodes() 3 15 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * File containing the Language MaskGenerator class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Legacy\Content\Language;
10
11
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
12
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
13
14
/**
15
 * Language MaskGenerator.
16
 */
17
class MaskGenerator
18
{
19
    /**
20
     * Language lookup.
21
     *
22
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\Handler
23
     */
24
    protected $languageHandler;
25
26
    /**
27
     * Creates a new Language MaskGenerator.
28
     *
29
     * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $languageHandler
30
     */
31
    public function __construct(LanguageHandler $languageHandler)
32
    {
33
        $this->languageHandler = $languageHandler;
0 ignored issues
show
Documentation Bug introduced by
$languageHandler is of type object<eZ\Publish\SPI\Pe...ntent\Language\Handler>, but the property $languageHandler was declared to be of type object<eZ\Publish\Core\P...ntent\Language\Handler>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
34
    }
35
36
    /**
37
     * Generates a language mask from the keys of $languages.
38
     *
39
     * @deprecated Move towards using {@see generateLanguageMaskFromLanguageCodes()} or the other generate* methods.
40
     *
41
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If language(s) in $languageCodes was not be found
42
     *
43
     * @param array $languages
44
     *
45
     * @return int
46
     */
47
    public function generateLanguageMask(array $languages)
48
    {
49
        $mask = 0;
50
        if (isset($languages['always-available'])) {
51
            $mask |= $languages['always-available'] ? 1 : 0;
52
            unset($languages['always-available']);
53
        }
54
55
        $languageCodes = array_keys($languages);
56
        $languageList = $this->languageHandler->loadListByLanguageCodes($languageCodes);
57
        foreach ($languageList as $language) {
58
            $mask |= $language->id;
59
        }
60
61 View Code Duplication
        if ($missing = array_diff($languageCodes, array_keys($languageList))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
62
            throw new NotFoundException('Language', implode(', ', $missing));
63
        }
64
65
        return $mask;
66
    }
67
68
    /**
69
     * Generates a language mask from pre-loaded Language Ids.
70
     *
71
     * @param int[] $languageIds
72
     * @param bool $alwaysAvailable
73
     *
74
     * @return int
75
     */
76
    public function generateLanguageMaskFromLanguageIds(array $languageIds, $alwaysAvailable): int
77
    {
78
        // make sure alwaysAvailable part of bit mask always results in 1 or 0
79
        $languageMask = $alwaysAvailable ? 1 : 0;
80
81
        foreach ($languageIds as $languageId) {
82
            $languageMask |= $languageId;
83
        }
84
85
        return $languageMask;
86
    }
87
88
    /**
89
     * Generates a language indicator from $languageCode and $alwaysAvailable.
90
     *
91
     * @param string $languageCode
92
     * @param bool $alwaysAvailable
93
     *
94
     * @return int
95
     *
96
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
97
     */
98
    public function generateLanguageIndicator($languageCode, $alwaysAvailable)
99
    {
100
        return $this->languageHandler->loadByLanguageCode($languageCode)->id | ($alwaysAvailable ? 1 : 0);
101
    }
102
103
    /**
104
     * Checks if $language is always available in $languages;.
105
     *
106
     * @param string $language
107
     * @param array $languages
108
     *
109
     * @return bool
110
     */
111
    public function isLanguageAlwaysAvailable($language, array $languages): bool
112
    {
113
        return isset($languages['always-available'])
114
           && ($languages['always-available'] == $language)
115
        ;
116
    }
117
118
    /**
119
     * Checks if $languageMask contains the alwaysAvailable bit field.
120
     *
121
     * @param int $languageMask
122
     *
123
     * @return bool
124
     */
125
    public function isAlwaysAvailable($languageMask): bool
126
    {
127
        return (bool)($languageMask & 1);
128
    }
129
130
    /**
131
     * Removes the alwaysAvailable flag from $languageId and returns cleaned up $languageId.
132
     *
133
     * @param int $languageId
134
     *
135
     * @return int
136
     */
137
    public function removeAlwaysAvailableFlag($languageId): int
138
    {
139
        return $languageId & ~1;
140
    }
141
142
    /**
143
     * Extracts every language Ids contained in $languageMask.
144
     *
145
     * @param int $languageMask
146
     *
147
     * @return array Array of language Id
148
     */
149
    public function extractLanguageIdsFromMask($languageMask): array
150
    {
151
        $exp = 2;
152
        $result = array();
153
154
        // Decomposition of $languageMask into its binary components.
155
        while ($exp <= $languageMask) {
156
            if ($languageMask & $exp) {
157
                $result[] = $exp;
158
            }
159
160
            $exp *= 2;
161
        }
162
163
        return $result;
164
    }
165
166
    /**
167
     * Extracts Language codes contained in given $languageMask.
168
     *
169
     * @param int $languageMask
170
     *
171
     * @return array
172
     */
173
    public function extractLanguageCodesFromMask($languageMask): array
174
    {
175
        $languageCodes = [];
176
        $languageList = $this->languageHandler->loadList(
177
            $this->extractLanguageIdsFromMask($languageMask)
178
        );
179
        foreach ($languageList as $language) {
180
            $languageCodes[] = $language->languageCode;
181
        }
182
183
        return $languageCodes;
184
    }
185
186
    /**
187
     * Checks if given $languageMask consists of multiple languages.
188
     *
189
     * @param int $languageMask
190
     *
191
     * @return bool
192
     */
193
    public function isLanguageMaskComposite($languageMask): bool
194
    {
195
        // Ignore first bit
196
        $languageMask = $this->removeAlwaysAvailableFlag($languageMask);
197
198
        // Special case
199
        if ($languageMask === 0) {
200
            return false;
201
        }
202
203
        // Return false if power of 2
204
        return (bool)($languageMask & ($languageMask - 1));
205
    }
206
207
    /**
208
     * Generates a language mask from plain array of language codes and always available flag.
209
     *
210
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If language(s) in $languageCodes was not be found
211
     *
212
     * @param string[] $languageCodes
213
     * @param bool $isAlwaysAvailable
214
     *
215
     * @return int
216
     */
217
    public function generateLanguageMaskFromLanguageCodes(array $languageCodes, bool $isAlwaysAvailable = false): int
218
    {
219
        $mask = $isAlwaysAvailable ? 1 : 0;
220
221
        $languageList = $this->languageHandler->loadListByLanguageCodes($languageCodes);
222
        foreach ($languageList as $language) {
223
            $mask |= $language->id;
224
        }
225
226 View Code Duplication
        if ($missing = array_diff($languageCodes, array_keys($languageList))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
227
            throw new NotFoundException('Language', implode(', ', $missing));
228
        }
229
230
        return $mask;
231
    }
232
}
233