Completed
Branch master (e35419)
by Gaetano
06:40
created

ContentVersionMatcher::matchOr()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 2
dl 0
loc 18
ccs 0
cts 10
cp 0
crap 30
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Matcher;
4
5
use eZ\Publish\API\Repository\Repository;
6
use eZ\Publish\API\Repository\Values\Content\Content;
7
use \eZ\Publish\API\Repository\Values\Content\VersionInfo;
8
use Kaliop\eZMigrationBundle\API\MatcherInterface;
9
use Kaliop\eZMigrationBundle\API\Collection\VersionInfoCollection;
10
use Kaliop\eZMigrationBundle\API\Exception\InvalidMatchResultsNumberException;
11
use Kaliop\eZMigrationBundle\API\Exception\InvalidMatchConditionsException;
12
13
class ContentVersionMatcher extends RepositoryMatcher implements MatcherInterface
14
{
15
    const MATCH_STATUS_DRAFT = 'draft';
16
    const MATCH_STATUS_PUBLISHED = 'published';
17
    const MATCH_STATUS_ARCHIVED = 'archived';
18
19
    const MATCH_STATUS = 'version_status';
20
    const MATCH_VERSION = 'version';
21
22
    const STATUS_MAP = array(
23
        self::MATCH_STATUS_DRAFT => VersionInfo::STATUS_DRAFT,
24
        self::MATCH_STATUS_PUBLISHED => VersionInfo::STATUS_PUBLISHED,
25
        self::MATCH_STATUS_ARCHIVED => VersionInfo::STATUS_ARCHIVED
26
    );
27
28
    protected $allowedConditions = array(
29
        self::MATCH_ALL, self::MATCH_AND, self::MATCH_OR, self::MATCH_NOT,
30
        self::MATCH_STATUS, self::MATCH_VERSION,
31
        // aliases
32
        'status'
33
    );
34
    protected $returns = 'VersionInfo';
35
36
    protected $contentMatcher;
37
38 80
    public function __construct(Repository $repository, MatcherInterface $contentMatcher)
39
    {
40 80
        $this->repository = $repository;
41 80
        $this->contentMatcher = $contentMatcher;
42 80
    }
43
44 1
    public function match(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0, $limit = 0)
45
    {
46 1
        $versions = array();
47
48 1
        $contentCollection = $this->contentMatcher->match($contentConditions, $sort, $offset, $limit);
0 ignored issues
show
Unused Code introduced by
The call to Kaliop\eZMigrationBundle...tcherInterface::match() has too many arguments starting with $sort. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

48
        /** @scrutinizer ignore-call */ 
49
        $contentCollection = $this->contentMatcher->match($contentConditions, $sort, $offset, $limit);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
49 1
        foreach($contentCollection as $content) {
50 1
            $versions = array_merge($versions, $this->matchContentVersions($versionConditions, $content));
51
        }
52
53 1
        return new VersionInfoCollection($versions);
54
    }
55
56
    /**
57
     * Like match, but will throw an exception if there are 0 or more than 1 items matching
58
     *
59
     * @param array $contentConditions
60
     * @param array $versionConditions
61
     * @param array $sort
62
     * @param int $offset
63
     * @return mixed
64
     * @throws InvalidMatchConditionsException
65
     * @throws InvalidMatchResultsNumberException
66
     */
67
    public function matchOne(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0)
68
    {
69
        $results = $this->match($contentConditions, $versionConditions, $sort, $offset, 2);
70
        $count = count($results);
71
        if ($count !== 1) {
72
            throw new InvalidMatchResultsNumberException("Found $count " . $this->returns . " when expected exactly only one to match the conditions");
73
        }
74
        return reset($results);
0 ignored issues
show
Bug introduced by
$results of type Kaliop\eZMigrationBundle...n\VersionInfoCollection is incompatible with the type array expected by parameter $array of reset(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

74
        return reset(/** @scrutinizer ignore-type */ $results);
Loading history...
75
    }
76
77
    /**
78
     * @param array $versionConditions
79
     * @param Content $content
80
     * @return VersionInfo[] key: obj_id/version_no
81
     * @throws InvalidMatchConditionsException
82
     */
83 1
    public function matchContentVersions(array $versionConditions, Content $content)
84
    {
85 1
        $this->validateConditions($versionConditions);
86
87 1
        foreach ($versionConditions as $key => $values) {
88
89 1
            if (!is_array($values)) {
90 1
                $values = array($values);
91
            }
92
93
            switch ($key) {
94 1
                case 'status':
95 1
                case self::MATCH_STATUS:
96
                    return $this->findContentVersionsByStatus($content, $values);
97
98 1
                case self::MATCH_VERSION:
99 1
                    return $this->findContentVersionsByVersionNo($content, $values);
100
101
                case self::MATCH_ALL:
102
                    return $this->findAllContentVersions($content);
103
104
                case self::MATCH_AND:
105
                    return $this->matchAnd($values, $content);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->matchAnd($values, $content) also could return the type mixed which is incompatible with the documented return type eZ\Publish\API\Repositor...s\Content\VersionInfo[].
Loading history...
106
107
                case self::MATCH_OR:
108
                    return $this->matchOr($values, $content);
109
110
                case self::MATCH_NOT:
111
                    return array_diff_key($this->findAllContentVersions($content), $this->matchContentVersions($values, $content));
112
            }
113
        }
114
    }
115
116
    protected function matchAnd($conditionsArray, $content = null)
117
    {
118
        /// @todo introduce proper re-validation of all child conditions
119
        if (!is_array($conditionsArray) || !count($conditionsArray)) {
120
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because no matching conditions found for 'and' clause.");
121
        }
122
123
        if (is_null($content)) {
124
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because there was no content to match for 'and' clause.");
125
        }
126
127
        $results = array();
128
        foreach ($conditionsArray as $conditions) {
129
            $out = $this->matchContentVersions($conditions, $content);
130
            if (!isset($results)) {
131
                $results = $out;
132
            } else {
133
                $results = array_intersect_key($results, $out);
134
            }
135
        }
136
137
        return $results;
138
    }
139
140
    protected function matchOr($conditionsArray, $content = null)
141
    {
142
        /// @todo introduce proper re-validation of all child conditions
143
        if (!is_array($conditionsArray) || !count($conditionsArray)) {
144
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because no matching conditions found for 'or' clause.");
145
        }
146
147
        if (is_null($content)) {
148
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because there was no content to match for 'or' clause.");
149
        }
150
151
        $results = array();
152
        foreach ($conditionsArray as $conditions) {
153
            $out = $this->matchContentVersions($conditions, $content);
154
            $results = array_replace($results, $out);
155
        }
156
157
        return $results;
158
    }
159
160
    /**
161
     * @param Content $content
162
     * @param string[] $values
163
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
164
     */
165
    protected function findContentVersionsByStatus(Content $content, array $values)
166
    {
167
        $versions = array();
168
        foreach ($this->findAllContentVersions($content) as $versionKey => $versionInfo) {
169
            foreach($values as $acceptedStatus) {
170
                if ($versionInfo->status == self::STATUS_MAP[$acceptedStatus]) {
171
                    $versions[$versionKey] = $versionInfo;
172
                    break;
173
                }
174
            }
175
        }
176
        return $versions;
177
    }
178
179
    /**
180
     * @param Content $content
181
     * @param int[] $values
182
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
183
     */
184 1
    protected function findContentVersionsByVersionNo(Content $content, array $values)
185
    {
186 1
        $versions = array();
187 1
        $contentVersions = $this->findAllContentVersions($content);
188 1
        $contentVersionsCount = count($contentVersions);
189 1
        $i = 0;
190 1
        foreach ($contentVersions as $versionKey => $versionInfo) {
191 1
            foreach($values as $acceptedVersionNo) {
192 1
                if ($acceptedVersionNo > 0 ) {
193 1
                    if ($acceptedVersionNo == $versionInfo->versionNo) {
194 1
                        $versions[$versionKey] = $versionInfo;
195 1
                        break;
196
                    }
197
                } else {
198
                    // negative $acceptedVersionNo means 'leave the last X versions', eg: -1 = leave the last version
199 1
                    if ($i < $contentVersionsCount + $acceptedVersionNo)  {
200 1
                        $versions[$versionKey] = $versionInfo;
201 1
                        break;
202
203
                    }
204
                }
205
            }
206 1
            $i++;
207
        }
208 1
        return $versions;
209
    }
210
211
    /**
212
     * @param Content $content
213
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
214
     */
215 1
    protected function findAllContentVersions(Content $content)
216
    {
217 1
        $contentVersions = $this->repository->getContentService()->loadVersions($content->contentInfo);
218
        // different eZ kernels apparently sort versions in different order...
219 1
        $sortedVersions = array();
220 1
        foreach($contentVersions as $versionInfo) {
221 1
            $sortedVersions[$content->contentInfo->id . '/' . $versionInfo->versionNo] = $versionInfo;
222
        }
223 1
        ksort($sortedVersions);
224
225 1
        return $sortedVersions;
226
    }
227
}
228