Completed
Push — master ( 397eee...f113dc )
by Gaetano
22:13 queued 10:37
created

LanguageManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use eZ\Publish\API\Repository\Values\Content\Language;
6
use Kaliop\eZMigrationBundle\API\Collection\LanguageCollection;
7
use Kaliop\eZMigrationBundle\API\MigrationGeneratorInterface;
8
use Kaliop\eZMigrationBundle\Core\Matcher\LanguageMatcher;
9
10
/**
11
 * Handles language migrations.
12
 */
13
class LanguageManager extends RepositoryExecutor implements MigrationGeneratorInterface
14
{
15
    protected $supportedStepTypes = array('language');
16
    protected $supportedActions = array('create', 'load', 'update', 'delete');
17
18
    /** @var LanguageMatcher $languageMatcher */
19
    protected $languageMatcher;
20
21
    /**
22
     * @param LanguageMatcher $languageMatcher
23
     */
24
    public function __construct(LanguageMatcher $languageMatcher)
25
    {
26
        $this->languageMatcher = $languageMatcher;
27
    }
28
29
    /**
30
     * Handles the language create migration action
31
     *
32
     * @todo allow creating disabkled languages
33
     */
34
    protected function create($step)
35
    {
36
        $languageService = $this->repository->getContentLanguageService();
37
38
        if (!isset($step->dsl['lang'])) {
39
            throw new \Exception("The 'lang' key is required to create a new language.");
40
        }
41
42
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
43
        $languageCreateStruct->languageCode = $this->referenceResolver->resolveReference($step->dsl['lang']);
44 View Code Duplication
        if (isset($step->dsl['name'])) {
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...
45
            $languageCreateStruct->name = $this->referenceResolver->resolveReference($step->dsl['name']);
46
        }
47 View Code Duplication
        if (isset($step->dsl['enabled'])) {
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...
48
            $languageCreateStruct->enabled = (bool)$this->referenceResolver->resolveReference($step->dsl['enabled']);
49
        }
50
        $language = $languageService->createLanguage($languageCreateStruct);
51
52
        $this->setReferences($language, $step);
0 ignored issues
show
Documentation introduced by
$language is of type object<eZ\Publish\API\Re...alues\Content\Language>, but the function expects a object<Object>|object<Ka...ion\AbstractCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
53
54
        return $language;
55
    }
56
57
    protected function load($step)
58
    {
59
        $languageCollection = $this->matchLanguages('load', $step);
60
61
        $this->setReferences($languageCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $languageCollection defined by $this->matchLanguages('load', $step) on line 59 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
62
63
        return $languageCollection;
64
    }
65
66
    /**
67
     * Handles the language update migration action
68
     */
69
    protected function update($step)
70
    {
71 View Code Duplication
        if (isset($step->dsl['lang'])) {
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...
72
            // BC
73
            $step->dsl['match'] = array('language_code' => $step->dsl['lang']);
74
        }
75
76
        $languageCollection = $this->matchLanguages('delete', $step);
77
78
        if (count($languageCollection) > 1 && array_key_exists('references', $step->dsl)) {
79
            throw new \Exception("Can not execute Language update because multiple languages match, and a references section is specified in the dsl. References can be set when only 1 language matches");
80
        }
81
82
        $languageService = $this->repository->getContentLanguageService();
83
84
        foreach ($languageCollection as $key => $language) {
0 ignored issues
show
Bug introduced by
The expression $languageCollection of type object<Kaliop\eZMigratio...anguageCollection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
85
86
            if (isset($step->dsl['name'])) {
87
                $languageService->updateLanguageName($language, $this->referenceResolver->resolveReference($step->dsl['name']));
88
            }
89
90
            if (isset($step->dsl['enabled'])) {
91
                if ($this->referenceResolver->resolveReference($step->dsl['enabled'])) {
92
                    $languageService->enableLanguage($language);
93
                } else {
94
                    $languageService->disableLanguage($language);
95
                };
96
            }
97
98
            $languageCollection[$key] = $languageService->loadLanguageById($key);
99
        }
100
101
        $this->setReferences($languageCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $languageCollection defined by $this->matchLanguages('delete', $step) on line 76 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
102
103
        return $languageCollection;
104
    }
105
106
    /**
107
     * Handles the language delete migration action
108
     */
109
    protected function delete($step)
110
    {
111 View Code Duplication
        if (isset($step->dsl['lang'])) {
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...
112
            // BC
113
            $step->dsl['match'] = array('language_code' => $step->dsl['lang']);
114
        }
115
        $languageCollection = $this->matchLanguages('delete', $step);
116
117
        $this->setReferences($languageCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $languageCollection defined by $this->matchLanguages('delete', $step) on line 115 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
118
119
        $languageService = $this->repository->getContentLanguageService();
120
121
        foreach ($languageCollection as $language) {
0 ignored issues
show
Bug introduced by
The expression $languageCollection of type object<Kaliop\eZMigratio...anguageCollection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
122
            $languageService->deleteLanguage($language);
123
        }
124
125
        return $languageCollection;
126
    }
127
128
    /**
129
     * @param string $action
130
     * @return LanguageCollection
131
     * @throws \Exception
132
     */
133 View Code Duplication
    protected function matchLanguages($action, $step)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
134
    {
135
        if (!isset($step->dsl['match'])) {
136
            throw new \Exception("A match condition is required to $action a language");
137
        }
138
139
        // convert the references passed in the match
140
        $match = $this->resolveReferencesRecursively($step->dsl['match']);
141
142
        return $this->languageMatcher->match($match);
143
    }
144
145
    /**
146
     * @param Language $language
147
     * @param array $references the definitions of the references to set
148
     * @throws \InvalidArgumentException When trying to assign a reference to an unsupported attribute
149
     * @return array key: the reference names, values: the reference values
150
     */
151 View Code Duplication
    protected function getReferencesValues($language, array $references, $step)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
152
    {
153
        $refs = array();
154
155
        foreach ($references as $reference) {
156
157
            switch ($reference['attribute']) {
158
                case 'language_id':
159
                case 'id':
160
                    $value = $language->id;
161
                    break;
162
                case 'enabled':
163
                    $value = $language->enabled;
164
                    break;
165
                case 'language_code':
166
                    $value = $language->languageCode;
167
                    break;
168
                case 'language_name':
169
                case 'name':
170
                    $value = $language->name;
171
                    break;
172
                default:
173
                    throw new \InvalidArgumentException('Language Manager does not support setting references for attribute ' . $reference['attribute']);
174
            }
175
176
            $refs[$reference['identifier']] = $value;
177
        }
178
179
        return $refs;
180
    }
181
182
    /**
183
     * @param array $matchCondition
184
     * @param string $mode
185
     * @param array $context
186
     * @throws \Exception
187
     * @return array
188
     */
189
    public function generateMigration(array $matchCondition, $mode, array $context = array())
190
    {
191
        $previousUserId = $this->loginUser($this->getAdminUserIdentifierFromContext($context));
192
        $languageCollection = $this->languageMatcher->match($matchCondition);
193
        $data = array();
194
195
        /** @var \eZ\Publish\API\Repository\Values\Content\Language $language */
196
        foreach ($languageCollection as $language) {
0 ignored issues
show
Bug introduced by
The expression $languageCollection of type object<Kaliop\eZMigratio...anguageCollection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
197
198
            $languageData = array(
199
                'type' => reset($this->supportedStepTypes),
200
                'mode' => $mode,
201
            );
202
203
            switch ($mode) {
204
                case 'create':
205
                    $languageData = array_merge(
206
                        $languageData,
207
                        array(
208
                            'lang' => $language->languageCode,
209
                            'name' => $language->name,
210
                            'enabled' => $language->enabled
211
                        )
212
                    );
213
                    break;
214
                case 'update':
215
                    $languageData = array_merge(
216
                        $languageData,
217
                        array(
218
                            'match' => array(
219
                                LanguageMatcher::MATCH_LANGUAGE_ID => $language->id
220
                            ),
221
                            'lang' => $language->languageCode,
222
                            'name' => $language->name,
223
                            'enabled' => $language->enabled
224
                        )
225
                    );
226
                    break;
227
                case 'delete':
228
                    $languageData = array_merge(
229
                        $languageData,
230
                        array(
231
                            'match' => array(
232
                                LanguageMatcher::MATCH_LANGUAGE_ID => $language->id
233
                            )
234
                        )
235
                    );
236
                    break;
237
                default:
238
                    throw new \Exception("Executor 'language' doesn't support mode '$mode'");
239
            }
240
241
            $data[] = $languageData;
242
        }
243
244
        $this->loginUser($previousUserId);
245
        return $data;
246
    }
247
}
248