protected function generateTree($table, $id, $arrPrevNext, $blnHasSorting, $intMargin=0, $arrClipboard=null, $blnCircularReference=false, $protectedPage=false, $blnNoRecursion=false, $arrFound=array())
	{
		/** @var AttributeBagInterface $objSessionBag */
		$objSessionBag = System::getContainer()->get('session')->getBag('contao_backend');

		$session = $objSessionBag->all();
		$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable.'_'.$table.'_tree' : $this->strTable.'_tree';

		// Toggle nodes
		if (Input::get('ptg'))
		{
			$session[$node][Input::get('ptg')] = (isset($session[$node][Input::get('ptg')]) && $session[$node][Input::get('ptg')] == 1) ? 0 : 1;
			$objSessionBag->replace($session);
			$this->redirect(preg_replace('/(&(amp;)?|\?)ptg=[^& ]*/i', '', Environment::get('request')));
		}

		$objRow = $this->Database->prepare("SELECT * FROM " . $table . " WHERE id=?")
								 ->limit(1)
								 ->execute($id);

		// Return if there is no result
		if ($objRow->numRows < 1)
		{
			$objSessionBag->replace($session);

			return '';
		}

		$return = '';
		$intSpacing = 20;
		$childs = array();

		// Add the ID to the list of current IDs
		if ($this->strTable == $table)
		{
			$this->current[] = $objRow->id;
		}

		// Check whether there are child records
		if (!$blnNoRecursion)
		{
			if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 || $this->strTable != $table)
			{
				$objChilds = $this->Database->prepare("SELECT id FROM " . $table . " WHERE pid=?" . (!empty($arrFound) ? " AND id IN(" . implode(',', array_map('\intval', $arrFound)) . ")" : '') . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($id);

				if ($objChilds->numRows)
				{
					$childs = $objChilds->fetchEach('id');
				}
			}
		}

		$blnProtected = false;

		// Check whether the page is protected
		if ($table == 'tl_page')
		{
			$blnProtected = ($objRow->protected || $protectedPage) ? true : false;
		}

		$session[$node][$id] = (\is_int($session[$node][$id])) ? $session[$node][$id] : 0;
		$mouseover = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 || $table == $this->strTable) ? ' toggle_select hover-div' : '';

		$return .= "\n  " . '<li class="'.((($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $objRow->type == 'root') || $table != $this->strTable) ? 'tl_folder' : 'tl_file').' click2edit'.$mouseover.' cf"><div class="tl_left" style="padding-left:'.($intMargin + $intSpacing).'px">';

		// Calculate label and add a toggle button
		$args = array();
		$folderAttribute = 'style="margin-left:20px"';
		$showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields'];
		$level = ($intMargin / $intSpacing + 1);
		$blnIsOpen = (!empty($arrFound) || $session[$node][$id] == 1);

		// Always show selected nodes
		if (!$blnIsOpen && !empty($this->arrPickerValue) && !empty(array_intersect($this->Database->getChildRecords(array($id), $this->strTable), $this->arrPickerValue)))
		{
			$blnIsOpen = true;
		}

		if (!empty($childs))
		{
			$folderAttribute = '';
			$img = $blnIsOpen ? 'folMinus.svg' : 'folPlus.svg';
			$alt = $blnIsOpen ? $GLOBALS['TL_LANG']['MSC']['collapseNode'] : $GLOBALS['TL_LANG']['MSC']['expandNode'];
			$return .= '<a href="'.$this->addToUrl('ptg='.$id).'" title="'.StringUtil::specialchars($alt).'" onclick="Backend.getScrollOffset();return AjaxRequest.toggleStructure(this,\''.$node.'_'.$id.'\','.$level.','.$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'].')">'.Image::getHtml($img, '', 'style="margin-right:2px"').'</a>';
		}

		foreach ($showFields as $k=>$v)
		{
			// Decrypt the value
			if ($GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['encrypt'])
			{
				$objRow->$v = Encryption::decrypt(StringUtil::deserialize($objRow->$v));
			}

			if (strpos($v, ':') !== false)
			{
				list($strKey, $strTable) = explode(':', $v);
				list($strTable, $strField) = explode('.', $strTable);

				$objRef = $this->Database->prepare("SELECT " . Database::quoteIdentifier($strField) . " FROM " . $strTable . " WHERE id=?")
										 ->limit(1)
										 ->execute($objRow->$strKey);

				$args[$k] = $objRef->numRows ? $objRef->$strField : '';
			}
			elseif (\in_array($GLOBALS['TL_DCA'][$table]['fields'][$v]['flag'], array(5, 6, 7, 8, 9, 10)))
			{
				$args[$k] = Date::parse(Config::get('datimFormat'), $objRow->$v);
			}
			elseif ($GLOBALS['TL_DCA'][$table]['fields'][$v]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['multiple'])
			{
				$args[$k] = ($objRow->$v != '') ? ($GLOBALS['TL_DCA'][$table]['fields'][$v]['label'][0] ?? $v) : '';
			}
			else
			{
				$args[$k] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$objRow->$v] ?: $objRow->$v;
			}
		}

		$label = vsprintf(((\strlen($GLOBALS['TL_DCA'][$table]['list']['label']['format'])) ? $GLOBALS['TL_DCA'][$table]['list']['label']['format'] : '%s'), $args);

		// Shorten the label if it is too long
		if ($GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'] > 0 && $GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'] < Utf8::strlen(strip_tags($label)))
		{
			$label = trim(StringUtil::substrHtml($label, $GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'])) . ' …';
		}

		$label = preg_replace('/\(\) ?|\[\] ?|\{\} ?|<> ?/', '', $label);

		// Call the label_callback ($row, $label, $this)
		if (\is_array($GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']))
		{
			$strClass = $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback'][0];
			$strMethod = $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback'][1];

			$this->import($strClass);
			$return .= $this->$strClass->$strMethod($objRow->row(), $label, $this, $folderAttribute, false, $blnProtected);
		}
		elseif (\is_callable($GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']))
		{
			$return .= $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']($objRow->row(), $label, $this, $folderAttribute, false, $blnProtected);
		}
		else
		{
			$return .= Image::getHtml('iconPLAIN.svg', '', $folderAttribute) . ' ' . $label;
		}

		$return .= '</div> <div class="tl_right">';
		$previous = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $arrPrevNext['pp'] : $arrPrevNext['p'];
		$next = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $arrPrevNext['nn'] : $arrPrevNext['n'];
		$_buttons = '';

		// Regular buttons ($row, $table, $root, $blnCircularReference, $childs, $previous, $next)
		if ($this->strTable == $table)
		{
			$_buttons .= (Input::get('act') == 'select') ? '<input type="checkbox" name="IDS[]" id="ids_'.$id.'" class="tl_tree_checkbox" value="'.$id.'">' : $this->generateButtons($objRow->row(), $table, $this->root, $blnCircularReference, $childs, $previous, $next);

			if ($this->strPickerFieldType)
			{
				$_buttons .= $this->getPickerInputField($id);
			}
		}

		// Paste buttons
		if ($arrClipboard !== false && Input::get('act') != 'select')
		{
			$_buttons .= ' ';

			// Call paste_button_callback(&$dc, $row, $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next)
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][0];
				$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][1];

				$this->import($strClass);
				$_buttons .= $this->$strClass->$strMethod($this, $objRow->row(), $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next);
			}
			elseif (\is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$_buttons .= $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']($this, $objRow->row(), $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next);
			}
			else
			{
				$imagePasteAfter = Image::getHtml('pasteafter.svg', sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id));
				$imagePasteInto = Image::getHtml('pasteinto.svg', sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id));

				// Regular tree (on cut: disable buttons of the page all its childs to avoid circular references)
				if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5)
				{
					$_buttons .= (($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id']))) || (!empty($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root']) && !$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['rootPaste'] && \in_array($id, $this->root))) ? Image::getHtml('pasteafter_.svg').' ' : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a> ';
					$_buttons .= (($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id'])))) ? Image::getHtml('pasteinto_.svg').' ' : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ';
				}

				// Extended tree
				else
				{
					$_buttons .= ($this->strTable == $table) ? ((($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id'])))) ? Image::getHtml('pasteafter_.svg') : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a> ') : '';
					$_buttons .= ($this->strTable != $table) ? '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ' : '';
				}
			}
		}

		$return .= ($_buttons ?: '&nbsp;') . '</div></li>';

		// Add the records of the table itself
		if ($table != $this->strTable)
		{
			// Also apply the filter settings to the child table (see #716)
			if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 && !empty($this->procedure))
			{
				$arrValues = $this->values;
				array_unshift($arrValues, $id);

				$objChilds = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE pid=? AND " . (implode(' AND ', $this->procedure)) . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($arrValues);
			}
			else
			{
				$objChilds = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE pid=?" . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($id);
			}

			if ($objChilds->numRows)
			{
				$ids = $objChilds->fetchEach('id');

				for ($j=0, $c=\count($ids); $j<$c; $j++)
				{
					$return .= $this->generateTree($this->strTable, $ids[$j], array('pp'=>$ids[($j-1)], 'nn'=>$ids[($j+1)]), $blnHasSorting, ($intMargin + $intSpacing + 20), $arrClipboard, false, ($j<(\count($ids)-1) || !empty($childs)), $blnNoRecursion, $arrFound);
				}
			}
		}

		// Begin a new submenu
		if (!$blnNoRecursion)
		{
			$blnAddParent = ($blnIsOpen || !empty($arrFound) || (!empty($childs) && $session[$node][$id] == 1));

			if ($blnAddParent)
			{
				$return .= '<li class="parent" id="'.$node.'_'.$id.'"><ul class="level_'.$level.'">';
			}

			// Add the records of the parent table
			if ($blnIsOpen && \is_array($childs))
			{
				for ($k=0, $c=\count($childs); $k<$c; $k++)
				{
					$return .= $this->generateTree($table, $childs[$k], array('p'=>$childs[($k-1)], 'n'=>$childs[($k+1)]), $blnHasSorting, ($intMargin + $intSpacing), $arrClipboard, ((($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $childs[$k] == $arrClipboard['id']) || $blnCircularReference) ? true : false), ($blnProtected || $protectedPage), $blnNoRecursion, $arrFound);
				}
			}

			// Close the submenu
			if ($blnAddParent)
			{
				$return .= '</ul></li>';
			}
		}

		$objSessionBag->replace($session);

		return $return;
	}
protected function generateTree($table, $id, $arrPrevNext, $blnHasSorting, $intMargin=0, $arrClipboard=null, $blnCircularReference=false, $protectedPage=false, $blnNoRecursion=false, $arrFound=array())
	{
		
		$objSessionBag = System::getContainer()->get('session')->getBag('contao_backend');

		$session = $objSessionBag->all();
		$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable.'_'.$table.'_tree' : $this->strTable.'_tree';

		
		if (Input::get('ptg'))
		{
			$session[$node][Input::get('ptg')] = (isset($session[$node][Input::get('ptg')]) && $session[$node][Input::get('ptg')] == 1) ? 0 : 1;
			$objSessionBag->replace($session);
			$this->redirect(preg_replace('/(&(amp;)?|\?)ptg=[^& ]*/i', '', Environment::get('request')));
		}

		$objRow = $this->Database->prepare("SELECT * FROM " . $table . " WHERE id=?")
								 ->limit(1)
								 ->execute($id);

		
		if ($objRow->numRows < 1)
		{
			$objSessionBag->replace($session);

			return '';
		}

		$return = '';
		$intSpacing = 20;
		$childs = array();

		
		if ($this->strTable == $table)
		{
			$this->current[] = $objRow->id;
		}

		
		if (!$blnNoRecursion)
		{
			if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 || $this->strTable != $table)
			{
				$objChilds = $this->Database->prepare("SELECT id FROM " . $table . " WHERE pid=?" . (!empty($arrFound) ? " AND id IN(" . implode(',', array_map('\intval', $arrFound)) . ")" : '') . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($id);

				if ($objChilds->numRows)
				{
					$childs = $objChilds->fetchEach('id');
				}
			}
		}

		$blnProtected = false;

		
		if ($table == 'tl_page')
		{
			$blnProtected = ($objRow->protected || $protectedPage) ? true : false;
		}

		$session[$node][$id] = (\is_int($session[$node][$id])) ? $session[$node][$id] : 0;
		$mouseover = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 || $table == $this->strTable) ? ' toggle_select hover-div' : '';

		$return .= "\n  " . '<li class="'.((($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $objRow->type == 'root') || $table != $this->strTable) ? 'tl_folder' : 'tl_file').' click2edit'.$mouseover.' cf"><div class="tl_left" style="padding-left:'.($intMargin + $intSpacing).'px">';

		
		$args = array();
		$folderAttribute = 'style="margin-left:20px"';
		$showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields'];
		$level = ($intMargin / $intSpacing + 1);
		$blnIsOpen = (!empty($arrFound) || $session[$node][$id] == 1);

		
		if (!$blnIsOpen && !empty($this->arrPickerValue) && !empty(array_intersect($this->Database->getChildRecords(array($id), $this->strTable), $this->arrPickerValue)))
		{
			$blnIsOpen = true;
		}

		if (!empty($childs))
		{
			$folderAttribute = '';
			$img = $blnIsOpen ? 'folMinus.svg' : 'folPlus.svg';
			$alt = $blnIsOpen ? $GLOBALS['TL_LANG']['MSC']['collapseNode'] : $GLOBALS['TL_LANG']['MSC']['expandNode'];
			$return .= '<a href="'.$this->addToUrl('ptg='.$id).'" title="'.StringUtil::specialchars($alt).'" onclick="Backend.getScrollOffset();return AjaxRequest.toggleStructure(this,\''.$node.'_'.$id.'\','.$level.','.$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'].')">'.Image::getHtml($img, '', 'style="margin-right:2px"').'</a>';
		}

		foreach ($showFields as $k=>$v)
		{
			
			if ($GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['encrypt'])
			{
				$objRow->$v = Encryption::decrypt(StringUtil::deserialize($objRow->$v));
			}

			if (strpos($v, ':') !== false)
			{
				list($strKey, $strTable) = explode(':', $v);
				list($strTable, $strField) = explode('.', $strTable);

				$objRef = $this->Database->prepare("SELECT " . Database::quoteIdentifier($strField) . " FROM " . $strTable . " WHERE id=?")
										 ->limit(1)
										 ->execute($objRow->$strKey);

				$args[$k] = $objRef->numRows ? $objRef->$strField : '';
			}
			elseif (\in_array($GLOBALS['TL_DCA'][$table]['fields'][$v]['flag'], array(5, 6, 7, 8, 9, 10)))
			{
				$args[$k] = Date::parse(Config::get('datimFormat'), $objRow->$v);
			}
			elseif ($GLOBALS['TL_DCA'][$table]['fields'][$v]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['multiple'])
			{
				$args[$k] = ($objRow->$v != '') ? ($GLOBALS['TL_DCA'][$table]['fields'][$v]['label'][0] ?? $v) : '';
			}
			else
			{
				$args[$k] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$objRow->$v] ?: $objRow->$v;
			}
		}

		$label = vsprintf(((\strlen($GLOBALS['TL_DCA'][$table]['list']['label']['format'])) ? $GLOBALS['TL_DCA'][$table]['list']['label']['format'] : '%s'), $args);

		
		if ($GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'] > 0 && $GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'] < Utf8::strlen(strip_tags($label)))
		{
			$label = trim(StringUtil::substrHtml($label, $GLOBALS['TL_DCA'][$table]['list']['label']['maxCharacters'])) . ' …';
		}

		$label = preg_replace('/\(\) ?|\[\] ?|\{\} ?|<> ?/', '', $label);

		
		if (\is_array($GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']))
		{
			$strClass = $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback'][0];
			$strMethod = $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback'][1];

			$this->import($strClass);
			$return .= $this->$strClass->$strMethod($objRow->row(), $label, $this, $folderAttribute, false, $blnProtected);
		}
		elseif (\is_callable($GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']))
		{
			$return .= $GLOBALS['TL_DCA'][$table]['list']['label']['label_callback']($objRow->row(), $label, $this, $folderAttribute, false, $blnProtected);
		}
		else
		{
			$return .= Image::getHtml('iconPLAIN.svg', '', $folderAttribute) . ' ' . $label;
		}

		$return .= '</div> <div class="tl_right">';
		$previous = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $arrPrevNext['pp'] : $arrPrevNext['p'];
		$next = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $arrPrevNext['nn'] : $arrPrevNext['n'];
		$_buttons = '';

		
		if ($this->strTable == $table)
		{
			$_buttons .= (Input::get('act') == 'select') ? '<input type="checkbox" name="IDS[]" id="ids_'.$id.'" class="tl_tree_checkbox" value="'.$id.'">' : $this->generateButtons($objRow->row(), $table, $this->root, $blnCircularReference, $childs, $previous, $next);

			if ($this->strPickerFieldType)
			{
				$_buttons .= $this->getPickerInputField($id);
			}
		}

		
		if ($arrClipboard !== false && Input::get('act') != 'select')
		{
			$_buttons .= ' ';

			
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][0];
				$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][1];

				$this->import($strClass);
				$_buttons .= $this->$strClass->$strMethod($this, $objRow->row(), $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next);
			}
			elseif (\is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$_buttons .= $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']($this, $objRow->row(), $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next);
			}
			else
			{
				$imagePasteAfter = Image::getHtml('pasteafter.svg', sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id));
				$imagePasteInto = Image::getHtml('pasteinto.svg', sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id));

				
				if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5)
				{
					$_buttons .= (($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id']))) || (!empty($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root']) && !$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['rootPaste'] && \in_array($id, $this->root))) ? Image::getHtml('pasteafter_.svg').' ' : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a> ';
					$_buttons .= (($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id'])))) ? Image::getHtml('pasteinto_.svg').' ' : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ';
				}

				
				else
				{
					$_buttons .= ($this->strTable == $table) ? ((($arrClipboard['mode'] == 'cut' && ($blnCircularReference || $arrClipboard['id'] == $id)) || ($arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || \in_array($id, $arrClipboard['id'])))) ? Image::getHtml('pasteafter_.svg') : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a> ') : '';
					$_buttons .= ($this->strTable != $table) ? '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$id.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ' : '';
				}
			}
		}

		$return .= ($_buttons ?: '&nbsp;') . '</div></li>';

		
		if ($table != $this->strTable)
		{
			
			if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 && !empty($this->procedure))
			{
				$arrValues = $this->values;
				array_unshift($arrValues, $id);

				$objChilds = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE pid=? AND " . (implode(' AND ', $this->procedure)) . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($arrValues);
			}
			else
			{
				$objChilds = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE pid=?" . ($blnHasSorting ? " ORDER BY sorting" : ''))
											->execute($id);
			}

			if ($objChilds->numRows)
			{
				$ids = $objChilds->fetchEach('id');

				for ($j=0, $c=\count($ids); $j<$c; $j++)
				{
					$return .= $this->generateTree($this->strTable, $ids[$j], array('pp'=>$ids[($j-1)], 'nn'=>$ids[($j+1)]), $blnHasSorting, ($intMargin + $intSpacing + 20), $arrClipboard, false, ($j<(\count($ids)-1) || !empty($childs)), $blnNoRecursion, $arrFound);
				}
			}
		}

		
		if (!$blnNoRecursion)
		{
			$blnAddParent = ($blnIsOpen || !empty($arrFound) || (!empty($childs) && $session[$node][$id] == 1));

			if ($blnAddParent)
			{
				$return .= '<li class="parent" id="'.$node.'_'.$id.'"><ul class="level_'.$level.'">';
			}

			
			if ($blnIsOpen && \is_array($childs))
			{
				for ($k=0, $c=\count($childs); $k<$c; $k++)
				{
					$return .= $this->generateTree($table, $childs[$k], array('p'=>$childs[($k-1)], 'n'=>$childs[($k+1)]), $blnHasSorting, ($intMargin + $intSpacing), $arrClipboard, ((($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $childs[$k] == $arrClipboard['id']) || $blnCircularReference) ? true : false), ($blnProtected || $protectedPage), $blnNoRecursion, $arrFound);
				}
			}

			
			if ($blnAddParent)
			{
				$return .= '</ul></li>';
			}
		}

		$objSessionBag->replace($session);

		return $return;
	}
protected function generateTree ( $ table , $ id , $ arrPrevNext , $ blnHasSorting , $ intMargin = 0 , $ arrClipboard = null , $ blnCircularReference = false , $ protectedPage = false , $ blnNoRecursion = false , $ arrFound = array ( ) ) { /** @var AttributeBagInterface $objSessionBag */ $ objSessionBag = System :: getContainer ( ) -> get ( 'session' ) -> getBag ( 'contao_backend' ) ; $ session = $ objSessionBag -> all ( ) ; $ node = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) ? $ this -> strTable . '_' . $ table . '_tree' : $ this -> strTable . '_tree' ; // Toggle nodes if ( Input :: get ( 'ptg' ) ) { $ session [ $ node ] [ Input :: get ( 'ptg' ) ] = ( isset ( $ session [ $ node ] [ Input :: get ( 'ptg' ) ] ) && $ session [ $ node ] [ Input :: get ( 'ptg' ) ] == 1 ) ? 0 : 1 ; $ objSessionBag -> replace ( $ session ) ; $ this -> redirect ( preg_replace ( '/(&(amp;)?|\?)ptg=[^& ]*/i' , '' , Environment :: get ( 'request' ) ) ) ; } $ objRow = $ this -> Database -> prepare ( "SELECT * FROM " . $ table . " WHERE id=?" ) -> limit ( 1 ) -> execute ( $ id ) ; // Return if there is no result if ( $ objRow -> numRows < 1 ) { $ objSessionBag -> replace ( $ session ) ; return '' ; } $ return = '' ; $ intSpacing = 20 ; $ childs = array ( ) ; // Add the ID to the list of current IDs if ( $ this -> strTable == $ table ) { $ this -> current [ ] = $ objRow -> id ; } // Check whether there are child records if ( ! $ blnNoRecursion ) { if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 || $ this -> strTable != $ table ) { $ objChilds = $ this -> Database -> prepare ( "SELECT id FROM " . $ table . " WHERE pid=?" . ( ! empty ( $ arrFound ) ? " AND id IN(" . implode ( ',' , array_map ( '\intval' , $ arrFound ) ) . ")" : '' ) . ( $ blnHasSorting ? " ORDER BY sorting" : '' ) ) -> execute ( $ id ) ; if ( $ objChilds -> numRows ) { $ childs = $ objChilds -> fetchEach ( 'id' ) ; } } } $ blnProtected = false ; // Check whether the page is protected if ( $ table == 'tl_page' ) { $ blnProtected = ( $ objRow -> protected || $ protectedPage ) ? true : false ; } $ session [ $ node ] [ $ id ] = ( \ is_int ( $ session [ $ node ] [ $ id ] ) ) ? $ session [ $ node ] [ $ id ] : 0 ; $ mouseover = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 || $ table == $ this -> strTable ) ? ' toggle_select hover-div' : '' ; $ return .= "\n  " . '<li class="' . ( ( ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 && $ objRow -> type == 'root' ) || $ table != $ this -> strTable ) ? 'tl_folder' : 'tl_file' ) . ' click2edit' . $ mouseover . ' cf"><div class="tl_left" style="padding-left:' . ( $ intMargin + $ intSpacing ) . 'px">' ; // Calculate label and add a toggle button $ args = array ( ) ; $ folderAttribute = 'style="margin-left:20px"' ; $ showFields = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'fields' ] ; $ level = ( $ intMargin / $ intSpacing + 1 ) ; $ blnIsOpen = ( ! empty ( $ arrFound ) || $ session [ $ node ] [ $ id ] == 1 ) ; // Always show selected nodes if ( ! $ blnIsOpen && ! empty ( $ this -> arrPickerValue ) && ! empty ( array_intersect ( $ this -> Database -> getChildRecords ( array ( $ id ) , $ this -> strTable ) , $ this -> arrPickerValue ) ) ) { $ blnIsOpen = true ; } if ( ! empty ( $ childs ) ) { $ folderAttribute = '' ; $ img = $ blnIsOpen ? 'folMinus.svg' : 'folPlus.svg' ; $ alt = $ blnIsOpen ? $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'collapseNode' ] : $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'expandNode' ] ; $ return .= '<a href="' . $ this -> addToUrl ( 'ptg=' . $ id ) . '" title="' . StringUtil :: specialchars ( $ alt ) . '" onclick="Backend.getScrollOffset();return AjaxRequest.toggleStructure(this,\'' . $ node . '_' . $ id . '\',' . $ level . ',' . $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] . ')">' . Image :: getHtml ( $ img , '' , 'style="margin-right:2px"' ) . '</a>' ; } foreach ( $ showFields as $ k => $ v ) { // Decrypt the value if ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'eval' ] [ 'encrypt' ] ) { $ objRow -> $ v = Encryption :: decrypt ( StringUtil :: deserialize ( $ objRow -> $ v ) ) ; } if ( strpos ( $ v , ':' ) !== false ) { list ( $ strKey , $ strTable ) = explode ( ':' , $ v ) ; list ( $ strTable , $ strField ) = explode ( '.' , $ strTable ) ; $ objRef = $ this -> Database -> prepare ( "SELECT " . Database :: quoteIdentifier ( $ strField ) . " FROM " . $ strTable . " WHERE id=?" ) -> limit ( 1 ) -> execute ( $ objRow -> $ strKey ) ; $ args [ $ k ] = $ objRef -> numRows ? $ objRef -> $ strField : '' ; } elseif ( \ in_array ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'flag' ] , array ( 5 , 6 , 7 , 8 , 9 , 10 ) ) ) { $ args [ $ k ] = Date :: parse ( Config :: get ( 'datimFormat' ) , $ objRow -> $ v ) ; } elseif ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'inputType' ] == 'checkbox' && ! $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'eval' ] [ 'multiple' ] ) { $ args [ $ k ] = ( $ objRow -> $ v != '' ) ? ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'label' ] [ 0 ] ?? $ v ) : '' ; } else { $ args [ $ k ] = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'fields' ] [ $ v ] [ 'reference' ] [ $ objRow -> $ v ] ? : $ objRow -> $ v ; } } $ label = vsprintf ( ( ( \ strlen ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'format' ] ) ) ? $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'format' ] : '%s' ) , $ args ) ; // Shorten the label if it is too long if ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'maxCharacters' ] > 0 && $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'maxCharacters' ] < Utf8 :: strlen ( strip_tags ( $ label ) ) ) { $ label = trim ( StringUtil :: substrHtml ( $ label , $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'maxCharacters' ] ) ) . ' …'; } $ label = preg_replace ( '/\(\) ?|\[\] ?|\{\} ?|<> ?/' , '' , $ label ) ; // Call the label_callback ($row, $label, $this) if ( \ is_array ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'label_callback' ] ) ) { $ strClass = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'label_callback' ] [ 0 ] ; $ strMethod = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'label_callback' ] [ 1 ] ; $ this -> import ( $ strClass ) ; $ return .= $ this -> $ strClass -> $ strMethod ( $ objRow -> row ( ) , $ label , $ this , $ folderAttribute , false , $ blnProtected ) ; } elseif ( \ is_callable ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'label_callback' ] ) ) { $ return .= $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'label' ] [ 'label_callback' ] ( $ objRow -> row ( ) , $ label , $ this , $ folderAttribute , false , $ blnProtected ) ; } else { $ return .= Image :: getHtml ( 'iconPLAIN.svg' , '' , $ folderAttribute ) . ' ' . $ label ; } $ return .= '</div> <div class="tl_right">' ; $ previous = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) ? $ arrPrevNext [ 'pp' ] : $ arrPrevNext [ 'p' ] ; $ next = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) ? $ arrPrevNext [ 'nn' ] : $ arrPrevNext [ 'n' ] ; $ _buttons = '' ; // Regular buttons ($row, $table, $root, $blnCircularReference, $childs, $previous, $next) if ( $ this -> strTable == $ table ) { $ _buttons .= ( Input :: get ( 'act' ) == 'select' ) ? '<input type="checkbox" name="IDS[]" id="ids_' . $ id . '" class="tl_tree_checkbox" value="' . $ id . '">' : $ this -> generateButtons ( $ objRow -> row ( ) , $ table , $ this -> root , $ blnCircularReference , $ childs , $ previous , $ next ) ; if ( $ this -> strPickerFieldType ) { $ _buttons .= $ this -> getPickerInputField ( $ id ) ; } } // Paste buttons if ( $ arrClipboard !== false && Input :: get ( 'act' ) != 'select' ) { $ _buttons .= ' ' ; // Call paste_button_callback(&$dc, $row, $table, $blnCircularReference, $arrClipboard, $childs, $previous, $next) if ( \ is_array ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ) ) { $ strClass = $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] [ 0 ] ; $ strMethod = $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] [ 1 ] ; $ this -> import ( $ strClass ) ; $ _buttons .= $ this -> $ strClass -> $ strMethod ( $ this , $ objRow -> row ( ) , $ table , $ blnCircularReference , $ arrClipboard , $ childs , $ previous , $ next ) ; } elseif ( \ is_callable ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ) ) { $ _buttons .= $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ( $ this , $ objRow -> row ( ) , $ table , $ blnCircularReference , $ arrClipboard , $ childs , $ previous , $ next ) ; } else { $ imagePasteAfter = Image :: getHtml ( 'pasteafter.svg' , sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteafter' ] [ 1 ] , $ id ) ) ; $ imagePasteInto = Image :: getHtml ( 'pasteinto.svg' , sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteinto' ] [ 1 ] , $ id ) ) ; // Regular tree (on cut: disable buttons of the page all its childs to avoid circular references) if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 ) { $ _buttons .= ( ( $ arrClipboard [ 'mode' ] == 'cut' && ( $ blnCircularReference || $ arrClipboard [ 'id' ] == $ id ) ) || ( $ arrClipboard [ 'mode' ] == 'cutAll' && ( $ blnCircularReference || \ in_array ( $ id , $ arrClipboard [ 'id' ] ) ) ) || ( ! empty ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'root' ] ) && ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'rootPaste' ] && \ in_array ( $ id , $ this -> root ) ) ) ? Image :: getHtml ( 'pasteafter_.svg' ) . ' ' : '<a href="' . $ this -> addToUrl ( 'act=' . $ arrClipboard [ 'mode' ] . '&amp;mode=1&amp;pid=' . $ id . ( ! \ is_array ( $ arrClipboard [ 'id' ] ) ? '&amp;id=' . $ arrClipboard [ 'id' ] : '' ) ) . '" title="' . StringUtil :: specialchars ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteafter' ] [ 1 ] , $ id ) ) . '" onclick="Backend.getScrollOffset()">' . $ imagePasteAfter . '</a> ' ; $ _buttons .= ( ( $ arrClipboard [ 'mode' ] == 'cut' && ( $ blnCircularReference || $ arrClipboard [ 'id' ] == $ id ) ) || ( $ arrClipboard [ 'mode' ] == 'cutAll' && ( $ blnCircularReference || \ in_array ( $ id , $ arrClipboard [ 'id' ] ) ) ) ) ? Image :: getHtml ( 'pasteinto_.svg' ) . ' ' : '<a href="' . $ this -> addToUrl ( 'act=' . $ arrClipboard [ 'mode' ] . '&amp;mode=2&amp;pid=' . $ id . ( ! \ is_array ( $ arrClipboard [ 'id' ] ) ? '&amp;id=' . $ arrClipboard [ 'id' ] : '' ) ) . '" title="' . StringUtil :: specialchars ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteinto' ] [ 1 ] , $ id ) ) . '" onclick="Backend.getScrollOffset()">' . $ imagePasteInto . '</a> ' ; } // Extended tree else { $ _buttons .= ( $ this -> strTable == $ table ) ? ( ( ( $ arrClipboard [ 'mode' ] == 'cut' && ( $ blnCircularReference || $ arrClipboard [ 'id' ] == $ id ) ) || ( $ arrClipboard [ 'mode' ] == 'cutAll' && ( $ blnCircularReference || \ in_array ( $ id , $ arrClipboard [ 'id' ] ) ) ) ) ? Image :: getHtml ( 'pasteafter_.svg' ) : '<a href="' . $ this -> addToUrl ( 'act=' . $ arrClipboard [ 'mode' ] . '&amp;mode=1&amp;pid=' . $ id . ( ! \ is_array ( $ arrClipboard [ 'id' ] ) ? '&amp;id=' . $ arrClipboard [ 'id' ] : '' ) ) . '" title="' . StringUtil :: specialchars ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteafter' ] [ 1 ] , $ id ) ) . '" onclick="Backend.getScrollOffset()">' . $ imagePasteAfter . '</a> ' ) : '' ; $ _buttons .= ( $ this -> strTable != $ table ) ? '<a href="' . $ this -> addToUrl ( 'act=' . $ arrClipboard [ 'mode' ] . '&amp;mode=2&amp;pid=' . $ id . ( ! \ is_array ( $ arrClipboard [ 'id' ] ) ? '&amp;id=' . $ arrClipboard [ 'id' ] : '' ) ) . '" title="' . StringUtil :: specialchars ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteinto' ] [ 1 ] , $ id ) ) . '" onclick="Backend.getScrollOffset()">' . $ imagePasteInto . '</a> ' : '' ; } } } $ return .= ( $ _buttons ? : '&nbsp;' ) . '</div></li>' ; // Add the records of the table itself if ( $ table != $ this -> strTable ) { // Also apply the filter settings to the child table (see #716) if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 && ! empty ( $ this -> procedure ) ) { $ arrValues = $ this -> values ; array_unshift ( $ arrValues , $ id ) ; $ objChilds = $ this -> Database -> prepare ( "SELECT id FROM " . $ this -> strTable . " WHERE pid=? AND " . ( implode ( ' AND ' , $ this -> procedure ) ) . ( $ blnHasSorting ? " ORDER BY sorting" : '' ) ) -> execute ( $ arrValues ) ; } else { $ objChilds = $ this -> Database -> prepare ( "SELECT id FROM " . $ this -> strTable . " WHERE pid=?" . ( $ blnHasSorting ? " ORDER BY sorting" : '' ) ) -> execute ( $ id ) ; } if ( $ objChilds -> numRows ) { $ ids = $ objChilds -> fetchEach ( 'id' ) ; for ( $ j = 0 , $ c = \ count ( $ ids ) ; $ j < $ c ; $ j ++ ) { $ return .= $ this -> generateTree ( $ this -> strTable , $ ids [ $ j ] , array ( 'pp' => $ ids [ ( $ j - 1 ) ] , 'nn' => $ ids [ ( $ j + 1 ) ] ) , $ blnHasSorting , ( $ intMargin + $ intSpacing + 20 ) , $ arrClipboard , false , ( $ j < ( \ count ( $ ids ) - 1 ) || ! empty ( $ childs ) ) , $ blnNoRecursion , $ arrFound ) ; } } } // Begin a new submenu if ( ! $ blnNoRecursion ) { $ blnAddParent = ( $ blnIsOpen || ! empty ( $ arrFound ) || ( ! empty ( $ childs ) && $ session [ $ node ] [ $ id ] == 1 ) ) ; if ( $ blnAddParent ) { $ return .= '<li class="parent" id="' . $ node . '_' . $ id . '"><ul class="level_' . $ level . '">' ; } // Add the records of the parent table if ( $ blnIsOpen && \ is_array ( $ childs ) ) { for ( $ k = 0 , $ c = \ count ( $ childs ) ; $ k < $ c ; $ k ++ ) { $ return .= $ this -> generateTree ( $ table , $ childs [ $ k ] , array ( 'p' => $ childs [ ( $ k - 1 ) ] , 'n' => $ childs [ ( $ k + 1 ) ] ) , $ blnHasSorting , ( $ intMargin + $ intSpacing ) , $ arrClipboard , ( ( ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 && $ childs [ $ k ] == $ arrClipboard [ 'id' ] ) || $ blnCircularReference ) ? true : false ) , ( $ blnProtected || $ protectedPage ) , $ blnNoRecursion , $ arrFound ) ; } } // Close the submenu if ( $ blnAddParent ) { $ return .= '</ul></li>' ; } } $ objSessionBag -> replace ( $ session ) ; return $ return ; }
Recursively generate the tree and return it as HTML string

@param string  $table
@param integer $id
@param array   $arrPrevNext
@param boolean $blnHasSorting
@param integer $intMargin
@param array   $arrClipboard
@param boolean $blnCircularReference
@param boolean $protectedPage
@param boolean $blnNoRecursion
@param array   $arrFound

@return string
Recursively generate the tree and return it as HTML string