[TASK] Use simple file backend for core php cache
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_treeview.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
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 * Contains base class for creating a browsable array/page/folder tree in HTML
29 *
30 * Revised for TYPO3 3.6 November/2003 by Kasper Skårhøj
31 *
32 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
33 * @coauthor René Fritz <r.fritz@colorcube.de>
34 */
35
36 /**
37 * Base class for creating a browsable array/page/folder tree in HTML
38 *
39 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
40 * @coauthor René Fritz <r.fritz@colorcube.de>
41 * @package TYPO3
42 * @subpackage t3lib
43 * @see t3lib_browsetree, t3lib_pagetree, t3lib_foldertree
44 */
45 class t3lib_treeView {
46
47 // EXTERNAL, static:
48 // If set, the first element in the tree is always expanded.
49 var $expandFirst = 0;
50 // If set, then ALL items will be expanded, regardless of stored settings.
51 var $expandAll = 0;
52 // Holds the current script to reload to.
53 var $thisScript = '';
54 // Which HTML attribute to use: alt/title. See init().
55 var $titleAttrib = 'title';
56 // If TRUE, no context menu is rendered on icons. If set to "titlelink" the
57 // icon is linked as the title is.
58 var $ext_IconMode = FALSE;
59 // If set, the id of the mounts will be added to the internal ids array
60 var $addSelfId = 0;
61 // Used if the tree is made of records (not folders for ex.)
62 var $title = 'no title';
63 // If TRUE, a default title attribute showing the UID of the record is shown.
64 // This cannot be enabled by default because it will destroy many applications
65 // where another title attribute is in fact applied later.
66 var $showDefaultTitleAttribute = FALSE;
67 // If TRUE, pages containing child records which has versions will be
68 // highlighted in yellow. This might be too expensive in terms
69 // of processing power.
70 var $highlightPagesWithVersions = TRUE;
71
72 /**
73 * Needs to be initialized with $GLOBALS['BE_USER']
74 * Done by default in init()
75 *
76 * @var t3lib_beUserAuth
77 */
78 var $BE_USER = '';
79
80 /**
81 * Needs to be initialized with e.g. $GLOBALS['WEBMOUNTS']
82 * Default setting in init() is 0 => 0
83 * The keys are mount-ids (can be anything basically) and the
84 * values are the ID of the root element (COULD be zero or anything else.
85 * For pages that would be the uid of the page, zero for the pagetree root.)
86 */
87 var $MOUNTS = '';
88
89 /**
90 * Database table to get the tree data from.
91 * Leave blank if data comes from an array.
92 */
93 var $table = '';
94
95 /**
96 * Defines the field of $table which is the parent id field (like pid for table pages).
97 */
98 var $parentField = 'pid';
99
100 /**
101 * WHERE clause used for selecting records for the tree. Is set by function init.
102 * Only makes sense when $this->table is set.
103 * @see init()
104 */
105 var $clause = '';
106
107 /**
108 * Field for ORDER BY. Is set by function init.
109 * Only makes sense when $this->table is set.
110 * @see init()
111 */
112 var $orderByFields = '';
113
114 /**
115 * Default set of fields selected from the tree table.
116 * Make SURE that these fields names listed herein are actually possible to select from $this->table (if that variable is set to a TCA table name)
117 * @see addField()
118 */
119 var $fieldArray = array('uid', 'title');
120
121 /**
122 * List of other fields which are ALLOWED to set (here, based on the "pages" table!)
123 * @see addField()
124 */
125 var $defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id';
126
127 /**
128 * Unique name for the tree.
129 * Used as key for storing the tree into the BE users settings.
130 * Used as key to pass parameters in links.
131 * MUST NOT contain underscore chars.
132 * etc.
133 */
134 var $treeName = '';
135
136 /**
137 * A prefix for table cell id's which will be wrapped around an item.
138 * Can be used for highlighting by JavaScript.
139 * Needs to be unique if multiple trees are on one HTML page.
140 * @see printTree()
141 */
142 var $domIdPrefix = 'row';
143
144 /**
145 * Back path for icons
146 */
147 var $backPath;
148
149 /**
150 * Icon file path.
151 */
152 var $iconPath = '';
153
154 /**
155 * Icon file name for item icons.
156 */
157 var $iconName = 'default.gif';
158
159 /**
160 * If TRUE, HTML code is also accumulated in ->tree array during rendering of the tree.
161 * If 2, then also the icon prefix code (depthData) is stored
162 */
163 var $makeHTML = 1;
164
165 /**
166 * If TRUE, records as selected will be stored internally in the ->recs array
167 */
168 var $setRecs = 0;
169
170 /**
171 * Sets the associative array key which identifies a new sublevel if arrays are used for trees.
172 * This value has formerly been "subLevel" and "--sublevel--"
173 */
174 var $subLevelID = '_SUB_LEVEL';
175
176 // *********
177 // Internal
178 // *********
179 // For record trees:
180 // one-dim array of the uid's selected.
181 var $ids = array();
182 // The hierarchy of element uids
183 var $ids_hierarchy = array();
184 // The hierarchy of versioned element uids
185 var $orig_ids_hierarchy = array();
186 // Temporary, internal array
187 var $buffer_idH = array();
188
189 // For FOLDER trees:
190 // Special UIDs for folders (integer-hashes of paths)
191 var $specUIDmap = array();
192
193 // For arrays:
194 // Holds the input data array
195 var $data = FALSE;
196 // Holds an index with references to the data array.
197 var $dataLookup = FALSE;
198
199 // For both types
200 // Tree is accumulated in this variable
201 var $tree = array();
202 // Holds (session stored) information about which items in the tree are unfolded and which are not.
203 var $stored = array();
204 // Points to the current mountpoint key
205 var $bank = 0;
206 // Accumulates the displayed records.
207 var $recs = array();
208
209 /**
210 * Initialize the tree class. Needs to be overwritten
211 * Will set ->fieldsArray, ->backPath and ->clause
212 *
213 * @param string Record WHERE clause
214 * @param string Record ORDER BY field
215 * @return void
216 */
217 function init($clause = '', $orderByFields = '') {
218 // Setting BE_USER by default
219 $this->BE_USER = $GLOBALS['BE_USER'];
220 // Setting title attribute to use.
221 $this->titleAttrib = 'title';
222 // Setting backpath.
223 $this->backPath = $GLOBALS['BACK_PATH'];
224
225 // Setting clause
226 if ($clause) {
227 $this->clause = $clause;
228 }
229 if ($orderByFields) {
230 $this->orderByFields = $orderByFields;
231 }
232
233 if (!is_array($this->MOUNTS)) {
234 // Dummy
235 $this->MOUNTS = array(0 => 0);
236 }
237
238 $this->setTreeName();
239
240 if ($this->table) {
241 t3lib_div::loadTCA($this->table);
242 }
243
244 // Setting this to FALSE disables the use of array-trees by default
245 $this->data = FALSE;
246 $this->dataLookup = FALSE;
247 }
248
249
250 /**
251 * Sets the tree name which is used to identify the tree
252 * Used for JavaScript and other things
253 *
254 * @param string $treeName Default is the table name. Underscores are stripped.
255 * @return void
256 */
257 function setTreeName($treeName = '') {
258 $this->treeName = $treeName ? $treeName : $this->treeName;
259 $this->treeName = $this->treeName ? $this->treeName : $this->table;
260 $this->treeName = str_replace('_', '', $this->treeName);
261 }
262
263 /**
264 * Adds a fieldname to the internal array ->fieldArray
265 *
266 * @param string $field Field name to
267 * @param boolean $noCheck If set, the fieldname will be set no matter what. Otherwise the field name must either be found as key in $GLOBALS['TCA'][$table]['columns'] or in the list ->defaultList
268 * @return void
269 */
270 function addField($field, $noCheck = 0) {
271 if ($noCheck || is_array($GLOBALS['TCA'][$this->table]['columns'][$field]) || t3lib_div::inList($this->defaultList, $field)) {
272 $this->fieldArray[] = $field;
273 }
274 }
275
276 /**
277 * Resets the tree, recs, ids, ids_hierarchy and orig_ids_hierarchy internal variables. Use it if you need it.
278 *
279 * @return void
280 */
281 function reset() {
282 $this->tree = array();
283 $this->recs = array();
284 $this->ids = array();
285 $this->ids_hierarchy = array();
286 $this->orig_ids_hierarchy = array();
287 }
288
289 /*******************************************
290 *
291 * output
292 *
293 *******************************************/
294
295 /**
296 * Will create and return the HTML code for a browsable tree
297 * Is based on the mounts found in the internal array ->MOUNTS (set in the constructor)
298 *
299 * @return string HTML code for the browsable tree
300 */
301 function getBrowsableTree() {
302
303 // Get stored tree structure AND updating it if needed according to incoming PM GET var.
304 $this->initializePositionSaving();
305
306 // Init done:
307 $titleLen = intval($this->BE_USER->uc['titleLen']);
308 $treeArr = array();
309
310 // Traverse mounts:
311 foreach ($this->MOUNTS as $idx => $uid) {
312
313 // Set first:
314 $this->bank = $idx;
315 $isOpen = $this->stored[$idx][$uid] || $this->expandFirst;
316
317 // Save ids while resetting everything else.
318 $curIds = $this->ids;
319 $this->reset();
320 $this->ids = $curIds;
321
322 // Set PM icon for root of mount:
323 $cmd = $this->bank . '_' . ($isOpen ? '0_' : '1_') . $uid . '_' . $this->treeName;
324 $icon = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . ($isOpen ? 'minus' : 'plus') . 'only.gif', 'width="18" height="16"') . ' alt="" />';
325 $firstHtml = $this->PM_ATagWrap($icon, $cmd);
326
327 // Preparing rootRec for the mount
328 if ($uid) {
329 $rootRec = $this->getRecord($uid);
330 $firstHtml .= $this->getIcon($rootRec);
331 } else {
332 // Artificial record for the tree root, id=0
333 $rootRec = $this->getRootRecord($uid);
334 $firstHtml .= $this->getRootIcon($rootRec);
335 }
336
337 if (is_array($rootRec)) {
338 // In case it was swapped inside getRecord due to workspaces.
339 $uid = $rootRec['uid'];
340
341 // Add the root of the mount to ->tree
342 $this->tree[] = array('HTML' => $firstHtml, 'row' => $rootRec, 'bank' => $this->bank);
343
344 // If the mount is expanded, go down:
345 if ($isOpen) {
346 // Set depth:
347 $depthD = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/blank.gif', 'width="18" height="16"') . ' alt="" />';
348 if ($this->addSelfId) {
349 $this->ids[] = $uid;
350 }
351 $this->getTree($uid, 999, $depthD, '', $rootRec['_SUBCSSCLASS']);
352 }
353
354 // Add tree:
355 $treeArr = array_merge($treeArr, $this->tree);
356 }
357 }
358 return $this->printTree($treeArr);
359 }
360
361 /**
362 * Compiles the HTML code for displaying the structure found inside the ->tree array
363 *
364 * @param array $treeArr "tree-array" - if blank string, the internal ->tree array is used.
365 * @return string The HTML code for the tree
366 */
367 function printTree($treeArr = '') {
368 $titleLen = intval($this->BE_USER->uc['titleLen']);
369 if (!is_array($treeArr)) {
370 $treeArr = $this->tree;
371 }
372 $out = '';
373
374 // put a table around it with IDs to access the rows from JS
375 // not a problem if you don't need it
376 // In XHTML there is no "name" attribute of <td> elements -
377 // but Mozilla will not be able to highlight rows if the name
378 // attribute is NOT there.
379 $out .= '
380
381 <!--
382 TYPO3 tree structure.
383 -->
384 <table cellpadding="0" cellspacing="0" border="0" id="typo3-tree">';
385
386 foreach ($treeArr as $k => $v) {
387 $idAttr = htmlspecialchars($this->domIdPrefix . $this->getId($v['row']) . '_' . $v['bank']);
388
389 $out .= '
390 <tr>
391 <td id="' . $idAttr . '"' .
392 ($v['row']['_CSSCLASS'] ? ' class="' . $v['row']['_CSSCLASS'] . '"' : '') . '>' .
393 $v['HTML'] .
394 $this->wrapTitle($this->getTitleStr($v['row'], $titleLen), $v['row'], $v['bank']) .
395 '</td>
396 </tr>
397 ';
398 }
399 $out .= '
400 </table>';
401 return $out;
402 }
403
404 /*******************************************
405 *
406 * rendering parts
407 *
408 *******************************************/
409
410 /**
411 * Generate the plus/minus icon for the browsable tree.
412 *
413 * @param array $row Record for the entry
414 * @param integer $a The current entry number
415 * @param integer $c The total number of entries. If equal to $a, a "bottom" element is returned.
416 * @param integer $nextCount The number of sub-elements to the current element.
417 * @param boolean $exp The element was expanded to render subelements if this flag is set.
418 * @return string Image tag with the plus/minus icon.
419 * @access private
420 * @see t3lib_pageTree::PMicon()
421 */
422 function PMicon($row, $a, $c, $nextCount, $exp) {
423 $PM = $nextCount ? ($exp ? 'minus' : 'plus') : 'join';
424 $BTM = ($a == $c) ? 'bottom' : '';
425 $icon = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $PM . $BTM . '.gif', 'width="18" height="16"') . ' alt="" />';
426
427 if ($nextCount) {
428 $cmd = $this->bank . '_' . ($exp ? '0_' : '1_') . $row['uid'] . '_' . $this->treeName;
429 $bMark = ($this->bank . '_' . $row['uid']);
430 $icon = $this->PM_ATagWrap($icon, $cmd, $bMark);
431 }
432 return $icon;
433 }
434
435 /**
436 * Wrap the plus/minus icon in a link
437 *
438 * @param string $icon HTML string to wrap, probably an image tag.
439 * @param string $cmd Command for 'PM' get var
440 * @param boolean $bMark If set, the link will have a anchor point (=$bMark) and a name attribute (=$bMark)
441 * @return string Link-wrapped input string
442 * @access private
443 */
444 function PM_ATagWrap($icon, $cmd, $bMark = '') {
445 if ($this->thisScript) {
446 if ($bMark) {
447 $anchor = '#' . $bMark;
448 $name = ' name="' . $bMark . '"';
449 }
450 $aUrl = $this->thisScript . '?PM=' . $cmd . $anchor;
451 return '<a href="' . htmlspecialchars($aUrl) . '"' . $name . '>' . $icon . '</a>';
452 } else {
453 return $icon;
454 }
455 }
456
457 /**
458 * Wrapping $title in a-tags.
459 *
460 * @param string $title Title string
461 * @param string $row Item record
462 * @param integer $bank Bank pointer (which mount point number)
463 * @return string
464 * @access private
465 */
466 function wrapTitle($title, $row, $bank = 0) {
467 $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($row) . '\',this,\'' . $this->domIdPrefix . $this->getId($row) . '\',' . $bank . ');';
468 return '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $title . '</a>';
469 }
470
471 /**
472 * Wrapping the image tag, $icon, for the row, $row (except for mount points)
473 *
474 * @param string $icon The image tag for the icon
475 * @param array $row The row for the current element
476 * @return string The processed icon input value.
477 * @access private
478 */
479 function wrapIcon($icon, $row) {
480 return $icon;
481 }
482
483 /**
484 * Adds attributes to image tag.
485 *
486 * @param string $icon Icon image tag
487 * @param string $attr Attributes to add, eg. ' border="0"'
488 * @return string Image tag, modified with $attr attributes added.
489 */
490 function addTagAttributes($icon, $attr) {
491 return preg_replace('/ ?\/?>$/', '', $icon) . ' ' . $attr . ' />';
492 }
493
494 /**
495 * Adds a red "+" to the input string, $str, if the field "php_tree_stop" in the $row (pages) is set
496 *
497 * @param string $str Input string, like a page title for the tree
498 * @param array $row record row with "php_tree_stop" field
499 * @return string Modified string
500 * @access private
501 */
502 function wrapStop($str, $row) {
503 if ($row['php_tree_stop']) {
504 $str .= '<span class="typo3-red"><a href="' . htmlspecialchars(t3lib_div::linkThisScript(array('setTempDBmount' => $row['uid']))) . '" class="typo3-red">+</a> </span>';
505 }
506 return $str;
507 }
508
509 /*******************************************
510 *
511 * tree handling
512 *
513 *******************************************/
514
515 /**
516 * Returns TRUE/FALSE if the next level for $id should be expanded - based on
517 * data in $this->stored[][] and ->expandAll flag.
518 * Extending parent function
519 *
520 * @param integer $id Record id/key
521 * @return boolean
522 * @access private
523 * @see t3lib_pageTree::expandNext()
524 */
525 function expandNext($id) {
526 return ($this->stored[$this->bank][$id] || $this->expandAll) ? 1 : 0;
527 }
528
529 /**
530 * Get stored tree structure AND updating it if needed according to incoming PM GET var.
531 *
532 * @return void
533 * @access private
534 */
535 function initializePositionSaving() {
536 // Get stored tree structure:
537 $this->stored = unserialize($this->BE_USER->uc['browseTrees'][$this->treeName]);
538
539 // PM action
540 // (If an plus/minus icon has been clicked, the PM GET var is sent and we
541 // must update the stored positions in the tree):
542 // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
543 $PM = explode('_', t3lib_div::_GP('PM'));
544 if (count($PM) == 4 && $PM[3] == $this->treeName) {
545 if (isset($this->MOUNTS[$PM[0]])) {
546 // set
547 if ($PM[1]) {
548 $this->stored[$PM[0]][$PM[2]] = 1;
549 $this->savePosition();
550 // Clear
551 } else {
552 unset($this->stored[$PM[0]][$PM[2]]);
553 $this->savePosition();
554 }
555 }
556 }
557 }
558
559 /**
560 * Saves the content of ->stored (keeps track of expanded positions in the tree)
561 * $this->treeName will be used as key for BE_USER->uc[] to store it in
562 *
563 * @return void
564 * @access private
565 */
566 function savePosition() {
567 $this->BE_USER->uc['browseTrees'][$this->treeName] = serialize($this->stored);
568 $this->BE_USER->writeUC();
569 }
570
571 /******************************
572 *
573 * Functions that might be overwritten by extended classes
574 *
575 ********************************/
576
577 /**
578 * Returns the root icon for a tree/mountpoint (defaults to the globe)
579 *
580 * @param array $rec Record for root.
581 * @return string Icon image tag.
582 */
583 function getRootIcon($rec) {
584 return $this->wrapIcon(t3lib_iconWorks::getSpriteIcon('apps-pagetree-root'), $rec);
585 }
586
587 /**
588 * Get icon for the row.
589 * If $this->iconPath and $this->iconName is set, try to get icon based on those values.
590 *
591 * @param array $row Item row.
592 * @return string Image tag.
593 */
594 function getIcon($row) {
595 if ($this->iconPath && $this->iconName) {
596 $icon = '<img' . t3lib_iconWorks::skinImg('', $this->iconPath . $this->iconName, 'width="18" height="16"') . ' alt=""' . ($this->showDefaultTitleAttribute ? ' title="UID: ' . $row['uid'] . '"' : '') . ' />';
597 } else {
598
599 $icon = t3lib_iconWorks::getSpriteIconForRecord($this->table, $row, array(
600 'title' => ($this->showDefaultTitleAttribute ? 'UID: ' . $row['uid'] : $this->getTitleAttrib($row)),
601 'class' => 'c-recIcon'
602 ));
603
604 }
605
606 return $this->wrapIcon($icon, $row);
607 }
608
609
610 /**
611 * Returns the title for the input record. If blank, a "no title" label (localized) will be returned.
612 * Do NOT htmlspecialchar the string from this function - has already been done.
613 *
614 * @param array $row The input row array (where the key "title" is used for the title)
615 * @param integer $titleLen Title length (30)
616 * @return string The title.
617 */
618 function getTitleStr($row, $titleLen = 30) {
619 if ($this->ext_showNavTitle && strlen(trim($row['nav_title'])) > 0) {
620 $title = '<span title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_tca.xml:title', 1) . ' ' . htmlspecialchars(trim($row['title'])) . '">' . htmlspecialchars(t3lib_div::fixed_lgd_cs($row['nav_title'], $titleLen)) . '</span>';
621 } else {
622 $title = htmlspecialchars(t3lib_div::fixed_lgd_cs($row['title'], $titleLen));
623 if (strlen(trim($row['nav_title'])) > 0) {
624 $title = '<span title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/locallang_tca.xml:pages.nav_title', 1) . ' ' . htmlspecialchars(trim($row['nav_title'])) . '">' . $title . '</span>';
625 }
626 $title = (strlen(trim($row['title'])) == 0) ? '<em>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.no_title', 1) . ']</em>' : $title;
627 }
628
629 return $title;
630 }
631
632 /**
633 * Returns the value for the image "title" attribute
634 *
635 * @param array $row The input row array (where the key "title" is used for the title)
636 * @return string The attribute value (is htmlspecialchared() already)
637 * @see wrapIcon()
638 */
639 function getTitleAttrib($row) {
640 return htmlspecialchars($row['title']);
641 }
642
643 /**
644 * Returns the id from the record (typ. uid)
645 *
646 * @param array $row Record array
647 * @return integer The "uid" field value.
648 */
649 function getId($row) {
650 return $row['uid'];
651 }
652
653 /**
654 * Returns jump-url parameter value.
655 *
656 * @param array $row The record array.
657 * @return string The jump-url parameter.
658 */
659 function getJumpToParam($row) {
660 return $this->getId($row);
661 }
662
663 /********************************
664 *
665 * tree data buidling
666 *
667 ********************************/
668
669 /**
670 * Fetches the data for the tree
671 *
672 * @param integer $uid item id for which to select subitems (parent id)
673 * @param integer $depth Max depth (recursivity limit)
674 * @param string $depthData HTML-code prefix for recursive calls.
675 * @param string $blankLineCode ? (internal)
676 * @param string $subCSSclass CSS class to use for <td> sub-elements
677 * @return integer The count of items on the level
678 */
679 function getTree($uid, $depth = 999, $depthData = '', $blankLineCode = '', $subCSSclass = '') {
680
681 // Buffer for id hierarchy is reset:
682 $this->buffer_idH = array();
683
684 // Init vars
685 $depth = intval($depth);
686 $HTML = '';
687 $a = 0;
688
689 $res = $this->getDataInit($uid, $subCSSclass);
690 $c = $this->getDataCount($res);
691 $crazyRecursionLimiter = 999;
692
693 $idH = array();
694
695 // Traverse the records:
696 while ($crazyRecursionLimiter > 0 && $row = $this->getDataNext($res, $subCSSclass)) {
697 $a++;
698 $crazyRecursionLimiter--;
699
700 $newID = $row['uid'];
701
702 if ($newID == 0) {
703 throw new RuntimeException('Endless recursion detected: TYPO3 has detected an error in the database. Please fix it manually (e.g. using phpMyAdmin) and change the UID of ' . $this->table . ':0 to a new value.<br /><br />See <a href="http://bugs.typo3.org/view.php?id=3495" target="_blank">bugs.typo3.org/view.php?id=3495</a> to get more information about a possible cause.', 1294586383);
704 }
705
706 // Reserve space.
707 $this->tree[] = array();
708 end($this->tree);
709 // Get the key for this space
710 $treeKey = key($this->tree);
711 $LN = ($a == $c) ? 'blank' : 'line';
712
713 // If records should be accumulated, do so
714 if ($this->setRecs) {
715 $this->recs[$row['uid']] = $row;
716 }
717
718 // Accumulate the id of the element in the internal arrays
719 $this->ids[] = $idH[$row['uid']]['uid'] = $row['uid'];
720 $this->ids_hierarchy[$depth][] = $row['uid'];
721 $this->orig_ids_hierarchy[$depth][] = $row['_ORIG_uid'] ? $row['_ORIG_uid'] : $row['uid'];
722
723 // Make a recursive call to the next level
724 $HTML_depthData = $depthData . '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $LN . '.gif', 'width="18" height="16"') . ' alt="" />';
725 if ($depth > 1 && $this->expandNext($newID) && !$row['php_tree_stop']) {
726 $nextCount = $this->getTree(
727 $newID,
728 $depth - 1,
729 $this->makeHTML ? $HTML_depthData : '',
730 $blankLineCode . ',' . $LN,
731 $row['_SUBCSSCLASS']
732 );
733 if (count($this->buffer_idH)) {
734 $idH[$row['uid']]['subrow'] = $this->buffer_idH;
735 }
736 // Set "did expand" flag
737 $exp = 1;
738 } else {
739 $nextCount = $this->getCount($newID);
740 // Clear "did expand" flag
741 $exp = 0;
742 }
743
744 // Set HTML-icons, if any:
745 if ($this->makeHTML) {
746 $HTML = $depthData . $this->PMicon($row, $a, $c, $nextCount, $exp);
747 $HTML .= $this->wrapStop($this->getIcon($row), $row);
748 }
749
750 // Finally, add the row/HTML content to the ->tree array in the reserved key.
751 $this->tree[$treeKey] = array(
752 'row' => $row,
753 'HTML' => $HTML,
754 'HTML_depthData' => $this->makeHTML == 2 ? $HTML_depthData : '',
755 'invertedDepth' => $depth,
756 'blankLineCode' => $blankLineCode,
757 'bank' => $this->bank
758 );
759 }
760
761 $this->getDataFree($res);
762 $this->buffer_idH = $idH;
763 return $c;
764 }
765
766 /********************************
767 *
768 * Data handling
769 * Works with records and arrays
770 *
771 ********************************/
772
773 /**
774 * Returns the number of records having the parent id, $uid
775 *
776 * @param integer $uid Id to count subitems for
777 * @return integer
778 * @access private
779 */
780 function getCount($uid) {
781 if (is_array($this->data)) {
782 $res = $this->getDataInit($uid);
783 return $this->getDataCount($res);
784 } else {
785 return $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
786 'uid',
787 $this->table,
788 $this->parentField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($uid, $this->table) .
789 t3lib_BEfunc::deleteClause($this->table) .
790 t3lib_BEfunc::versioningPlaceholderClause($this->table) .
791 $this->clause // whereClauseMightContainGroupOrderBy
792 );
793 }
794 }
795
796 /**
797 * Returns root record for uid (<=0)
798 *
799 * @param integer $uid uid, <= 0 (normally, this does not matter)
800 * @return array Array with title/uid keys with values of $this->title/0 (zero)
801 */
802 function getRootRecord($uid) {
803 return array('title' => $this->title, 'uid' => 0);
804 }
805
806 /**
807 * Returns the record for a uid.
808 * For tables: Looks up the record in the database.
809 * For arrays: Returns the fake record for uid id.
810 *
811 * @param integer $uid UID to look up
812 * @return array The record
813 */
814 function getRecord($uid) {
815 if (is_array($this->data)) {
816 return $this->dataLookup[$uid];
817 } else {
818 return t3lib_BEfunc::getRecordWSOL($this->table, $uid);
819 }
820 }
821
822 /**
823 * Getting the tree data: Selecting/Initializing data pointer to items for a certain parent id.
824 * For tables: This will make a database query to select all children to "parent"
825 * For arrays: This will return key to the ->dataLookup array
826 *
827 * @param integer $parentId parent item id
828 * @param string $subCSSclass Class for sub-elements.
829 * @return mixed Data handle (Tables: An sql-resource, arrays: A parentId integer. -1 is returned if there were NO subLevel.)
830 * @access private
831 */
832 function getDataInit($parentId, $subCSSclass = '') {
833 if (is_array($this->data)) {
834 if (!is_array($this->dataLookup[$parentId][$this->subLevelID])) {
835 $parentId = -1;
836 } else {
837 reset($this->dataLookup[$parentId][$this->subLevelID]);
838 }
839 return $parentId;
840 } else {
841 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
842 implode(',', $this->fieldArray),
843 $this->table,
844 $this->parentField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($parentId, $this->table) .
845 t3lib_BEfunc::deleteClause($this->table) .
846 t3lib_BEfunc::versioningPlaceholderClause($this->table) .
847 $this->clause, // whereClauseMightContainGroupOrderBy
848 '',
849 $this->orderByFields
850 );
851 return $res;
852 }
853 }
854
855 /**
856 * Getting the tree data: Counting elements in resource
857 *
858 * @param mixed $res Data handle
859 * @return integer number of items
860 * @access private
861 * @see getDataInit()
862 */
863 function getDataCount(&$res) {
864 if (is_array($this->data)) {
865 return count($this->dataLookup[$res][$this->subLevelID]);
866 } else {
867 $c = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
868 return $c;
869 }
870 }
871
872 /**
873 * Getting the tree data: next entry
874 *
875 * @param mixed $res Data handle
876 * @param string $subCSSclass CSS class for sub elements (workspace related)
877 * @return array item data array OR FALSE if end of elements.
878 * @access private
879 * @see getDataInit()
880 */
881 function getDataNext(&$res, $subCSSclass = '') {
882 if (is_array($this->data)) {
883 if ($res < 0) {
884 $row = FALSE;
885 } else {
886 list(, $row) = each($this->dataLookup[$res][$this->subLevelID]);
887
888 // Passing on default <td> class for subelements:
889 if (is_array($row) && $subCSSclass !== '') {
890 $row['_CSSCLASS'] = $row['_SUBCSSCLASS'] = $subCSSclass;
891 }
892 }
893 return $row;
894 } else {
895 while ($row = @$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
896 t3lib_BEfunc::workspaceOL($this->table, $row, $this->BE_USER->workspace, TRUE);
897 if (is_array($row)) {
898 break;
899 }
900 }
901
902 // Passing on default <td> class for subelements:
903 if (is_array($row) && $subCSSclass !== '') {
904
905 if ($this->table === 'pages' && $this->highlightPagesWithVersions && !isset($row['_CSSCLASS']) && count(t3lib_BEfunc::countVersionsOfRecordsOnPage($this->BE_USER->workspace, $row['uid']))) {
906 $row['_CSSCLASS'] = 'ver-versions';
907 }
908
909 if (!isset($row['_CSSCLASS'])) {
910 $row['_CSSCLASS'] = $subCSSclass;
911 }
912 if (!isset($row['_SUBCSSCLASS'])) {
913 $row['_SUBCSSCLASS'] = $subCSSclass;
914 }
915 }
916
917 return $row;
918 }
919 }
920
921 /**
922 * Getting the tree data: frees data handle
923 *
924 * @param mixed $res Data handle
925 * @return void
926 * @access private
927 */
928 function getDataFree(&$res) {
929 if (!is_array($this->data)) {
930 $GLOBALS['TYPO3_DB']->sql_free_result($res);
931 }
932 }
933
934 /**
935 * Used to initialize class with an array to browse.
936 * The array inputted will be traversed and an internal index for lookup is created.
937 * The keys of the input array are perceived as "uid"s of records which means that keys GLOBALLY must be unique like uids are.
938 * "uid" and "pid" "fakefields" are also set in each record.
939 * All other fields are optional.
940 *
941 * @param array $dataArr The input array, see examples below in this script.
942 * @param boolean $traverse Internal, for recursion.
943 * @param integer $pid Internal, for recursion.
944 * @return void
945 */
946 function setDataFromArray(&$dataArr, $traverse = FALSE, $pid = 0) {
947 if (!$traverse) {
948 $this->data = &$dataArr;
949 $this->dataLookup = array();
950 // Add root
951 $this->dataLookup[0][$this->subLevelID] =& $dataArr;
952 }
953
954 foreach ($dataArr as $uid => $val) {
955
956 $dataArr[$uid]['uid'] = $uid;
957 $dataArr[$uid]['pid'] = $pid;
958
959 // Gives quick access to id's
960 $this->dataLookup[$uid] = &$dataArr[$uid];
961
962 if (is_array($val[$this->subLevelID])) {
963 $this->setDataFromArray($dataArr[$uid][$this->subLevelID], TRUE, $uid);
964 }
965 }
966 }
967
968 /**
969 * Sets the internal data arrays
970 *
971 * @param array $treeArr Content for $this->data
972 * @param array $treeLookupArr Content for $this->dataLookup
973 * @return void
974 */
975 function setDataFromTreeArray(&$treeArr, &$treeLookupArr) {
976 $this->data = &$treeArr;
977 $this->dataLookup =& $treeLookupArr;
978 }
979
980 /*
981 array(
982 [id1] => array(
983 'title'=>'title...',
984 'id' => 'id1',
985 'icon' => 'icon ref, relative to typo3/ folder...'
986 ),
987 [id2] => array(
988 'title'=>'title...',
989 'id' => 'id2',
990 'icon' => 'icon ref, relative to typo3/ folder...'
991 ),
992 [id3] => array(
993 'title'=>'title...',
994 'id' => 'id3',
995 'icon' => 'icon ref, relative to typo3/ folder...'
996 $this->subLevelID => array(
997 [id3_asdf#1] => array(
998 'title'=>'title...',
999 'id' => 'asdf#1',
1000 'icon' => 'icon ref, relative to typo3/ folder...'
1001 ),
1002 [5] => array(
1003 'title'=>'title...',
1004 'id' => 'id...',
1005 'icon' => 'icon ref, relative to typo3/ folder...'
1006 ),
1007 [6] => array(
1008 'title'=>'title...',
1009 'id' => 'id...',
1010 'icon' => 'icon ref, relative to typo3/ folder...'
1011 ),
1012 )
1013 ),
1014 )
1015 */
1016 }
1017
1018 ?>