[TASK] Extension manager: default sorting for Extensions
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Domain / Repository / ExtensionRepository.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Domain\Repository;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012-2013 Susanne Moog, <typo3@susannemoog.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26 /**
27 * A repository for extensions
28 *
29 * @author Susanne Moog <typo3@susannemoog.de>
30 */
31 class ExtensionRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
32
33 /**
34 * @var string
35 */
36 const TABLE_NAME = 'tx_extensionmanager_domain_model_extension';
37
38 /**
39 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
40 */
41 protected $databaseConnection;
42
43 /**
44 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
45 * @inject
46 */
47 protected $dataMapper;
48
49 /**
50 * Do not include pid in queries
51 *
52 * @return void
53 */
54 public function initializeObject() {
55 /** @var $defaultQuerySettings \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface */
56 $defaultQuerySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\QuerySettingsInterface');
57 $defaultQuerySettings->setRespectStoragePage(FALSE);
58 $this->setDefaultQuerySettings($defaultQuerySettings);
59 $this->databaseConnection = $GLOBALS['TYPO3_DB'];
60 }
61
62 /**
63 * Count all extensions
64 *
65 * @return integer
66 */
67 public function countAll() {
68 $query = $this->createQuery();
69 $query = $this->addDefaultConstraints($query);
70 return $query->execute()->count();
71 }
72
73 /**
74 * Finds all extensions
75 *
76 * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
77 */
78 public function findAll() {
79 $query = $this->createQuery();
80 $query = $this->addDefaultConstraints($query);
81 $query->setOrderings(
82 array(
83 'lastUpdated' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
84 )
85 );
86 return $query->execute();
87 }
88
89 /**
90 * Find an extension by extension key ordered by version
91 *
92 * @param string $extensionKey
93 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
94 */
95 public function findByExtensionKeyOrderedByVersion($extensionKey) {
96 $query = $this->createQuery();
97 $query->matching($query->logicalAnd($query->equals('extensionKey', $extensionKey), $query->greaterThanOrEqual('reviewState', 0)));
98 $query->setOrderings(array('version' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING));
99 return $query->execute();
100 }
101
102 /**
103 * Find the current version by extension key
104 *
105 * @param string $extensionKey
106 * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
107 */
108 public function findOneByCurrentVersionByExtensionKey($extensionKey) {
109 $query = $this->createQuery();
110 $query->matching(
111 $query->logicalAnd(
112 $query->equals('extensionKey', $extensionKey),
113 $query->greaterThanOrEqual('reviewState', 0),
114 $query->equals('currentVersion', 1)
115 )
116 );
117 $query->setLimit(1);
118 return $query->execute()->getFirst();
119 }
120
121 /**
122 * Find one extension by extension key and version
123 *
124 * @param string $extensionKey
125 * @param string $version (example: 4.3.10)
126 * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
127 */
128 public function findOneByExtensionKeyAndVersion($extensionKey, $version) {
129 $query = $this->createQuery();
130 // Hint: This method must not filter out insecure extensions, if needed,
131 // it should be done on a different level, or with a helper method.
132 $query->matching($query->logicalAnd(
133 $query->equals('extensionKey', $extensionKey),
134 $query->equals('version', $version)
135 ));
136 return $query->setLimit(1)->execute()->getFirst();
137 }
138
139 /**
140 * Find an extension by title, author name or extension key
141 * This is the function used by the TER search. It is using a
142 * scoring for the matches to sort the extension with an
143 * exact key match on top
144 *
145 * @param string $searchString The string to search for extensions
146 * @return mixed
147 */
148 public function findByTitleOrAuthorNameOrExtensionKey($searchString) {
149 $quotedSearchString = $this->databaseConnection->escapeStrForLike($this->databaseConnection->quoteStr($searchString, 'tx_extensionmanager_domain_model_extension'), 'tx_extensionmanager_domain_model_extension');
150 $quotedSearchStringForLike = '\'%' . $quotedSearchString . '%\'';
151 $quotedSearchString = '\'' . $quotedSearchString . '\'';
152 $select = 'tx_extensionmanager_domain_model_extension.*,
153 (
154 (extension_key like ' . $quotedSearchString . ') * 8 +
155 (extension_key like ' . $quotedSearchStringForLike . ') * 4 +
156 (title like ' . $quotedSearchStringForLike . ') * 2 +
157 (author_name like ' . $quotedSearchStringForLike . ')
158 ) as position';
159 $from = 'tx_extensionmanager_domain_model_extension';
160 $where = '(
161 extension_key = ' . $quotedSearchString . '
162 OR
163 extension_key LIKE ' . $quotedSearchStringForLike . '
164 OR
165 title LIKE ' . $quotedSearchStringForLike . '
166 OR
167 description LIKE ' . $quotedSearchStringForLike . '
168 OR
169 author_name LIKE ' . $quotedSearchStringForLike . '
170 )
171 AND current_version=1 AND review_state >= 0
172 HAVING position > 0';
173 $order = 'position desc';
174 $result = $this->databaseConnection->exec_SELECTgetRows($select, $from, $where, '', $order);
175 return $this->dataMapper->map('TYPO3\\CMS\\Extensionmanager\\Domain\\Model\\Extension', $result);
176 }
177
178 /**
179 * Find an extension between a certain version range ordered by version number
180 *
181 * @param string $extensionKey
182 * @param integer $lowestVersion
183 * @param integer $highestVersion
184 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
185 */
186 public function findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $lowestVersion = 0, $highestVersion = 0) {
187 $query = $this->createQuery();
188 $constraint = NULL;
189 if ($lowestVersion !== 0 && $highestVersion !== 0) {
190 $constraint = $query->logicalAnd($query->lessThanOrEqual('integerVersion', $highestVersion), $query->greaterThanOrEqual('integerVersion', $lowestVersion), $query->equals('extensionKey', $extensionKey));
191 } elseif ($lowestVersion === 0 && $highestVersion !== 0) {
192 $constraint = $query->logicalAnd($query->lessThanOrEqual('integerVersion', $highestVersion), $query->equals('extensionKey', $extensionKey));
193 } elseif ($lowestVersion !== 0 && $highestVersion === 0) {
194 $constraint = $query->logicalAnd($query->greaterThanOrEqual('integerVersion', $lowestVersion), $query->equals('extensionKey', $extensionKey));
195 } elseif ($lowestVersion === 0 && $highestVersion === 0) {
196 $constraint = $query->equals('extensionKey', $extensionKey);
197 }
198 if ($constraint) {
199 $query->matching($query->logicalAnd($constraint, $query->greaterThanOrEqual('reviewState', 0)));
200 }
201 $query->setOrderings(array(
202 'integerVersion' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
203 ));
204 return $query->execute();
205 }
206
207 /**
208 * Finds all extensions with category "distribution" not published by the TYPO3 CMS Team
209 *
210 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
211 */
212 public function findAllCommunityDistributions() {
213 $query = $this->createQuery();
214 $query->matching(
215 $query->logicalAnd(
216 $query->equals('category', \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY),
217 $query->equals('currentVersion', 1),
218 $query->logicalNot($query->equals('ownerusername', 'typo3v4'))
219 )
220 );
221
222 $query->setOrderings(array(
223 'alldownloadcounter' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
224 ));
225
226 return $query->execute();
227 }
228
229 /**
230 * Finds all extensions with category "distribution" that are published by the TYPO3 CMS Team
231 *
232 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
233 */
234 public function findAllOfficialDistributions() {
235 $query = $this->createQuery();
236 $query->matching(
237 $query->logicalAnd(
238 $query->equals('category', \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY),
239 $query->equals('currentVersion', 1),
240 $query->equals('ownerusername', 'typo3v4')
241 )
242 );
243
244 $query->setOrderings(array(
245 'alldownloadcounter' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
246 ));
247
248 return $query->execute();
249 }
250
251 /**
252 * Count extensions with a certain key between a given version range
253 *
254 * @param string $extensionKey
255 * @param integer $lowestVersion
256 * @param integer $highestVersion
257 * @return integer
258 */
259 public function countByVersionRangeAndExtensionKey($extensionKey, $lowestVersion = 0, $highestVersion = 0) {
260 return $this->findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $lowestVersion, $highestVersion)->count();
261 }
262
263 /**
264 * Find highest version available of an extension
265 *
266 * @param string $extensionKey
267 * @return \TYPO3\CMS\Extensionmanager\Domain\Model\Extension
268 */
269 public function findHighestAvailableVersion($extensionKey) {
270 $query = $this->createQuery();
271 $query->matching($query->logicalAnd($query->equals('extensionKey', $extensionKey), $query->greaterThanOrEqual('reviewState', 0)));
272 $query->setOrderings(array(
273 'integerVersion' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
274 ));
275 return $query->setLimit(1)->execute()->getFirst();
276 }
277
278 /**
279 * Updates the current_version field after update.
280 *
281 * @param int $repositoryUid
282 * @return int
283 */
284 public function insertLastVersion($repositoryUid = 1) {
285 $this->markExtensionWithMaximumVersionAsCurrent($repositoryUid);
286
287 return $this->getNumberOfCurrentExtensions();
288 }
289
290 /**
291 * Sets current_version = 1 for all extensions where the extension version is maximal.
292 *
293 * For performance reasons, the "native" TYPO3_DB is used here directly.
294 *
295 * @param int $repositoryUid
296 * @return void
297 */
298 protected function markExtensionWithMaximumVersionAsCurrent($repositoryUid) {
299 $uidsOfCurrentVersion = $this->fetchMaximalVersionsForAllExtensions($repositoryUid);
300
301 $this->databaseConnection->exec_UPDATEquery(
302 self::TABLE_NAME,
303 'uid IN (' . implode(',', $uidsOfCurrentVersion) . ')',
304 array(
305 'current_version' => 1,
306 )
307 );
308 }
309
310 /**
311 * Fetches the UIDs of all maximal versions for all extensions.
312 * This is done by doing a subselect in the WHERE clause to get all
313 * max versions and then the UID of that record in the outer select.
314 *
315 * @param int $repositoryUid
316 * @return array
317 */
318 protected function fetchMaximalVersionsForAllExtensions($repositoryUid) {
319 $extensionUids = $this->databaseConnection->exec_SELECTgetRows(
320 'a.uid AS uid',
321 self::TABLE_NAME . ' a',
322 'integer_version=(' .
323 $this->databaseConnection->SELECTquery(
324 'MAX(integer_version)',
325 self::TABLE_NAME . ' b',
326 'b.repository=' . (int)$repositoryUid . ' AND a.extension_key=b.extension_key'
327 ) .
328 ') AND repository=' . (int)$repositoryUid,
329 '', '', '', 'uid'
330 );
331 return array_keys($extensionUids);
332 }
333
334 /**
335 * Returns the number of extensions that are current.
336 *
337 * @return int
338 */
339 protected function getNumberOfCurrentExtensions() {
340 return $this->databaseConnection->exec_SELECTcountRows(
341 '*',
342 self::TABLE_NAME,
343 'current_version = 1'
344 );
345 }
346
347 /**
348 * Adds default constraints to the query - in this case it
349 * enables us to always just search for the latest version of an extension
350 *
351 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Query $query the query to adjust
352 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Query
353 */
354 protected function addDefaultConstraints(\TYPO3\CMS\Extbase\Persistence\Generic\Query $query) {
355 if ($query->getConstraint()) {
356 $query->matching($query->logicalAnd(
357 $query->getConstraint(),
358 $query->equals('current_version', TRUE),
359 $query->greaterThanOrEqual('reviewState', 0)
360 ));
361 } else {
362 $query->matching($query->logicalAnd(
363 $query->equals('current_version', TRUE),
364 $query->greaterThanOrEqual('reviewState', 0)
365 ));
366 }
367 return $query;
368 }
369 }