Fixed bug #16342: TCA tree throws Fatal error on displaying deleted records
[Packages/TYPO3.CMS.git] / t3lib / tree / tca / class.t3lib_tree_tca_databasetreedataprovider.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 Steffen Ritter <info@steffen-ritter.net>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * TCA tree data provider
30 *
31 * @author Steffen Ritter <info@steffen-ritter.net>
32 * @package TYPO3
33 * @subpackage t3lib_tree
34 */
35
36 class t3lib_tree_Tca_DatabaseTreeDataProvider extends t3lib_tree_Tca_AbstractTcaTreeDataProvider {
37
38 const MODE_CHILDREN = 1;
39 const MODE_PARENT = 2;
40
41 /**
42 * @var string
43 */
44 protected $tableName = '';
45
46 /**
47 * @var string
48 */
49 protected $treeId = '';
50
51 /**
52 * @var string
53 */
54 protected $labelField = '';
55
56 /**
57 * @var string
58 *
59 */
60 protected $tableWhere = '';
61
62 /**
63 * @var int
64 */
65 protected $lookupMode = t3lib_tree_tca_DatabaseTreeDataProvider::MODE_CHILDREN;
66
67 /**
68 * @var string
69 */
70 protected $lookupField = '';
71
72 /**
73 * @var int
74 */
75 protected $rootUid = 0;
76
77 /**
78 * @var array
79 */
80 protected $idCache = array();
81
82 /**
83 * Sets the label field
84 *
85 * @param string $labelField
86 * @return void
87 */
88 public function setLabelField($labelField) {
89 $this->labelField = $labelField;
90 }
91
92 /**
93 * Gets the label field
94 *
95 * @return string
96 */
97 public function getLabelField() {
98 return $this->labelField;
99 }
100
101 /**
102 * Sets the table name
103 *
104 * @param string $tableName
105 * @return void
106 */
107 public function setTableName($tableName) {
108 $this->tableName = $tableName;
109 }
110
111 /**
112 * Gets the table name
113 *
114 * @return string
115 */
116 public function getTableName() {
117 return $this->tableName;
118 }
119
120 /**
121 * Sets the lookup field
122 *
123 * @param string $lookupField
124 * @return void
125 */
126 public function setLookupField($lookupField) {
127 $this->lookupField = $lookupField;
128 }
129
130 /**
131 * Gets the lookup field
132 *
133 * @return string
134 */
135 public function getLookupField() {
136 return $this->lookupField;
137 }
138
139 /**
140 * Sets the lookup mode
141 *
142 * @param int $lookupMode
143 * @return void
144 */
145 public function setLookupMode($lookupMode) {
146 $this->lookupMode = $lookupMode;
147 }
148
149 /**
150 * Gets the lookup mode
151 *
152 * @return int
153 */
154 public function getLookupMode() {
155 return $this->lookupMode;
156 }
157
158
159 /**
160 * Gets the nodes
161 *
162 * @param t3lib_tree_Node $node
163 * @return t3lib_tree_NodeCollection
164 */
165 public function getNodes(t3lib_tree_Node $node) {
166
167 }
168
169 /**
170 * Gets the root node
171 *
172 * @return t3lib_tree_tca_DatabaseNode
173 */
174 public function getRoot() {
175 return $this->buildRepresentationForNode($this->treeData);
176 }
177
178 /**
179 * Sets the root uid
180 *
181 * @param $rootUid
182 * @return void
183 */
184 public function setRootUid($rootUid) {
185 $this->rootUid = $rootUid;
186 }
187
188 /**
189 * Gets the root uid
190 *
191 * @return int
192 */
193 public function getRootUid() {
194 return $this->rootUid;
195 }
196
197 /**
198 * Sets the tableWhere clause
199 *
200 * @param string $tableWhere
201 * @return void
202 */
203 public function setTableWhere(string $tableWhere) {
204 $this->tableWhere = $tableWhere;
205 }
206
207 /**
208 * Gets the tableWhere clause
209 *
210 * @return string
211 */
212 public function getTableWhere() {
213 return $this->tableWhere;
214 }
215
216 /**
217 * Builds a complete node including childs
218 *
219 * @param t3lib_tree_Node $basicNode
220 * @param null|t3lib_tree_tca_DatabaseNode $parent
221 * @param int $level
222 * @return A|object
223 */
224 protected function buildRepresentationForNode(t3lib_tree_Node $basicNode, t3lib_tree_tca_DatabaseNode $parent = NULL, $level = 0) {
225 $node = t3lib_div::makeInstance('t3lib_tree_tca_DatabaseNode');
226 $row = array();
227 if ($basicNode->getId() == 0) {
228 $node->setSelected(FALSE);
229 $node->setExpanded(TRUE);
230 $node->setLabel($GLOBALS['LANG']->sL($GLOBALS['TCA'][$this->tableName]['ctrl']['title']));
231 } else {
232 $row = t3lib_BEfunc::getRecordWSOL($this->tableName, $basicNode->getId(), '*', '', FALSE);
233 if ($this->getLabelField() !== '') {
234 $node->setLabel($row[$this->getLabelField()]);
235 } else {
236 $node->setLabel($basicNode->getId());
237 }
238 $node->setSelected(t3lib_div::inList($this->getSelectedList(), $basicNode->getId()));
239 $node->setExpanded($this->isExpanded($basicNode));
240 }
241 $node->setSelectable(!t3lib_div::inList($this->getNonSelectableLevelList(), $level));
242 $node->setIcon(t3lib_iconWorks::mapRecordTypeToSpriteIconClass($this->tableName, $row));
243 $node->setId($basicNode->getId());
244 $node->setParentNode($parent);
245 if ($basicNode->hasChildNodes()) {
246 $node->setHasChildren(TRUE);
247
248 $childNodes = t3lib_div::makeInstance('t3lib_tree_NodeCollection');
249 foreach ($basicNode->getChildNodes() as $child) {
250 $childNodes->append($this->buildRepresentationForNode($child, $node, $level + 1));
251 }
252 $node->setChildNodes($childNodes);
253 }
254
255 return $node;
256 }
257
258 /**
259 * Init the tree data
260 *
261 * @return void
262 */
263 public function initializeTreeData() {
264 parent::initializeTreeData();
265
266 $this->treeData = t3lib_div::makeInstance('t3lib_tree_Node');
267 $this->treeData->setId($this->getRootUid());
268 $this->treeData->setParentNode(NULL);
269 $childNodes = $this->getChildrenOf($this->treeData, 0);
270 if ($childNodes !== NULL) {
271 $this->treeData->setChildNodes($childNodes);
272 }
273 }
274
275 /**
276 * Gets node children
277 *
278 * @param t3lib_tree_Node $node
279 * @param $level
280 * @return A|null|object
281 */
282 protected function getChildrenOf(t3lib_tree_Node $node, $level) {
283 $nodeData = NULL;
284 if ($node->getId() !== 0) {
285 $nodeData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
286 '*',
287 $this->tableName,
288 'uid=' . $node->getId()
289 );
290 }
291 if ($nodeData == NULL) {
292 $nodeData = array(
293 'uid' => 0,
294 $this->getLookupField() => '',
295 );
296 }
297 $storage = NULL;
298 $children = $this->getRelatedRecords($nodeData);
299 if (count($children)) {
300 $storage = t3lib_div::makeInstance('t3lib_tree_NodeCollection');
301 foreach ($children as $child) {
302 $node = t3lib_div::makeInstance('t3lib_tree_Node');
303 ;
304 $node->setId($child);
305 if ($level <= $this->levelMaximum) {
306 $children = $this->getChildrenOf($node, $level + 1);
307 if ($children !== NULL) {
308 $node->setChildNodes($children);
309 }
310 }
311 $storage->append($node);
312 }
313 }
314
315 return $storage;
316 }
317
318 /**
319 * Gets related records depending on TCA configuration
320 *
321 * @param $row
322 * @return array
323 */
324 protected function getRelatedRecords(array $row) {
325 if ($this->getLookupMode() == t3lib_tree_tca_DatabaseTreeDataProvider::MODE_PARENT) {
326 $children = $this->getChildrenUidsFromParentRelation($row);
327 } else {
328 $children = $this->getChildrenUidsFromChildrenRelation($row);
329 }
330
331 $allowedArray = array();
332 foreach ($children as $child) {
333 if (!in_array($child, $this->idCache)) {
334 $allowedArray[] = $child;
335 }
336 }
337
338 $this->idCache = array_merge($this->idCache, $allowedArray);
339
340 return $allowedArray;
341 }
342
343 /**
344 * Gets related records depending on TCA configuration
345 *
346 * @param $row
347 * @return array
348 */
349 protected function getChildrenUidsFromParentRelation(array $row) {
350 $relatedUids = array();
351 $uid = $row['uid'];
352
353 $columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
354 switch ((string) $columnConfiguration['type']) {
355 case 'inline':
356 case 'select':
357 if ($columnConfiguration['MM']) {
358 $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
359 // dummy field for setting "look from other site"
360 $columnConfiguration['MM_oppositeField'] = 'children';
361
362 $dbGroup->start(
363 $row[$this->getLookupField()],
364 $columnConfiguration['foreign_table'],
365 $columnConfiguration['MM'],
366 $uid, $this->getTableName(),
367 $columnConfiguration
368 );
369
370 $relatedUids = $dbGroup->tableArray[$columnConfiguration['foreign_table']];
371 } elseif ($columnConfiguration['foreign_table'] && $GLOBALS['TCA'][$columnConfiguration['foreign_table']] && $columnConfiguration['foreign_field']) {
372 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
373 'uid',
374 $columnConfiguration['foreign_table'],
375 " (CONCAT(','," . $columnConfiguration['foreign_field'] . ",',') LIKE '%," . intval($uid) . ",%' "
376 . (intval($uid) == 0 ? (" OR " . $columnConfiguration['foreign_field'] . " = ''") : '')
377 . ") " . t3lib_BEfunc::deleteClause($columnConfiguration['foreign_table'])
378 );
379 foreach ($records as $record) {
380 $relatedUids[] = $record['uid'];
381 }
382 } else {
383 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
384 'uid',
385 $columnConfiguration['foreign_table'],
386 " (CONCAT(','," . $this->getLookupField() . ",',') LIKE '%," . intval($uid) . ",%' "
387 . (intval($uid) == 0 ? (" OR " . $this->getLookupField() . " = ''") : '')
388 . ") " . t3lib_BEfunc::deleteClause($columnConfiguration['foreign_table'])
389 );
390 foreach ($records as $record) {
391 $relatedUids[] = $record['uid'];
392 }
393 }
394 break;
395 case 'group':
396 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
397 'uid',
398 $columnConfiguration['foreign_table'],
399 " (CONCAT(','," . $this->getLookupField() . ",',') LIKE '%," . intval($uid) . ",%' "
400 . (intval($uid) == 0 ? (" OR " . $this->getLookupField() . " = ''") : '')
401 . ") " . t3lib_BEfunc::deleteClause($columnConfiguration['foreign_table'])
402 );
403 foreach ($records as $record) {
404 $relatedUids[] = $record['uid'];
405 }
406 break;
407 }
408
409 return $relatedUids;
410 }
411
412 /**
413 * Gets related children records depending on TCA configuration
414 *
415 * @param $row
416 * @return array
417 */
418 protected function getChildrenUidsFromChildrenRelation(array $row) {
419 $relatedUids = array();
420 $uid = $row['uid'];
421 $value = $row[$this->getLookupField()];
422
423 $columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
424 switch ((string) $columnConfiguration['type']) {
425 case 'inline':
426 case 'select':
427 if ($columnConfiguration['MM']) {
428 $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
429 $dbGroup->start(
430 $value,
431 $columnConfiguration['foreign_table'],
432 $columnConfiguration['MM'],
433 $uid,
434 $this->getTableName(),
435 $columnConfiguration
436 );
437
438 $relatedUids = $dbGroup->tableArray[$columnConfiguration['foreign_table']];
439 } elseif ($columnConfiguration['foreign_table'] && $GLOBALS['TCA'][$columnConfiguration['foreign_table']] && $columnConfiguration['foreign_field']) {
440 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
441 'uid',
442 $columnConfiguration['foreign_table'],
443 $columnConfiguration['foreign_field'] . '=' . intval($uid) . ' ' . t3lib_BEfunc::deleteClause($columnConfiguration['foreign_table'])
444 );
445 foreach ($records as $record) {
446 $relatedUids[] = $record['uid'];
447 }
448 } else {
449 $relatedUids = t3lib_div::intExplode(',', $value, TRUE);
450 }
451 break;
452 case 'group':
453 $relatedUids = t3lib_div::intExplode(',', $value, TRUE);
454 break;
455 }
456
457 return $relatedUids;
458 }
459
460 }
461
462 ?>