[TASK] Replace DatabaseConnection->cleanIntArray()
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / DataHandling / PlainDataResolver.php
1 <?php
2 namespace TYPO3\CMS\Core\DataHandling;
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\Versioning\VersionState;
19
20 /**
21 * Plain data resolving.
22 *
23 * This component resolves data constraints for given IDs of a
24 * particular table on a plain/raw database level. Thus, workspaces
25 * placeholders and overlay related resorting is applied automatically.
26 */
27 class PlainDataResolver
28 {
29 /**
30 * @var string
31 */
32 protected $tableName;
33
34 /**
35 * @var int[]
36 */
37 protected $liveIds;
38
39 /**
40 * @var string
41 */
42 protected $sortingStatement;
43
44 /**
45 * @var int
46 */
47 protected $workspaceId;
48
49 /**
50 * @var bool
51 */
52 protected $keepLiveIds = false;
53
54 /**
55 * @var bool
56 */
57 protected $keepDeletePlaceholder = false;
58
59 /**
60 * @var bool
61 */
62 protected $keepMovePlaceholder = true;
63
64 /**
65 * @var int[]
66 */
67 protected $resolvedIds;
68
69 /**
70 * @param string $tableName
71 * @param int[] $liveIds
72 * @param NULL|string $sortingStatement
73 */
74 public function __construct($tableName, array $liveIds, $sortingStatement = null)
75 {
76 $this->tableName = $tableName;
77 $this->liveIds = $this->reindex($liveIds);
78 $this->sortingStatement = $sortingStatement;
79 }
80
81 /**
82 * Sets the target workspace ID the final result shall use.
83 *
84 * @param int $workspaceId
85 */
86 public function setWorkspaceId($workspaceId)
87 {
88 $this->workspaceId = (int)$workspaceId;
89 }
90
91 /**
92 * Sets whether live IDs shall be kept in the final result set.
93 *
94 * @param bool $keepLiveIds
95 */
96 public function setKeepLiveIds($keepLiveIds)
97 {
98 $this->keepLiveIds = (bool)$keepLiveIds;
99 }
100
101 /**
102 * Sets whether delete placeholders shall be kept in the final result set.
103 *
104 * @param bool $keepDeletePlaceholder
105 */
106 public function setKeepDeletePlaceholder($keepDeletePlaceholder)
107 {
108 $this->keepDeletePlaceholder = (bool)$keepDeletePlaceholder;
109 }
110
111 /**
112 * Sets whether move placeholders shall be kept in case they cannot be substituted.
113 *
114 * @param bool $keepMovePlaceholder
115 */
116 public function setKeepMovePlaceholder($keepMovePlaceholder)
117 {
118 $this->keepMovePlaceholder = (bool)$keepMovePlaceholder;
119 }
120
121 /**
122 * @return int[]
123 */
124 public function get()
125 {
126 if (isset($this->resolvedIds)) {
127 return $this->resolvedIds;
128 }
129
130 $ids = $this->processVersionOverlays($this->liveIds);
131 $ids = $this->processSorting($ids);
132 $ids = $this->applyLiveIds($ids);
133
134 $this->resolvedIds = $ids;
135 return $this->resolvedIds;
136 }
137
138 /**
139 * Processes version overlays on the final result set.
140 *
141 * @param int[] $ids
142 * @return int[]
143 */
144 protected function processVersionOverlays(array $ids)
145 {
146 if (empty($this->workspaceId) || !$this->isWorkspaceEnabled() || empty($ids)) {
147 return $ids;
148 }
149
150 $ids = $this->processVersionMovePlaceholders($ids);
151 $versions = $this->getDatabaseConnection()->exec_SELECTgetRows(
152 'uid,t3ver_oid,t3ver_state',
153 $this->tableName,
154 'pid=-1 AND t3ver_oid IN (' . $this->intImplode(',', $ids) . ')'
155 . ' AND t3ver_wsid=' . $this->workspaceId
156 );
157
158 if (!empty($versions)) {
159 foreach ($versions as $version) {
160 $liveReferenceId = $version['t3ver_oid'];
161 $versionId = $version['uid'];
162 if (isset($ids[$liveReferenceId])) {
163 if (!$this->keepDeletePlaceholder && VersionState::cast($version['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
164 unset($ids[$liveReferenceId]);
165 } else {
166 $ids[$liveReferenceId] = $versionId;
167 }
168 }
169 }
170 $ids = $this->reindex($ids);
171 }
172
173 return $ids;
174 }
175
176 /**
177 * Processes and resolves move placeholders on the final result set.
178 *
179 * @param int[] $ids
180 * @return int[]
181 */
182 protected function processVersionMovePlaceholders(array $ids)
183 {
184 // Early return on insufficient data-set
185 if (empty($this->workspaceId) || !$this->isWorkspaceEnabled() || empty($ids)) {
186 return $ids;
187 }
188
189 $movePlaceholders = $this->getDatabaseConnection()->exec_SELECTgetRows(
190 'uid,t3ver_move_id',
191 $this->tableName,
192 'pid<>-1 AND t3ver_state=' . VersionState::MOVE_PLACEHOLDER
193 . ' AND t3ver_wsid=' . $this->workspaceId
194 . ' AND t3ver_move_id IN (' . $this->intImplode(',', $ids) . ')'
195 );
196
197 if (!empty($movePlaceholders)) {
198 foreach ($movePlaceholders as $movePlaceholder) {
199 $liveReferenceId = $movePlaceholder['t3ver_move_id'];
200 $movePlaceholderId = $movePlaceholder['uid'];
201 // Substitute MOVE_PLACEHOLDER and purge live reference
202 if (isset($ids[$movePlaceholderId])) {
203 $ids[$movePlaceholderId] = $liveReferenceId;
204 unset($ids[$liveReferenceId]);
205 // Just purge live reference
206 } elseif (!$this->keepMovePlaceholder) {
207 unset($ids[$liveReferenceId]);
208 }
209 }
210 $ids = $this->reindex($ids);
211 }
212
213 return $ids;
214 }
215
216 /**
217 * Processes sorting of the final result set, if
218 * a sorting statement (table column/expression) is given.
219 *
220 * @param int[] $ids
221 * @return int[]
222 */
223 protected function processSorting(array $ids)
224 {
225 // Early return on missing sorting statement or insufficient data-set
226 if (empty($this->sortingStatement) || count($ids) < 2) {
227 return $ids;
228 }
229
230 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
231 'uid',
232 $this->tableName,
233 'uid IN (' . $this->intImplode(',', $ids) . ')',
234 '',
235 $this->sortingStatement,
236 '',
237 'uid'
238 );
239
240 if (!is_array($records)) {
241 return array();
242 }
243
244 $ids = $this->reindex(array_keys($records));
245 return $ids;
246 }
247
248 /**
249 * Applies live IDs to the final result set, if
250 * the current table is enabled for workspaces and
251 * the keepLiveIds class member is enabled.
252 *
253 * @param int[] $ids
254 * @return int[]
255 */
256 protected function applyLiveIds(array $ids)
257 {
258 if (!$this->keepLiveIds || !$this->isWorkspaceEnabled() || empty($ids)) {
259 return $ids;
260 }
261
262 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
263 'uid,t3ver_oid',
264 $this->tableName,
265 'uid IN (' . $this->intImplode(',', $ids) . ')',
266 '',
267 '',
268 '',
269 'uid'
270 );
271
272 if (!is_array($records)) {
273 return array();
274 }
275
276 foreach ($ids as $id) {
277 if (!empty($records[$id]['t3ver_oid'])) {
278 $ids[$id] = $records[$id]['t3ver_oid'];
279 }
280 }
281
282 $ids = $this->reindex($ids);
283 return $ids;
284 }
285
286 /**
287 * Re-indexes the given IDs.
288 *
289 * @param int[] $ids
290 * @return int[]
291 */
292 protected function reindex(array $ids)
293 {
294 if (empty($ids)) {
295 return $ids;
296 }
297 $ids = array_values($ids);
298 $ids = array_combine($ids, $ids);
299 return $ids;
300 }
301
302 /**
303 * @return bool
304 */
305 protected function isWorkspaceEnabled()
306 {
307 return BackendUtility::isTableWorkspaceEnabled($this->tableName);
308 }
309
310 /**
311 * @return bool
312 */
313 protected function isLocalizationEnabled()
314 {
315 return BackendUtility::isTableLocalizable($this->tableName);
316 }
317
318 /**
319 * Implodes an array of casted integer values.
320 *
321 * @param string $delimiter
322 * @param array $values
323 * @return string
324 */
325 protected function intImplode($delimiter, array $values)
326 {
327 return implode($delimiter, array_map('intval', $values));
328 }
329
330 /**
331 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
332 */
333 protected function getDatabaseConnection()
334 {
335 return $GLOBALS['TYPO3_DB'];
336 }
337 }