kaliop-uk /
ezmigrationbundle
| 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
|
|||
| 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
|
|||
| 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 |
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.