Issues (225)

Core/Matcher/ContentVersionMatcher.php (2 issues)

1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Matcher;
4
5
use eZ\Publish\API\Repository\Exceptions\UnauthorizedException ;
6
use eZ\Publish\API\Repository\Repository;
7
use eZ\Publish\API\Repository\Values\Content\Content;
8
use eZ\Publish\API\Repository\Values\Content\VersionInfo;
9
use Kaliop\eZMigrationBundle\API\MatcherInterface;
10
use Kaliop\eZMigrationBundle\API\Collection\VersionInfoCollection;
11
use Kaliop\eZMigrationBundle\API\Exception\InvalidMatchResultsNumberException;
12
use Kaliop\eZMigrationBundle\API\Exception\InvalidMatchConditionsException;
13
14
class ContentVersionMatcher extends RepositoryMatcher implements MatcherInterface
15
{
16
    const MATCH_STATUS_DRAFT = 'draft';
17
    const MATCH_STATUS_PUBLISHED = 'published';
18
    const MATCH_STATUS_ARCHIVED = 'archived';
19
20
    const MATCH_STATUS = 'version_status';
21
    const MATCH_VERSION = 'version';
22
23
    const STATUS_MAP = array(
24
        self::MATCH_STATUS_DRAFT => VersionInfo::STATUS_DRAFT,
25
        self::MATCH_STATUS_PUBLISHED => VersionInfo::STATUS_PUBLISHED,
26
        self::MATCH_STATUS_ARCHIVED => VersionInfo::STATUS_ARCHIVED
27
    );
28
29
    protected $allowedConditions = array(
30
        self::MATCH_ALL, self::MATCH_AND, self::MATCH_OR, self::MATCH_NOT,
31
        self::MATCH_STATUS, self::MATCH_VERSION,
32
        // aliases
33
        'status'
34
    );
35
    protected $returns = 'VersionInfo';
36
37
    protected $contentMatcher;
38
39 149
    public function __construct(Repository $repository, MatcherInterface $contentMatcher)
40
    {
41 149
        parent::__construct($repository);
42 149
        $this->contentMatcher = $contentMatcher;
43 149
    }
44
45
    /**
46
     * @param array $contentConditions
47
     * @param array $versionConditions
48
     * @param array $sort
49
     * @param int $offset
50
     * @param int $limit
51
     * @param bool $tolerateMisses
52
     * @return VersionInfoCollection
53
     * @throws InvalidMatchConditionsException
54
     */
55 1
    public function match(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0, $limit = 0, $tolerateMisses = false)
56
    {
57 1
        $versions = array();
58
59 1
        $contentCollection = $this->contentMatcher->match($contentConditions, $sort, $offset, $limit, $tolerateMisses);
0 ignored issues
show
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

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

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...
60 1
        foreach ($contentCollection as $content) {
61 1
            $versions = array_merge($versions, $this->matchContentVersions($versionConditions, $content));
62
        }
63
64 1
        return new VersionInfoCollection($versions);
65
    }
66
67
    /**
68
     * Like match, but will throw an exception if there are 0 or more than 1 items matching
69
     *
70
     * @param array $contentConditions
71
     * @param array $versionConditions
72
     * @param array $sort
73
     * @param int $offset
74
     * @return mixed
75
     * @throws InvalidMatchConditionsException
76
     * @throws InvalidMatchResultsNumberException
77
     */
78
    public function matchOne(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0)
79
    {
80
        $results = $this->match($contentConditions, $versionConditions, $sort, $offset, 2);
81
        $count = count($results);
82
        if ($count !== 1) {
83
            throw new InvalidMatchResultsNumberException("Found $count " . $this->returns . " when expected exactly only one to match the conditions");
84
        }
85
        return reset($results);
86
    }
87
88
    /**
89
     * @param array $versionConditions
90
     * @param Content $content
91
     * @return VersionInfo[] key: obj_id/version_no
92
     * @throws InvalidMatchConditionsException
93
     */
94 1
    public function matchContentVersions(array $versionConditions, Content $content)
95
    {
96 1
        $this->validateConditions($versionConditions);
97
98 1
        foreach ($versionConditions as $key => $values) {
99
100 1
            if (!is_array($values)) {
101 1
                $values = array($values);
102
            }
103
104
            switch ($key) {
105 1
                case 'status':
106 1
                case self::MATCH_STATUS:
107
                    return $this->findContentVersionsByStatus($content, $values);
108
109 1
                case self::MATCH_VERSION:
110 1
                    return $this->findContentVersionsByVersionNo($content, $values);
111
112
                case self::MATCH_ALL:
113
                    return $this->findAllContentVersions($content);
114
115
                case self::MATCH_AND:
116
                    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...
117
118
                case self::MATCH_OR:
119
                    return $this->matchOr($values, $content);
120
121
                case self::MATCH_NOT:
122
                    return array_diff_key($this->findAllContentVersions($content), $this->matchContentVersions($values, $content));
123
            }
124
        }
125
    }
126
127
    protected function matchAnd($conditionsArray, $content = null)
128
    {
129
        /// @todo introduce proper re-validation of all child conditions
130
        if (!is_array($conditionsArray) || !count($conditionsArray)) {
131
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because no matching conditions found for 'and' clause.");
132
        }
133
134
        if (is_null($content)) {
135
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because there was no content to match for 'and' clause.");
136
        }
137
138
        $results = array();
139
        foreach ($conditionsArray as $conditions) {
140
            $out = $this->matchContentVersions($conditions, $content);
141
            if (!isset($results)) {
142
                $results = $out;
143
            } else {
144
                $results = array_intersect_key($results, $out);
145
            }
146
        }
147
148
        return $results;
149
    }
150
151
    protected function matchOr($conditionsArray, $content = null)
152
    {
153
        /// @todo introduce proper re-validation of all child conditions
154
        if (!is_array($conditionsArray) || !count($conditionsArray)) {
155
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because no matching conditions found for 'or' clause.");
156
        }
157
158
        if (is_null($content)) {
159
            throw new InvalidMatchConditionsException($this->returns . " can not be matched because there was no content to match for 'or' clause.");
160
        }
161
162
        $results = array();
163
        foreach ($conditionsArray as $conditions) {
164
            $out = $this->matchContentVersions($conditions, $content);
165
            $results = array_replace($results, $out);
166
        }
167
168
        return $results;
169
    }
170
171
    /**
172
     * NB: does not throw when matching no version
173
     * @param Content $content
174
     * @param string[] $values
175
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
176
     * @throws UnauthorizedException
177
     */
178
    protected function findContentVersionsByStatus(Content $content, array $values)
179
    {
180
        $versions = array();
181
        foreach ($this->findAllContentVersions($content) as $versionKey => $versionInfo) {
182
            foreach ($values as $acceptedStatus) {
183
                if ($versionInfo->status == self::STATUS_MAP[$acceptedStatus]) {
184
                    $versions[$versionKey] = $versionInfo;
185
                    break;
186
                }
187
            }
188
        }
189
        return $versions;
190
    }
191
192
    /**
193
     * NB: does not throw when matching no version
194
     * @param Content $content
195
     * @param int[] $values
196
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
197
     * @throws UnauthorizedException
198
     */
199 1
    protected function findContentVersionsByVersionNo(Content $content, array $values)
200
    {
201 1
        $versions = array();
202 1
        $contentVersions = $this->findAllContentVersions($content);
203 1
        $contentVersionsCount = count($contentVersions);
204 1
        $i = 0;
205 1
        foreach ($contentVersions as $versionKey => $versionInfo) {
206 1
            foreach ($values as $acceptedVersionNo) {
207 1
                if ($acceptedVersionNo > 0) {
208 1
                    if ($acceptedVersionNo == $versionInfo->versionNo) {
209 1
                        $versions[$versionKey] = $versionInfo;
210 1
                        break;
211
                    }
212
                } else {
213
                    // negative $acceptedVersionNo means 'leave the last X versions', eg: -1 = leave the last version
214 1
                    if ($i < $contentVersionsCount + $acceptedVersionNo)  {
215 1
                        $versions[$versionKey] = $versionInfo;
216 1
                        break;
217
218
                    }
219
                }
220
            }
221 1
            $i++;
222
        }
223 1
        return $versions;
224
    }
225
226
    /**
227
     * @param Content $content
228
     * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no.
229
     * @throws UnauthorizedException
230
     */
231 1
    protected function findAllContentVersions(Content $content)
232
    {
233 1
        $contentVersions = $this->repository->getContentService()->loadVersions($content->contentInfo);
234
        // different eZ kernels apparently sort versions in different order...
235 1
        $sortedVersions = array();
236 1
        foreach ($contentVersions as $versionInfo) {
237 1
            $sortedVersions[$content->contentInfo->id . '/' . $versionInfo->versionNo] = $versionInfo;
238
        }
239 1
        ksort($sortedVersions);
240
241 1
        return $sortedVersions;
242
    }
243
}
244