Fixed bug #16605: TCA tree: sorting is not working
[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 /**
84 * Stores TCA-Configuration of the LookUpField in tableName
85 *
86 * @var array
87 */
88 protected $columnConfiguration;
89
90 /**
91 * node sort values (the orderings from foreign_Table_where evaluation)
92 *
93 * @var array
94 */
95 protected $nodeSortValues = array();
96
97 /**
98 * @var array TCEforms compiled TSConfig array
99 */
100 protected $generatedTSConfig = array();
101
102 /**
103 * Sets the label field
104 *
105 * @param string $labelField
106 * @return void
107 */
108 public function setLabelField($labelField) {
109 $this->labelField = $labelField;
110 }
111
112 /**
113 * Gets the label field
114 *
115 * @return string
116 */
117 public function getLabelField() {
118 return $this->labelField;
119 }
120
121 /**
122 * Sets the table name
123 *
124 * @param string $tableName
125 * @return void
126 */
127 public function setTableName($tableName) {
128 $this->tableName = $tableName;
129 }
130
131 /**
132 * Gets the table name
133 *
134 * @return string
135 */
136 public function getTableName() {
137 return $this->tableName;
138 }
139
140 /**
141 * Sets the lookup field
142 *
143 * @param string $lookupField
144 * @return void
145 */
146 public function setLookupField($lookupField) {
147 $this->lookupField = $lookupField;
148 }
149
150 /**
151 * Gets the lookup field
152 *
153 * @return string
154 */
155 public function getLookupField() {
156 return $this->lookupField;
157 }
158
159 /**
160 * Sets the lookup mode
161 *
162 * @param int $lookupMode
163 * @return void
164 */
165 public function setLookupMode($lookupMode) {
166 $this->lookupMode = $lookupMode;
167 }
168
169 /**
170 * Gets the lookup mode
171 *
172 * @return int
173 */
174 public function getLookupMode() {
175 return $this->lookupMode;
176 }
177
178
179 /**
180 * Gets the nodes
181 *
182 * @param t3lib_tree_Node $node
183 * @return t3lib_tree_NodeCollection
184 */
185 public function getNodes(t3lib_tree_Node $node) {
186
187 }
188
189 /**
190 * Gets the root node
191 *
192 * @return t3lib_tree_tca_DatabaseNode
193 */
194 public function getRoot() {
195 return $this->buildRepresentationForNode($this->treeData);
196 }
197
198 /**
199 * Sets the root uid
200 *
201 * @param $rootUid
202 * @return void
203 */
204 public function setRootUid($rootUid) {
205 $this->rootUid = $rootUid;
206 }
207
208 /**
209 * Gets the root uid
210 *
211 * @return int
212 */
213 public function getRootUid() {
214 return $this->rootUid;
215 }
216
217 /**
218 * Sets the tableWhere clause
219 *
220 * @param string $tableWhere
221 * @return void
222 */
223 public function setTableWhere(string $tableWhere) {
224 $this->tableWhere = $tableWhere;
225 }
226
227 /**
228 * Gets the tableWhere clause
229 *
230 * @return string
231 */
232 public function getTableWhere() {
233 return $this->tableWhere;
234 }
235
236 /**
237 * Builds a complete node including childs
238 *
239 * @param t3lib_tree_Node $basicNode
240 * @param null|t3lib_tree_tca_DatabaseNode $parent
241 * @param int $level
242 * @return A|object
243 */
244 protected function buildRepresentationForNode(t3lib_tree_Node $basicNode, t3lib_tree_tca_DatabaseNode $parent = NULL, $level = 0) {
245 $node = t3lib_div::makeInstance('t3lib_tree_tca_DatabaseNode');
246 $row = array();
247 if ($basicNode->getId() == 0) {
248 $node->setSelected(FALSE);
249 $node->setExpanded(TRUE);
250 $node->setLabel($GLOBALS['LANG']->sL($GLOBALS['TCA'][$this->tableName]['ctrl']['title']));
251 } else {
252 $row = t3lib_BEfunc::getRecordWSOL($this->tableName, $basicNode->getId(), '*', '', FALSE);
253 if ($this->getLabelField() !== '') {
254 $node->setLabel($row[$this->getLabelField()]);
255 } else {
256 $node->setLabel($basicNode->getId());
257 }
258 $node->setSelected(t3lib_div::inList($this->getSelectedList(), $basicNode->getId()));
259 $node->setExpanded($this->isExpanded($basicNode));
260 }
261 $node->setId($basicNode->getId());
262
263 $node->setSelectable(!t3lib_div::inList($this->getNonSelectableLevelList(), $level));
264 $node->setSortValue($this->nodeSortValues[$basicNode->getId()]);
265
266 $node->setIcon(t3lib_iconWorks::mapRecordTypeToSpriteIconClass($this->tableName, $row));
267 $node->setParentNode($parent);
268 if ($basicNode->hasChildNodes()) {
269 $node->setHasChildren(TRUE);
270
271 $childNodes = t3lib_div::makeInstance('t3lib_tree_SortedNodeCollection');
272 foreach ($basicNode->getChildNodes() as $child) {
273 $childNodes->append($this->buildRepresentationForNode($child, $node, $level + 1));
274 }
275 $node->setChildNodes($childNodes);
276 }
277
278 return $node;
279 }
280
281 /**
282 * Init the tree data
283 *
284 * @return void
285 */
286 public function initializeTreeData() {
287 parent::initializeTreeData();
288 $this->nodeSortValues = array_flip($this->itemWhiteList);
289
290 $this->columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
291 if (isset($this->columnConfiguration['foreign_table']) && $this->columnConfiguration['foreign_table'] != $this->getTableName()) {
292 throw new InvalidArgumentException(
293 'TCA Tree configuration is invalid: tree for different node-Tables is not implemented yet',
294 '1290944650'
295 );
296 }
297
298 $this->treeData = t3lib_div::makeInstance('t3lib_tree_Node');
299 $this->treeData->setId($this->getRootUid());
300 $this->treeData->setParentNode(NULL);
301 $childNodes = $this->getChildrenOf($this->treeData, 0);
302 if ($childNodes !== NULL) {
303 $this->treeData->setChildNodes($childNodes);
304 }
305 }
306
307 /**
308 * Gets node children
309 *
310 * @param t3lib_tree_Node $node
311 * @param $level
312 * @return A|null|object
313 */
314 protected function getChildrenOf(t3lib_tree_Node $node, $level) {
315 $nodeData = NULL;
316 if ($node->getId() !== 0) {
317 $nodeData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
318 '*',
319 $this->tableName,
320 'uid=' . $node->getId()
321 );
322 }
323 if ($nodeData == NULL) {
324 $nodeData = array(
325 'uid' => 0,
326 $this->getLookupField() => '',
327 );
328 }
329 $storage = NULL;
330 $children = $this->getRelatedRecords($nodeData);
331 if (count($children)) {
332 $storage = t3lib_div::makeInstance('t3lib_tree_NodeCollection');
333 foreach ($children as $child) {
334 $node = t3lib_div::makeInstance('t3lib_tree_Node');
335 ;
336 $node->setId($child);
337 if ($level <= $this->levelMaximum) {
338 $children = $this->getChildrenOf($node, $level + 1);
339 if ($children !== NULL) {
340 $node->setChildNodes($children);
341 }
342 }
343 $storage->append($node);
344 }
345 }
346
347 return $storage;
348 }
349
350 /**
351 * Gets related records depending on TCA configuration
352 *
353 * @param $row
354 * @return array
355 */
356 protected function getRelatedRecords(array $row) {
357 if ($this->getLookupMode() == t3lib_tree_tca_DatabaseTreeDataProvider::MODE_PARENT) {
358 $children = $this->getChildrenUidsFromParentRelation($row);
359 } else {
360 $children = $this->getChildrenUidsFromChildrenRelation($row);
361 }
362
363 $allowedArray = array();
364 foreach ($children as $child) {
365 if (!in_array($child, $this->idCache) && in_array($child, $this->itemWhiteList)) {
366 $allowedArray[] = $child;
367 }
368 }
369
370 $this->idCache = array_merge($this->idCache, $allowedArray);
371
372 return $allowedArray;
373 }
374
375 /**
376 * Gets related records depending on TCA configuration
377 *
378 * @param $row
379 * @return array
380 */
381 protected function getChildrenUidsFromParentRelation(array $row) {
382 $uid = $row['uid'];
383
384 switch ((string) $this->columnConfiguration['type']) {
385 case 'inline':
386 case 'select':
387 if ($this->columnConfiguration['MM']) {
388 $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
389 // dummy field for setting "look from other site"
390 $this->columnConfiguration['MM_oppositeField'] = 'children';
391
392 $dbGroup->start(
393 $row[$this->getLookupField()],
394 $this->getTableName(),
395 $this->columnConfiguration['MM'],
396 $uid,
397 $this->getTableName(),
398 $this->columnConfiguration
399 );
400
401 $relatedUids = $dbGroup->tableArray[$this->getTableName()];
402 } elseif ($this->columnConfiguration['foreign_field']) {
403 $relatedUids = $this->listFieldQuery($this->columnConfiguration['foreign_field'], $uid);
404 } else {
405 $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
406 }
407 break;
408 default:
409 $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
410 }
411
412 return $relatedUids;
413 }
414
415 /**
416 * Gets related children records depending on TCA configuration
417 *
418 * @param $row
419 * @return array
420 */
421 protected function getChildrenUidsFromChildrenRelation(array $row) {
422 $relatedUids = array();
423 $uid = $row['uid'];
424 $value = $row[$this->getLookupField()];
425
426 switch ((string) $this->columnConfiguration['type']) {
427 case 'inline':
428 case 'select':
429 if ($this->columnConfiguration['MM']) {
430 $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
431 $dbGroup->start(
432 $value,
433 $this->getTableName(),
434 $this->columnConfiguration['MM'],
435 $uid,
436 $this->getTableName(),
437 $this->columnConfiguration
438 );
439
440 $relatedUids = $dbGroup->tableArray[$this->getTableName()];
441 } elseif ($this->columnConfiguration['foreign_field']) {
442 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
443 'uid',
444 $this->getTableName(),
445 $this->columnConfiguration['foreign_field'] . '=' . intval($uid)
446 );
447 foreach ($records as $record) {
448 $relatedUids[] = $record['uid'];
449 }
450 } else {
451 $relatedUids = t3lib_div::intExplode(',', $value, TRUE);
452 }
453 break;
454 default:
455 $relatedUids = t3lib_div::intExplode(',', $value, TRUE);
456 }
457
458 return $relatedUids;
459 }
460
461 /**
462 * Queries the table for an field which might contain a list.
463 *
464 * @param string $fieldName the name of the field to be queried
465 * @param int $queryId the uid to search for
466 *
467 * @return int[] all uids found
468 */
469 protected function listFieldQuery($fieldName, $queryId) {
470 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
471 'uid',
472 $this->getTableName(),
473 $GLOBALS['TYPO3_DB']->listQuery($fieldName, intval($queryId), $this->getTableName())
474 . (intval($queryId) == 0 ? (' OR ' . $fieldName . ' = \'\'') : '')
475 );
476 $uidArray = array();
477 foreach ($records as $record) {
478 $uidArray[] = $record['uid'];
479 }
480 return $uidArray;
481 }
482 }
483
484 ?>