Completed
Push — master ( 290d49...5307dc )
by Gaetano
13:54 queued 06:53
created

ObjectStateManager::delete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 14
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 14
loc 14
ccs 7
cts 7
cp 1
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use eZ\Publish\API\Repository\Values\ObjectState\ObjectState;
6
use Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateGroupMatcher;
7
use Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateMatcher;
8
use Kaliop\eZMigrationBundle\API\Collection\ObjectStateCollection;
9
use Kaliop\eZMigrationBundle\API\MigrationGeneratorInterface;
10
11
/**
12
 * Handles object-state migrations.
13
 */
14
class ObjectStateManager extends RepositoryExecutor implements MigrationGeneratorInterface
15
{
16
    /**
17
     * @var array
18
     */
19
    protected $supportedStepTypes = array('object_state');
20
    protected $supportedActions = array('create', 'load', 'update', 'delete');
21
22
    /**
23
     * @var ObjectStateMatcher
24
     */
25
    protected $objectStateMatcher;
26
27
    /**
28
     * @var ObjectStateGroupMatcher
29
     */
30
    protected $objectStateGroupMatcher;
31
32
    /**
33
     * @param ObjectStateMatcher      $objectStateMatcher
34
     * @param ObjectStateGroupMatcher $objectStateGroupMatcher
35
     */
36 80
    public function __construct(ObjectStateMatcher $objectStateMatcher, ObjectStateGroupMatcher $objectStateGroupMatcher)
37
    {
38 80
        $this->objectStateMatcher = $objectStateMatcher;
39 80
        $this->objectStateGroupMatcher = $objectStateGroupMatcher;
40 80
    }
41
42
    /**
43
     * Handles the create step of object state migrations.
44
     *
45
     * @throws \Exception
46
     */
47 1
    protected function create($step)
48
    {
49 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...
50 1
            if (!isset($step->dsl[$key])) {
51 1
                throw new \Exception("The '$key' key is missing in a object state creation definition");
52
            }
53
        }
54
55 1
        if (!count($step->dsl['names'])) {
56
            throw new \Exception('No object state names have been defined. Need to specify at least one to create the state.');
57
        }
58
59 1
        $objectStateService = $this->repository->getObjectStateService();
60
61 1
        $objectStateGroupId = $step->dsl['object_state_group'];
62 1
        $objectStateGroupId = $this->referenceResolver->resolveReference($objectStateGroupId);
63 1
        $objectStateGroup = $this->objectStateGroupMatcher->matchOneByKey($objectStateGroupId);
64
65 1
        $objectStateIdentifier = $this->referenceResolver->resolveReference($step->dsl['identifier']);
66 1
        $objectStateCreateStruct = $objectStateService->newObjectStateCreateStruct($objectStateIdentifier);
67 1
        $objectStateCreateStruct->defaultLanguageCode = $this->getLanguageCode($step); // was: self::DEFAULT_LANGUAGE_CODE;
68
69 1
        foreach ($step->dsl['names'] as $languageCode => $name) {
70 1
            $objectStateCreateStruct->names[$languageCode] = $name;
71
        }
72 1
        if (isset($step->dsl['descriptions'])) {
73 1
            foreach ($step->dsl['descriptions'] as $languageCode => $description) {
74 1
                $objectStateCreateStruct->descriptions[$languageCode] = $description;
75
            }
76
        }
77
78 1
        $objectState = $objectStateService->createObjectState($objectStateGroup, $objectStateCreateStruct);
79
80 1
        $this->setReferences($objectState, $step);
0 ignored issues
show
Documentation introduced by
$objectState is of type object<eZ\Publish\API\Re...bjectState\ObjectState>, 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...
81
82 1
        return $objectState;
83
    }
84
85
    protected function load($step)
86
    {
87
        $stateCollection = $this->matchObjectStates('load', $step);
88
89
        $this->setReferences($stateCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $stateCollection defined by $this->matchObjectStates('load', $step) on line 87 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...
90
91
        return $stateCollection;
92
    }
93
94
    /**
95
     * Handles the update step of object state migrations.
96
     *
97
     * @throws \Exception
98
     */
99 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...
100
    {
101 1
        $stateCollection = $this->matchObjectStates('update', $step);
102
103 1
        if (count($stateCollection) > 1 && array_key_exists('references', $step->dsl)) {
104
            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");
105
        }
106
107 1
        if (count($stateCollection) > 1 && isset($step->dsl['identifier'])) {
108
            throw new \Exception("Can not execute Object State update because multiple states match, and an identifier is specified in the dsl.");
109
        }
110
111 1
        $objectStateService = $this->repository->getObjectStateService();
112
113 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...
114 1
            $objectStateUpdateStruct = $objectStateService->newObjectStateUpdateStruct();
115
116 1
            if (isset($step->dsl['identifier'])) {
117 1
                $objectStateUpdateStruct->identifier = $this->referenceResolver->resolveReference($step->dsl['identifier']);
118
            }
119 1
            if (isset($step->dsl['names'])) {
120
                foreach ($step->dsl['names'] as $name) {
121
                    $objectStateUpdateStruct->names[$name['languageCode']] = $name['name'];
122
                }
123
            }
124 1
            if (isset($step->dsl['descriptions'])) {
125
                foreach ($step->dsl['descriptions'] as $languageCode => $description) {
126
                    $objectStateUpdateStruct->descriptions[$languageCode] = $description;
127
                }
128
            }
129 1
            $state = $objectStateService->updateObjectState($state, $objectStateUpdateStruct);
130
131 1
            $this->setReferences($state, $step);
0 ignored issues
show
Documentation introduced by
$state is of type object<eZ\Publish\API\Re...bjectState\ObjectState>, 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...
132
        }
133
134 1
        return $stateCollection;
135
    }
136
137
    /**
138
     * Handles the deletion step of object state migrations.
139
     */
140 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...
141
    {
142 1
        $stateCollection = $this->matchObjectStates('delete', $step);
143
144 1
        $this->setReferences($stateCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $stateCollection defined by $this->matchObjectStates('delete', $step) on line 142 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...
145
146 1
        $objectStateService = $this->repository->getObjectStateService();
147
148 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...
149 1
            $objectStateService->deleteObjectState($state);
150
        }
151
152 1
        return $stateCollection;
153
    }
154
155
    /**
156
     * @param string $action
157
     * @return ObjectStateCollection
158
     * @throws \Exception
159
     */
160 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...
161
    {
162 1
        if (!isset($step->dsl['match'])) {
163
            throw new \Exception("A match condition is required to $action an object state");
164
        }
165
166
        // convert the references passed in the match
167 1
        $match = $this->resolveReferencesRecursively($step->dsl['match']);
168
169 1
        return $this->objectStateMatcher->match($match);
170
    }
171
172
    /**
173
     * @param ObjectState $objectState
174
     * @param array $references the definitions of the references to set
175
     * @throws \InvalidArgumentException When trying to assign a reference to an unsupported attribute
176
     * @return array key: the reference names, values: the reference values
177
     */
178 1 View Code Duplication
    protected function getReferencesValues($objectState, 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...
179
    {
180 1
        $refs = array();
181
182 1
        foreach ($references as $reference) {
183 1
            switch ($reference['attribute']) {
184 1
                case 'object_state_id':
185 1
                case 'id':
186 1
                    $value = $objectState->id;
187 1
                    break;
188
                case 'priority':
189
                    $value = $objectState->priority;
190
                    break;
191
                default:
192
                    throw new \InvalidArgumentException('Object State Manager does not support setting references for attribute ' . $reference['attribute']);
193
            }
194
195 1
            $refs[$reference['identifier']] = $value;
196
        }
197
198 1
        return $refs;
199
    }
200
201
    /**
202
     * @param array $matchCondition
203
     * @param string $mode
204
     * @param array $context
205
     * @throws \Exception
206
     * @return array
207
     */
208 3
    public function generateMigration(array $matchCondition, $mode, array $context = array())
209
    {
210 3
        $previousUserId = $this->loginUser($this->getAdminUserIdentifierFromContext($context));
211 3
        $objectStateCollection = $this->objectStateMatcher->match($matchCondition);
212 3
        $data = array();
213
214
        /** @var \eZ\Publish\API\Repository\Values\ObjectState\ObjectState $objectState */
215 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...
216
217
            $groupData = array(
218 3
                'type' => reset($this->supportedStepTypes),
219 3
                'mode' => $mode,
220
            );
221
222
            switch ($mode) {
223 3
                case 'create':
224 1
                    $groupData = array_merge(
225 1
                        $groupData,
226
                        array(
227 1
                            'object_state_group' => $objectState->getObjectStateGroup()->identifier,
228 1
                            'identifier' => $objectState->identifier,
229
                        )
230
                    );
231 1
                    break;
232 2
                case 'update':
233 1
                    $groupData = array_merge(
234 1
                        $groupData,
235
                        array(
236
                            'match' => array(
237
                                ObjectStateMatcher::MATCH_OBJECTSTATE_IDENTIFIER =>
238 1
                                    $objectState->getObjectStateGroup()->identifier . '/' . $objectState->identifier
239
                            ),
240 1
                            'identifier' => $objectState->identifier,
241
                        )
242
                    );
243 1
                    break;
244 1
                case 'delete':
245 1
                    $groupData = array_merge(
246 1
                        $groupData,
247
                        array(
248
                            'match' => array(
249
                                ObjectStateMatcher::MATCH_OBJECTSTATE_IDENTIFIER =>
250 1
                                    $objectState->getObjectStateGroup()->identifier . '/' . $objectState->identifier
251
                            )
252
                        )
253
                    );
254 1
                    break;
255
                default:
256
                    throw new \Exception("Executor 'object_state_group' doesn't support mode '$mode'");
257
            }
258
259 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...
260 2
                $names = array();
261 2
                $descriptions = array();
262 2
                foreach($objectState->languageCodes as $languageCode) {
263 2
                    $names[$languageCode] =  $objectState->getName($languageCode);
264
                }
265 2
                foreach($objectState->languageCodes as $languageCode) {
266 2
                    $descriptions[$languageCode] =  $objectState->getDescription($languageCode);
267
                }
268 2
                $groupData = array_merge(
269 2
                    $groupData,
270
                    array(
271 2
                        'names' => $names,
272 2
                        'descriptions' => $descriptions,
273
                    )
274
                );
275
            }
276
277 3
            $data[] = $groupData;
278
        }
279
280 3
        $this->loginUser($previousUserId);
281 3
        return $data;
282
    }
283
}
284