[BUGFIX] Adds missing tablename sys_language in fetchOriginLanguage function
[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
19 /**
20 * Repository for record localizations
21 */
22 class LocalizationRepository
23 {
24 /**
25 * Fetch the language from which the records of a colPos in a certain language were initially localized
26 *
27 * @param int $pageId
28 * @param int $colPos
29 * @param int $localizedLanguage
30 * @return array|false|null
31 */
32 public function fetchOriginLanguage($pageId, $colPos, $localizedLanguage)
33 {
34 $record = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
35 'tt_content_orig.sys_language_uid',
36 'tt_content,tt_content AS tt_content_orig,sys_language',
37 'tt_content.colPos = ' . (int)$colPos
38 . ' AND tt_content.pid = ' . (int)$pageId
39 . ' AND tt_content.sys_language_uid = ' . (int)$localizedLanguage
40 . ' AND tt_content.t3_origuid = tt_content_orig.uid'
41 . ' AND tt_content_orig.sys_language_uid=sys_language.uid'
42 . $this->getExcludeQueryPart()
43 . $this->getAllowedLanguagesForBackendUser(),
44 'tt_content_orig.sys_language_uid'
45 );
46
47 return $record;
48 }
49
50 /**
51 * @param $pageId
52 * @param $colPos
53 * @param $languageId
54 * @return int
55 */
56 public function getLocalizedRecordCount($pageId, $colPos, $languageId)
57 {
58 $rows = (int)$this->getDatabaseConnection()->exec_SELECTcountRows(
59 'uid',
60 'tt_content',
61 'tt_content.sys_language_uid=' . (int)$languageId
62 . ' AND tt_content.colPos = ' . (int)$colPos
63 . ' AND tt_content.pid=' . (int)$pageId
64 . ' AND tt_content.t3_origuid <> 0'
65 . $this->getExcludeQueryPart()
66 );
67
68 return $rows;
69 }
70
71 /**
72 * Fetch all available languages
73 *
74 * @param int $pageId
75 * @param int $colPos
76 * @param int $languageId
77 * @return array
78 */
79 public function fetchAvailableLanguages($pageId, $colPos, $languageId)
80 {
81 $result = $this->getDatabaseConnection()->exec_SELECTgetRows(
82 'sys_language.uid',
83 'tt_content,sys_language',
84 'tt_content.sys_language_uid=sys_language.uid'
85 . ' AND tt_content.colPos = ' . (int)$colPos
86 . ' AND tt_content.pid = ' . (int)$pageId
87 . ' AND sys_language.uid <> ' . (int)$languageId
88 . $this->getExcludeQueryPart()
89 . $this->getAllowedLanguagesForBackendUser(),
90 'sys_language.uid',
91 'sys_language.title'
92 );
93
94 return $result;
95 }
96
97 /**
98 * Builds an additional where clause to exclude deleted records and setting the versioning placeholders
99 *
100 * @return string
101 */
102 public function getExcludeQueryPart()
103 {
104 return BackendUtility::deleteClause('tt_content')
105 . BackendUtility::versioningPlaceholderClause('tt_content');
106 }
107
108 /**
109 * Builds an additional where clause to exclude hidden languages and limit a backend user to its allowed languages,
110 * if the user is not an admin.
111 *
112 * @return string
113 */
114 public function getAllowedLanguagesForBackendUser()
115 {
116 $backendUser = $this->getBackendUser();
117 $additionalWhere = '';
118 if (!$backendUser->isAdmin()) {
119 $additionalWhere .= ' AND sys_language.hidden=0';
120
121 if (!empty($backendUser->user['allowed_languages'])) {
122 $additionalWhere .= ' AND sys_language.uid IN(' . $this->getDatabaseConnection()->cleanIntList($backendUser->user['allowed_languages']) . ')';
123 }
124 }
125
126 return $additionalWhere;
127 }
128
129 /**
130 * Get records for copy process
131 *
132 * @param int $pageId
133 * @param int $colPos
134 * @param int $destLanguageId
135 * @param int $languageId
136 * @param string $fields
137 * @return bool|\mysqli_result|object
138 */
139 public function getRecordsToCopyDatabaseResult($pageId, $colPos, $destLanguageId, $languageId, $fields = '*')
140 {
141 $db = $this->getDatabaseConnection();
142
143 // Get original uid of existing elements triggered language / colpos
144 $originalUids = $db->exec_SELECTgetRows(
145 't3_origuid',
146 'tt_content',
147 'sys_language_uid=' . (int)$destLanguageId
148 . ' AND tt_content.colPos = ' . (int)$colPos
149 . ' AND tt_content.pid=' . (int)$pageId
150 . $this->getExcludeQueryPart(),
151 '',
152 '',
153 '',
154 't3_origuid'
155 );
156 $originalUidList = $db->cleanIntList(implode(',', array_keys($originalUids)));
157
158 $res = $db->exec_SELECTquery(
159 $fields,
160 'tt_content',
161 'tt_content.sys_language_uid=' . (int)$languageId
162 . ' AND tt_content.colPos = ' . (int)$colPos
163 . ' AND tt_content.pid=' . (int)$pageId
164 . ' AND tt_content.uid NOT IN (' . $originalUidList . ')'
165 . $this->getExcludeQueryPart(),
166 '',
167 'tt_content.sorting'
168 );
169
170 return $res;
171 }
172
173 /**
174 * Fetches the localization for a given record.
175 *
176 * @FIXME: This method is a clone of BackendUtility::getRecordLocalization, using origUid instead of transOrigPointerField
177 *
178 * @param string $table Table name present in $GLOBALS['TCA']
179 * @param int $uid The uid of the record
180 * @param int $language The uid of the language record in sys_language
181 * @param string $andWhereClause Optional additional WHERE clause (default: '')
182 * @return mixed Multidimensional array with selected records; if none exist, FALSE is returned
183 */
184 public function getRecordLocalization($table, $uid, $language, $andWhereClause = '')
185 {
186 $recordLocalization = false;
187
188 // Check if translations are stored in other table
189 if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) {
190 $table = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable'];
191 }
192
193 if (BackendUtility::isTableLocalizable($table)) {
194 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
195
196 if (isset($tcaCtrl['origUid'])) {
197 $recordLocalization = BackendUtility::getRecordsByField(
198 $table,
199 $tcaCtrl['origUid'],
200 $uid,
201 'AND ' . $tcaCtrl['languageField'] . '=' . (int)$language . ($andWhereClause ? ' ' . $andWhereClause : ''),
202 '',
203 '',
204 '1'
205 );
206 }
207 }
208 return $recordLocalization;
209 }
210
211 /**
212 * Returning uid of previous localized record, if any, for tables with a "sortby" column
213 * Used when new localized records are created so that localized records are sorted in the same order as the default language records
214 *
215 * @FIXME: This method is a clone of DataHandler::getPreviousLocalizedRecordUid which is protected there and uses
216 * BackendUtility::getRecordLocalization which we also needed to clone in this class. Also, this method takes two
217 * language arguments.
218 *
219 * @param string $table Table name
220 * @param int $uid Uid of default language record
221 * @param int $pid Pid of default language record
222 * @param int $sourceLanguage Language of origin
223 * @param int $destinationLanguage Language of localization
224 * @return int uid of record after which the localized record should be inserted
225 */
226 public function getPreviousLocalizedRecordUid($table, $uid, $pid, $sourceLanguage, $destinationLanguage)
227 {
228 $previousLocalizedRecordUid = $uid;
229 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
230 $sortRow = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
231 $select = $sortRow . ',pid,uid';
232 // For content elements, we also need the colPos
233 if ($table === 'tt_content') {
234 $select .= ',colPos';
235 }
236 // Get the sort value of the default language record
237 $row = BackendUtility::getRecord($table, $uid, $select);
238 if (is_array($row)) {
239 // Find the previous record in default language on the same page
240 $where = 'pid=' . (int)$pid . ' AND ' . 'sys_language_uid=' . (int)$sourceLanguage . ' AND ' . $sortRow . '<' . (int)$row[$sortRow];
241 // Respect the colPos for content elements
242 if ($table === 'tt_content') {
243 $where .= ' AND colPos=' . (int)$row['colPos'];
244 }
245 $res = $this->getDatabaseConnection()->exec_SELECTquery(
246 $select,
247 $table,
248 $where . BackendUtility::deleteClause($table),
249 '',
250 $sortRow . ' DESC',
251 '1'
252 );
253 // If there is an element, find its localized record in specified localization language
254 if ($previousRow = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
255 $previousLocalizedRecord = $this->getRecordLocalization($table, $previousRow['uid'], $destinationLanguage);
256 if (is_array($previousLocalizedRecord[0])) {
257 $previousLocalizedRecordUid = $previousLocalizedRecord[0]['uid'];
258 }
259 }
260 $this->getDatabaseConnection()->sql_free_result($res);
261 }
262 }
263 return $previousLocalizedRecordUid;
264 }
265
266 /**
267 * Returns the current BE user.
268 *
269 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
270 */
271 protected function getBackendUser()
272 {
273 return $GLOBALS['BE_USER'];
274 }
275
276 /**
277 * Returns the database connection
278 *
279 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
280 */
281 protected function getDatabaseConnection()
282 {
283 return $GLOBALS['TYPO3_DB'];
284 }
285 }