Completed
Push — master ( ba3b59...d7270b )
by Gaetano
16:37 queued 12:29
created

ObjectStateManager::update()   C

Complexity

Conditions 11
Paths 11

Size

Total Lines 37
Code Lines 20

Duplication

Lines 37
Ratio 100 %

Code Coverage

Tests 14
CRAP Score 14.267

Importance

Changes 0
Metric Value
dl 37
loc 37
ccs 14
cts 20
cp 0.7
rs 5.2653
c 0
b 0
f 0
cc 11
eloc 20
nc 11
nop 1
crap 14.267

How to fix   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
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateGroupMatcher;
6
use Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateMatcher;
7
use Kaliop\eZMigrationBundle\API\Collection\ObjectStateCollection;
8
use Kaliop\eZMigrationBundle\API\MigrationGeneratorInterface;
9
10
/**
11
 * Handles object-state migrations.
12
 */
13
class ObjectStateManager extends RepositoryExecutor implements MigrationGeneratorInterface
14
{
15
    /**
16
     * @var array
17
     */
18
    protected $supportedStepTypes = array('object_state');
19
20
    /**
21
     * @var ObjectStateMatcher
22
     */
23
    protected $objectStateMatcher;
24
25
    /**
26
     * @var ObjectStateGroupMatcher
27
     */
28
    protected $objectStateGroupMatcher;
29
30
    /**
31
     * @param ObjectStateMatcher      $objectStateMatcher
32
     * @param ObjectStateGroupMatcher $objectStateGroupMatcher
33
     */
34 73
    public function __construct(ObjectStateMatcher $objectStateMatcher, ObjectStateGroupMatcher $objectStateGroupMatcher)
35
    {
36 73
        $this->objectStateMatcher = $objectStateMatcher;
37 73
        $this->objectStateGroupMatcher = $objectStateGroupMatcher;
38 73
    }
39
40
    /**
41
     * Handles the create step of object state migrations.
42
     *
43
     * @throws \Exception
44
     */
45 1
    protected function create($step)
46
    {
47 1 View Code Duplication
        foreach (array('object_state_group', 'names', 'identifier') as $key) {
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 1
            if (!isset($step->dsl[$key])) {
49 1
                throw new \Exception("The '$key' key is missing in a object state creation definition");
50
            }
51
        }
52
53 1
        if (!count($step->dsl['names'])) {
54
            throw new \Exception('No object state names have been defined. Need to specify at least one to create the state.');
55
        }
56
57 1
        $objectStateService = $this->repository->getObjectStateService();
58
59 1
        $objectStateGroupId = $step->dsl['object_state_group'];
60 1
        $objectStateGroupId = $this->referenceResolver->resolveReference($objectStateGroupId);
61 1
        $objectStateGroup = $this->objectStateGroupMatcher->matchOneByKey($objectStateGroupId);
62
63 1
        $objectStateIdentifier = $this->referenceResolver->resolveReference($step->dsl['identifier']);
64 1
        $objectStateCreateStruct = $objectStateService->newObjectStateCreateStruct($objectStateIdentifier);
65 1
        $objectStateCreateStruct->defaultLanguageCode = self::DEFAULT_LANGUAGE_CODE;
66
67 1
        foreach ($step->dsl['names'] as $languageCode => $name) {
68 1
            $objectStateCreateStruct->names[$languageCode] = $name;
69
        }
70 1
        if (isset($step->dsl['descriptions'])) {
71 1
            foreach ($step->dsl['descriptions'] as $languageCode => $description) {
72 1
                $objectStateCreateStruct->descriptions[$languageCode] = $description;
73
            }
74
        }
75
76 1
        $objectState = $objectStateService->createObjectState($objectStateGroup, $objectStateCreateStruct);
77
78 1
        $this->setReferences($objectState, $step);
79
80 1
        return $objectState;
81
    }
82
83
    /**
84
     * Handles the update step of object state migrations.
85
     *
86
     * @throws \Exception
87
     */
88 1 View Code Duplication
    protected function update($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...
89
    {
90 1
        $stateCollection = $this->matchObjectStates('update', $step);
91
92 1
        if (count($stateCollection) > 1 && array_key_exists('references', $step->dsl)) {
93
            throw new \Exception("Can not execute Object State update because multiple states match, and a references section is specified in the dsl. References can be set when only 1 state matches");
94
        }
95
96 1
        if (count($stateCollection) > 1 && isset($step->dsl['identifier'])) {
97
            throw new \Exception("Can not execute Object State update because multiple states match, and an identifier is specified in the dsl.");
98
        }
99
100 1
        $objectStateService = $this->repository->getObjectStateService();
101
102 1
        foreach ($stateCollection as $state) {
0 ignored issues
show
Bug introduced by
The expression $stateCollection of type object<Kaliop\eZMigratio...ctStateCollection>|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...
103 1
            $objectStateUpdateStruct = $objectStateService->newObjectStateUpdateStruct();
104
105 1
            if (isset($step->dsl['identifier'])) {
106 1
                $objectStateUpdateStruct->identifier = $this->referenceResolver->resolveReference($step->dsl['identifier']);
107
            }
108 1
            if (isset($step->dsl['names'])) {
109
                foreach ($step->dsl['names'] as $name) {
110
                    $objectStateUpdateStruct->names[$name['languageCode']] = $name['name'];
111
                }
112
            }
113 1
            if (isset($step->dsl['descriptions'])) {
114
                foreach ($step->dsl['descriptions'] as $languageCode => $description) {
115
                    $objectStateUpdateStruct->descriptions[$languageCode] = $description;
116
                }
117
            }
118 1
            $state = $objectStateService->updateObjectState($state, $objectStateUpdateStruct);
119
120 1
            $this->setReferences($state, $step);
121
        }
122
123 1
        return $stateCollection;
124
    }
125
126
    /**
127
     * Handles the deletion step of object state migrations.
128
     */
129 1 View Code Duplication
    protected function delete($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...
130
    {
131 1
        $stateCollection = $this->matchObjectStates('delete', $step);
132
133 1
        $this->setReferences($stateCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $stateCollection defined by $this->matchObjectStates('delete', $step) on line 131 can be null; however, Kaliop\eZMigrationBundle...anager::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...
134
135 1
        $objectStateService = $this->repository->getObjectStateService();
136
137 1
        foreach ($stateCollection as $state) {
0 ignored issues
show
Bug introduced by
The expression $stateCollection of type object<Kaliop\eZMigratio...ctStateCollection>|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...
138 1
            $objectStateService->deleteObjectState($state);
139
        }
140
141 1
        return $stateCollection;
142
    }
143
144
    /**
145
     * @param string $action
146
     * @return ObjectStateCollection
147
     * @throws \Exception
148
     */
149 1 View Code Duplication
    protected function matchObjectStates($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...
150
    {
151 1
        if (!isset($step->dsl['match'])) {
152
            throw new \Exception("A match condition is required to $action an object state");
153
        }
154
155
        // convert the references passed in the match
156 1
        $match = $this->resolveReferencesRecursively($step->dsl['match']);
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: will be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
157
158 1
        return $this->objectStateMatcher->match($match);
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     * @param \eZ\Publish\API\Repository\Values\ObjectState\ObjectState|ObjectStateCollection $objectState
164
     */
165 1 View Code Duplication
    protected function setReferences($objectState, $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...
166
    {
167 1
        if (!array_key_exists('references', $step->dsl)) {
168 1
            return false;
169
        }
170
171 1
        $references = $this->setReferencesCommon($objectState, $step->dsl['references']);
172 1
        $objectState = $this->insureSingleEntity($objectState, $references);
173
174 1
        foreach ($references as $reference) {
175 1
            switch ($reference['attribute']) {
176 1
                case 'object_state_id':
177 1
                case 'id':
178 1
                    $value = $objectState->id;
179 1
                    break;
180
                case 'priority':
181
                    $value = $objectState->priority;
182
                    break;
183
                default:
184
                    throw new \InvalidArgumentException('Object State Manager does not support setting references for attribute ' . $reference['attribute']);
185
            }
186
187 1
            $overwrite = false;
188 1
            if (isset($reference['overwrite'])) {
189
                $overwrite = $reference['overwrite'];
190
            }
191 1
            $this->referenceResolver->addReference($reference['identifier'], $value, $overwrite);
192
        }
193
194 1
        return true;
195
    }
196
197
    /**
198
     * @param array $matchCondition
199
     * @param string $mode
200
     * @param array $context
201
     * @throws \Exception
202
     * @return array
203
     */
204 3
    public function generateMigration(array $matchCondition, $mode, array $context = array())
205
    {
206 3
        $previousUserId = $this->loginUser($this->getAdminUserIdentifierFromContext($context));
207 3
        $objectStateCollection = $this->objectStateMatcher->match($matchCondition);
208 3
        $data = array();
209
210
        /** @var \eZ\Publish\API\Repository\Values\ObjectState\ObjectState $objectState */
211 3
        foreach ($objectStateCollection as $objectState) {
0 ignored issues
show
Bug introduced by
The expression $objectStateCollection of type object<Kaliop\eZMigratio...ctStateCollection>|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...
212
213
            $groupData = array(
214 3
                'type' => reset($this->supportedStepTypes),
215 3
                'mode' => $mode,
216
            );
217
218
            switch ($mode) {
219 3
                case 'create':
220 1
                    $groupData = array_merge(
221 1
                        $groupData,
222
                        array(
223 1
                            'object_state_group' => $objectState->getObjectStateGroup()->identifier,
224 1
                            'identifier' => $objectState->identifier,
225
                        )
226
                    );
227 1
                    break;
228 2
                case 'update':
229 1
                    $groupData = array_merge(
230 1
                        $groupData,
231
                        array(
232
                            'match' => array(
233
                                ObjectStateMatcher::MATCH_OBJECTSTATE_IDENTIFIER =>
234 1
                                    $objectState->getObjectStateGroup()->identifier . '/' . $objectState->identifier
235
                            ),
236 1
                            'identifier' => $objectState->identifier,
237
                        )
238
                    );
239 1
                    break;
240 1
                case 'delete':
241 1
                    $groupData = array_merge(
242 1
                        $groupData,
243
                        array(
244
                            'match' => array(
245
                                ObjectStateMatcher::MATCH_OBJECTSTATE_IDENTIFIER =>
246 1
                                    $objectState->getObjectStateGroup()->identifier . '/' . $objectState->identifier
247
                            )
248
                        )
249
                    );
250 1
                    break;
251
                default:
252
                    throw new \Exception("Executor 'object_state_group' doesn't support mode '$mode'");
253
            }
254
255 3 View Code Duplication
            if ($mode != 'delete') {
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...
256 2
                $names = array();
257 2
                $descriptions = array();
258 2
                foreach($objectState->languageCodes as $languageCode) {
259 2
                    $names[$languageCode] =  $objectState->getName($languageCode);
260
                }
261 2
                foreach($objectState->languageCodes as $languageCode) {
262 2
                    $descriptions[$languageCode] =  $objectState->getDescription($languageCode);
263
                }
264 2
                $groupData = array_merge(
265 2
                    $groupData,
266
                    array(
267 2
                        'names' => $names,
268 2
                        'descriptions' => $descriptions,
269
                    )
270
                );
271
            }
272
273 3
            $data[] = $groupData;
274
        }
275
276 3
        $this->loginUser($previousUserId);
277 3
        return $data;
278
    }
279
}
280