Completed
Push — master ( b2c38b...f910d1 )
by Gaetano
07:22
created

LocationMatcher::matchLocation()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6.0493

Importance

Changes 0
Metric Value
dl 0
loc 24
c 0
b 0
f 0
ccs 8
cts 9
cp 0.8889
rs 8.9137
cc 6
nc 17
nop 4
crap 6.0493
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Matcher;
4
5
use eZ\Publish\API\Repository\Values\Content\Query;
6
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
7
use eZ\Publish\API\Repository\Values\Content\Location;
8
use Kaliop\eZMigrationBundle\API\Collection\LocationCollection;
9
use Kaliop\eZMigrationBundle\API\SortingMatcherInterface;
10
11
class LocationMatcher extends QueryBasedMatcher implements SortingMatcherInterface
12
{
13
    use FlexibleKeyMatcherTrait;
14
15
    const MATCH_DEPTH = 'depth';
16
    const MATCH_IS_MAIN_LOCATION = 'is_main_location';
17
    const MATCH_PRIORITY = 'priority';
18
19
    protected $allowedConditions = array(
20
        self::MATCH_AND, self::MATCH_OR, self::MATCH_NOT,
21
        self::MATCH_CONTENT_ID, self::MATCH_LOCATION_ID, self::MATCH_CONTENT_REMOTE_ID, self::MATCH_LOCATION_REMOTE_ID,
22
        self::MATCH_ATTRIBUTE, self::MATCH_CONTENT_TYPE_ID, self::MATCH_CONTENT_TYPE_IDENTIFIER, self::MATCH_GROUP,
23
        self::MATCH_CREATION_DATE, self::MATCH_MODIFICATION_DATE, self::MATCH_OBJECT_STATE, self::MATCH_OWNER,
24
        self::MATCH_PARENT_LOCATION_ID, self::MATCH_PARENT_LOCATION_REMOTE_ID, self::MATCH_SECTION, self::MATCH_SUBTREE,
25
        self::MATCH_VISIBILITY,
26
        // aliases
27
        'content_type', 'content_type_id', 'content_type_identifier',
28
        // location-only
29
        self::MATCH_DEPTH, self::MATCH_IS_MAIN_LOCATION, self::MATCH_PRIORITY,
30
    );
31
    protected $returns = 'Location';
32
33
    /**
34
     * @param array $conditions key: condition, value: int / string / int[] / string[]
35
     * @param array $sort
36 12
     * @param int $offset
37
     * @param int $limit
38 12
     * @return LocationCollection
39
     */
40
    public function match(array $conditions, array $sort = array(), $offset = 0, $limit = 0)
41
    {
42
        return $this->matchLocation($conditions, $sort, $offset, $limit);
43
    }
44
45 2 View Code Duplication
    public function matchOne(array $conditions, array $sort = array(), $offset = 0, $limit = 0)
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...
46
    {
47 2
        $results = $this->match($conditions, $sort, $offset, $limit);
48
        $count = count($results);
49 2
        if ($count !== 1) {
50
            throw new \Exception("Found $count " . $this->returns . " when expected exactly only one to match the conditions");
51 2
        }
52 2
        return reset($results);
53 2
    }
54 2
55 2
    /**
56
     * @param array $conditions key: condition, value: value: int / string / int[] / string[]
57 2
     * @param array $sort
58 2
     * @param int $offset
59 2
     * @param int $limit
60
     * @return LocationCollection
61
     */
62 2
    public function matchLocation(array $conditions, array $sort = array(), $offset = 0, $limit = 0)
63
    {
64
        $this->validateConditions($conditions);
65
66
        foreach ($conditions as $key => $values) {
67
68
            $query = new LocationQuery();
69
            $query->limit = $limit != 0 ? $limit : self::INT_MAX_16BIT;
70
            $query->offset = $offset;
71 12
            if (!empty($sort)) {
72
                $query->sortClauses = $this->getSortClauses($sort);
73 12
            }
74 12
            if (isset($query->performCount)) $query->performCount = false;
75
            $query->filter = $this->getQueryCriterion($key, $values);
76 1
            $results = $this->repository->getSearchService()->findLocations($query);
77
78
            $locations = [];
79 2
            foreach ($results->searchHits as $result) {
80
                $locations[$result->valueObject->id] = $result->valueObject;
81 2
            }
82 2
83
            return new LocationCollection($locations);
84
        }
85
    }
86 2
87 1
    /**
88 1
     * When matching by key, we accept location Id and remote Id only
89 1
     * @param int|string $key
90
     * @return array
91
     */
92 1
    protected function getConditionsFromKey($key)
93
    {
94 2
        if (is_int($key) || ctype_digit($key)) {
95 2
            return array(self::MATCH_LOCATION_ID => $key);
96
        }
97
        return array(self::MATCH_LOCATION_REMOTE_ID => $key);
98
    }
99
100
    protected function getQueryCriterion($key, $values)
101
    {
102
        if (!is_array($values)) {
103
            $values = array($values);
104 2
        }
105 1
106 1
        switch ($key) {
107 1 View Code Duplication
            case self::MATCH_DEPTH:
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...
108
                $match = reset($values);
109
                $operator = key($values);
110 1
                if (!isset(self::$operatorsMap[$operator])) {
111
                    throw new \Exception("Can not use '$operator' as comparison operator for depth");
112
                }
113 2
                return new Query\Criterion\Location\Depth(self::$operatorsMap[$operator], $match);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \eZ\Publish\A...ap[$operator], $match); (eZ\Publish\API\Repositor...riterion\Location\Depth) is incompatible with the return type of the parent method Kaliop\eZMigrationBundle...cher::getQueryCriterion of type eZ\Publish\API\Repositor...ry\Criterion\LogicalNot.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
114
115
            case self::MATCH_IS_MAIN_LOCATION:
116
            case 'is_main':
117
                /// @todo error/warning if there is more than 1 value...
118
                $value = reset($values);
119
                if ($value) {
120
                    return new Query\Criterion\Location\IsMainLocation(Query\Criterion\Location\IsMainLocation::MAIN);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \eZ\Publish\A...\IsMainLocation::MAIN); (eZ\Publish\API\Repositor...Location\IsMainLocation) is incompatible with the return type of the parent method Kaliop\eZMigrationBundle...cher::getQueryCriterion of type eZ\Publish\API\Repositor...ry\Criterion\LogicalNot.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
121
                } else {
122
                    return new Query\Criterion\Location\IsMainLocation(Query\Criterion\Location\IsMainLocation::NOT_MAIN);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \eZ\Publish\A...ainLocation::NOT_MAIN); (eZ\Publish\API\Repositor...Location\IsMainLocation) is incompatible with the return type of the parent method Kaliop\eZMigrationBundle...cher::getQueryCriterion of type eZ\Publish\API\Repositor...ry\Criterion\LogicalNot.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
123
                }
124
125 View Code Duplication
            case self::MATCH_PRIORITY:
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...
126
                $match = reset($values);
127
                $operator = key($values);
128
                if (!isset(self::$operatorsMap[$operator])) {
129
                    throw new \Exception("Can not use '$operator' as comparison operator for depth");
130
                }
131
                return new Query\Criterion\Location\Priority(self::$operatorsMap[$operator], $match);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \eZ\Publish\A...ap[$operator], $match); (eZ\Publish\API\Repositor...erion\Location\Priority) is incompatible with the return type of the parent method Kaliop\eZMigrationBundle...cher::getQueryCriterion of type eZ\Publish\API\Repositor...ry\Criterion\LogicalNot.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
132
        }
133
134
        return parent::getQueryCriterion($key, $values);
135
    }
136
137
    /**
138
     * Returns all locations of a set of objects
139
     *
140
     * @param int[] $contentIds
141
     * @return Location[]
142
     * @deprecated
143
     */
144 View Code Duplication
    protected function findLocationsByContentIds(array $contentIds)
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...
145
    {
146
        $locations = [];
147
148
        foreach ($contentIds as $contentId) {
149
            $content = $this->repository->getContentService()->loadContent($contentId);
150
            foreach($this->repository->getLocationService()->loadLocations($content->contentInfo) as $location) {
151
                $locations[$location->id] = $location;
152
            }
153
        }
154
155
        return $locations;
156
    }
157
158
    /**
159
     * Returns all locations of a set of objects
160
     *
161
     * @param int[] $remoteContentIds
162
     * @return Location[]
163
     * @deprecated
164
     */
165 View Code Duplication
    protected function findLocationsByContentRemoteIds(array $remoteContentIds)
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
        $locations = [];
168
169
        foreach ($remoteContentIds as $remoteContentId) {
170
            $content = $this->repository->getContentService()->loadContentByRemoteId($remoteContentId);
171
            foreach($this->repository->getLocationService()->loadLocations($content->contentInfo) as $location) {
172
                $locations[$location->id] = $location;
173
            }
174
        }
175
176
        return $locations;
177
    }
178
179
    /**
180
     * @param int[] $locationIds
181
     * @return Location[]
182
     * @deprecated
183
     */
184
    protected function findLocationsByLocationIds(array $locationIds)
185
    {
186
        $locations = [];
187
188
        foreach ($locationIds as $locationId) {
189
            $locations[$locationId] = $this->repository->getLocationService()->loadLocation($locationId);
190
        }
191
192
        return $locations;
193
    }
194
195
    /**
196
     * @param int[] $locationRemoteIds
197
     * @return Location[]
198
     * @deprecated
199
     */
200
    protected function findLocationsByLocationRemoteIds($locationRemoteIds)
201
    {
202
        $locations = [];
203
204
        foreach ($locationRemoteIds as $locationRemoteId) {
205
            $location = $this->repository->getLocationService()->loadLocationByRemoteId($locationRemoteId);
206
            $locations[$location->id] = $location;
207
        }
208
209
        return $locations;
210
    }
211
212
    /**
213
     * @param int[] $parentLocationIds
214
     * @return Location[]
215
     * @deprecated
216
     */
217 View Code Duplication
    protected function findLocationsByParentLocationIds($parentLocationIds)
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...
218
    {
219
        $query = new LocationQuery();
220
        $query->limit = self::INT_MAX_16BIT;
221
        if (isset($query->performCount)) $query->performCount = false;
222
        $query->filter = new Query\Criterion\ParentLocationId($parentLocationIds);
223
224
        $results = $this->repository->getSearchService()->findLocations($query);
225
226
        $locations = [];
227
228
        foreach ($results->searchHits as $result) {
229
            $locations[$result->valueObject->id] = $result->valueObject;
230
        }
231
232
        return $locations;
233
    }
234
235
    /**
236
     * @param int[] $parentLocationRemoteIds
237
     * @return Location[]
238
     * @deprecated
239
     */
240 View Code Duplication
    protected function findLocationsByParentLocationRemoteIds($parentLocationRemoteIds)
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...
241
    {
242
        $locationIds = [];
243
244
        foreach ($parentLocationRemoteIds as $parentLocationRemoteId) {
245
            $location = $this->repository->getLocationService()->loadLocationByRemoteId($parentLocationRemoteId);
246
            $locationIds[$location->id] = $location->id;
247
        }
248
249
        return $this->findLocationsByParentLocationIds($locationIds);
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...nsByParentLocationIds() has been deprecated.

This method has been deprecated.

Loading history...
250
    }
251
}
252