[TASK] Deprecate unused LocalizationRepository methods
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Domain / Repository / Localization / LocalizationRepository.php
1 <?php
2 namespace TYPO3\CMS\Backend\Domain\Repository\Localization;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Database\Connection;
19 use TYPO3\CMS\Core\Database\ConnectionPool;
20 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
21 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
22 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24
25 /**
26 * Repository for record localizations
27 */
28 class LocalizationRepository
29 {
30 /**
31 * Fetch the language from which the records of a colPos in a certain language were initially localized
32 *
33 * @param int $pageId
34 * @param int $colPos
35 * @param int $localizedLanguage
36 * @return array|false
37 */
38 public function fetchOriginLanguage($pageId, $colPos, $localizedLanguage)
39 {
40 $queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
41
42 $constraints = [
43 $queryBuilder->expr()->eq(
44 'tt_content.colPos',
45 $queryBuilder->createNamedParameter($colPos, \PDO::PARAM_INT)
46 ),
47 $queryBuilder->expr()->eq(
48 'tt_content.pid',
49 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
50 ),
51 $queryBuilder->expr()->eq(
52 'tt_content.sys_language_uid',
53 $queryBuilder->createNamedParameter($localizedLanguage, \PDO::PARAM_INT)
54 ),
55 ];
56 $constraints += $this->getAllowedLanguageConstraintsForBackendUser();
57
58 $queryBuilder->select('tt_content_orig.sys_language_uid')
59 ->from('tt_content')
60 ->join(
61 'tt_content',
62 'tt_content',
63 'tt_content_orig',
64 $queryBuilder->expr()->eq(
65 'tt_content.t3_origuid',
66 $queryBuilder->quoteIdentifier('tt_content_orig.uid')
67 )
68 )
69 ->join(
70 'tt_content_orig',
71 'sys_language',
72 'sys_language',
73 $queryBuilder->expr()->eq(
74 'tt_content_orig.sys_language_uid',
75 $queryBuilder->quoteIdentifier('sys_language.uid')
76 )
77 )
78 ->where(...$constraints)
79 ->groupBy('tt_content_orig.sys_language_uid');
80
81 return $queryBuilder->execute()->fetch();
82 }
83
84 /**
85 * @param int $pageId
86 * @param int $colPos
87 * @param int $languageId
88 * @return int
89 */
90 public function getLocalizedRecordCount($pageId, $colPos, $languageId)
91 {
92 $queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
93
94 $rowCount = $queryBuilder->count('uid')
95 ->from('tt_content')
96 ->where(
97 $queryBuilder->expr()->eq(
98 'tt_content.sys_language_uid',
99 $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
100 ),
101 $queryBuilder->expr()->eq(
102 'tt_content.colPos',
103 $queryBuilder->createNamedParameter($colPos, \PDO::PARAM_INT)
104 ),
105 $queryBuilder->expr()->eq(
106 'tt_content.pid',
107 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
108 ),
109 $queryBuilder->expr()->neq(
110 'tt_content.t3_origuid',
111 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
112 )
113 )
114 ->execute()
115 ->fetchColumn(0);
116
117 return (int)$rowCount;
118 }
119
120 /**
121 * Fetch all available languages
122 *
123 * @param int $pageId
124 * @param int $colPos
125 * @param int $languageId
126 * @return array
127 */
128 public function fetchAvailableLanguages($pageId, $colPos, $languageId)
129 {
130 $queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
131
132 $constraints = [
133 $queryBuilder->expr()->eq(
134 'tt_content.sys_language_uid',
135 $queryBuilder->quoteIdentifier('sys_language.uid')
136 ),
137 $queryBuilder->expr()->eq(
138 'tt_content.colPos',
139 $queryBuilder->createNamedParameter($colPos, \PDO::PARAM_INT)
140 ),
141 $queryBuilder->expr()->eq(
142 'tt_content.pid',
143 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
144 ),
145 $queryBuilder->expr()->neq(
146 'sys_language.uid',
147 $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
148 )
149 ];
150 $constraints += $this->getAllowedLanguageConstraintsForBackendUser();
151
152 $queryBuilder->select('sys_language.uid')
153 ->from('tt_content')
154 ->from('sys_language')
155 ->where(...$constraints)
156 ->groupBy('sys_language.uid')
157 ->orderBy('sys_language.sorting');
158
159 $result = $queryBuilder->execute()->fetchAll();
160
161 return $result;
162 }
163
164 /**
165 * Builds an additional where clause to exclude deleted records and setting the versioning placeholders
166 *
167 * @return string
168 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
169 */
170 public function getExcludeQueryPart()
171 {
172 GeneralUtility::logDeprecatedFunction();
173
174 return BackendUtility::deleteClause('tt_content') . BackendUtility::versioningPlaceholderClause('tt_content');
175 }
176
177 /**
178 * Builds an additional where clause to exclude hidden languages and limit a backend user to its allowed languages,
179 * if the user is not an admin.
180 *
181 * @return string
182 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
183 */
184 public function getAllowedLanguagesForBackendUser()
185 {
186 GeneralUtility::logDeprecatedFunction();
187
188 $backendUser = $this->getBackendUser();
189 $additionalWhere = '';
190 if (!$backendUser->isAdmin()) {
191 $additionalWhere .= ' AND sys_language.hidden=0';
192
193 if (!empty($backendUser->user['allowed_languages'])) {
194 $additionalWhere .= ' AND sys_language.uid IN(' . implode(',', GeneralUtility::intExplode(',', $backendUser->user['allowed_languages'])) . ')';
195 }
196 }
197
198 return $additionalWhere;
199 }
200
201 /**
202 * Builds additional query constraints to exclude hidden languages and
203 * limit a backend user to its allowed languages (unless the user is an admin)
204 *
205 * @return array
206 */
207 protected function getAllowedLanguageConstraintsForBackendUser(): array
208 {
209 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
210 $constraints = [];
211
212 $backendUser = $this->getBackendUser();
213 if (!$backendUser->isAdmin()) {
214 if (!empty($GLOBALS['TCA']['sys_language']['ctrl']['enablecolumns']['disabled'])) {
215 $constraints[] = $queryBuilder->expr()->eq(
216 'sys_language.' . $GLOBALS['TCA']['sys_language']['ctrl']['enablecolumns']['disabled'],
217 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
218 );
219 }
220
221 if (!empty($backendUser->user['allowed_languages'])) {
222 $constraints[] = $queryBuilder->expr()->in(
223 'sys_language.uid',
224 $queryBuilder->createNamedParameter(
225 GeneralUtility::intExplode(',', $backendUser->user['allowed_languages'], true),
226 Connection::PARAM_INT_ARRAY
227 )
228 );
229 }
230 }
231
232 return $constraints;
233 }
234
235 /**
236 * Get records for copy process
237 *
238 * @param int $pageId
239 * @param int $colPos
240 * @param int $destLanguageId
241 * @param int $languageId
242 * @param string $fields
243 * @return \Doctrine\DBAL\Driver\Statement
244 */
245 public function getRecordsToCopyDatabaseResult($pageId, $colPos, $destLanguageId, $languageId, $fields = '*')
246 {
247 $originalUids = [];
248
249 // Get original uid of existing elements triggered language / colpos
250 $queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
251
252 $originalUidsStatement = $queryBuilder
253 ->select('t3_origuid')
254 ->from('tt_content')
255 ->where(
256 $queryBuilder->expr()->eq(
257 'sys_language_uid',
258 $queryBuilder->createNamedParameter($destLanguageId, \PDO::PARAM_INT)
259 ),
260 $queryBuilder->expr()->eq(
261 'tt_content.colPos',
262 $queryBuilder->createNamedParameter($colPos, \PDO::PARAM_INT)
263 ),
264 $queryBuilder->expr()->eq(
265 'tt_content.pid',
266 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
267 )
268 )
269 ->execute();
270
271 while ($origUid = $originalUidsStatement->fetchColumn(0)) {
272 $originalUids[] = (int)$origUid;
273 }
274
275 $queryBuilder->select(...GeneralUtility::trimExplode(',', $fields, true))
276 ->from('tt_content')
277 ->where(
278 $queryBuilder->expr()->eq(
279 'tt_content.sys_language_uid',
280 $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
281 ),
282 $queryBuilder->expr()->eq(
283 'tt_content.colPos',
284 $queryBuilder->createNamedParameter($colPos, \PDO::PARAM_INT)
285 ),
286 $queryBuilder->expr()->eq(
287 'tt_content.pid',
288 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
289 )
290 )
291 ->orderBy('tt_content.sorting');
292
293 if (!empty($originalUids)) {
294 $queryBuilder
295 ->andWhere(
296 $queryBuilder->expr()->notIn(
297 'tt_content.uid',
298 $queryBuilder->createNamedParameter($originalUids, Connection::PARAM_INT_ARRAY)
299 )
300 );
301 }
302
303 return $queryBuilder->execute();
304 }
305
306 /**
307 * Fetches the localization for a given record.
308 *
309 * @FIXME: This method is a clone of BackendUtility::getRecordLocalization, using origUid instead of transOrigPointerField
310 *
311 * @param string $table Table name present in $GLOBALS['TCA']
312 * @param int $uid The uid of the record
313 * @param int $language The uid of the language record in sys_language
314 * @param string $andWhereClause Optional additional WHERE clause (default: '')
315 * @return mixed Multidimensional array with selected records; if none exist, FALSE is returned
316 *
317 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
318 */
319 public function getRecordLocalization($table, $uid, $language, $andWhereClause = '')
320 {
321 GeneralUtility::logDeprecatedFunction();
322 $recordLocalization = false;
323
324 // Pages still stores translations in the pages_language_overlay table, all other tables store in themself
325 if ($table === 'pages') {
326 $table = 'pages_language_overlay';
327 }
328
329 if (BackendUtility::isTableLocalizable($table)) {
330 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
331
332 if (isset($tcaCtrl['origUid'])) {
333 $recordLocalization = BackendUtility::getRecordsByField(
334 $table,
335 $tcaCtrl['origUid'],
336 $uid,
337 'AND ' . $tcaCtrl['languageField'] . '=' . (int)$language . ($andWhereClause ? ' ' . $andWhereClause : ''),
338 '',
339 '',
340 '1'
341 );
342 }
343 }
344 return $recordLocalization;
345 }
346
347 /**
348 * Returning uid of previous localized record, if any, for tables with a "sortby" column
349 * Used when new localized records are created so that localized records are sorted in the same order as the default language records
350 *
351 * @FIXME: This method is a clone of DataHandler::getPreviousLocalizedRecordUid which is protected there and uses
352 * BackendUtility::getRecordLocalization which we also needed to clone in this class. Also, this method takes two
353 * language arguments.
354 *
355 * @param string $table Table name
356 * @param int $uid Uid of default language record
357 * @param int $pid Pid of default language record
358 * @param int $sourceLanguage Language of origin
359 * @param int $destinationLanguage Language of localization
360 * @return int uid of record after which the localized record should be inserted
361 *
362 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
363 */
364 public function getPreviousLocalizedRecordUid($table, $uid, $pid, $sourceLanguage, $destinationLanguage)
365 {
366 GeneralUtility::logDeprecatedFunction();
367 $previousLocalizedRecordUid = $uid;
368 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
369 $sortRow = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
370 $select = [$sortRow, 'pid', 'uid'];
371 // For content elements, we also need the colPos
372 if ($table === 'tt_content') {
373 $select[] = 'colPos';
374 }
375 // Get the sort value of the default language record
376 $row = BackendUtility::getRecord($table, $uid, implode(',', $select));
377 if (is_array($row)) {
378 $queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
379
380 $queryBuilder->select(...$select)
381 ->from($table)
382 ->where(
383 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)),
384 $queryBuilder->expr()->eq(
385 'sys_language_uid',
386 $queryBuilder->createNamedParameter($sourceLanguage, \PDO::PARAM_INT)
387 ),
388 $queryBuilder->expr()->lt(
389 $sortRow,
390 $queryBuilder->createNamedParameter($row[$sortRow], \PDO::PARAM_INT)
391 )
392 );
393
394 // Respect the colPos for content elements
395 if ($table === 'tt_content') {
396 $queryBuilder->andWhere(
397 $queryBuilder->expr()->eq(
398 'colPos',
399 $queryBuilder->createNamedParameter($row['colPos'], \PDO::PARAM_INT)
400 )
401 );
402 }
403
404 $previousRow = $queryBuilder->orderBy($sortRow, 'DESC')->execute()->fetch();
405
406 // If there is an element, find its localized record in specified localization language
407 if ($previousRow !== false) {
408 $previousLocalizedRecord = $this->getRecordLocalization(
409 $table,
410 $previousRow['uid'],
411 $destinationLanguage
412 );
413 if (is_array($previousLocalizedRecord[0])) {
414 $previousLocalizedRecordUid = $previousLocalizedRecord[0]['uid'];
415 }
416 }
417 }
418 }
419
420 return $previousLocalizedRecordUid;
421 }
422
423 /**
424 * Returns the current BE user.
425 *
426 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
427 */
428 protected function getBackendUser()
429 {
430 return $GLOBALS['BE_USER'];
431 }
432
433 /**
434 * Get a QueryBuilder for the given table with preconfigured restrictions
435 * to not retrieve workspace placeholders or deleted records.
436 *
437 * @param string $tableName
438 * @return \TYPO3\CMS\Core\Database\Query\QueryBuilder
439 */
440 protected function getQueryBuilderWithWorkspaceRestriction(string $tableName): QueryBuilder
441 {
442 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
443 $queryBuilder->getRestrictions()
444 ->removeAll()
445 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
446 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
447
448 return $queryBuilder;
449 }
450 }