/**
* List all records of the current table and return them as HTML string
*
* @return string
*/
protected function listView()
{
$return = '';
$table = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 ? $this->ptable : $this->strTable;
$orderBy = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields'];
$firstOrderBy = preg_replace('/\\s+.*$/', '', $orderBy[0]);
if (is_array($this->orderBy) && $this->orderBy[0] != '') {
$orderBy = $this->orderBy;
$firstOrderBy = $this->firstOrderBy;
}
$query = "SELECT * FROM " . $this->strTable;
if (!empty($this->procedure)) {
$query .= " WHERE " . implode(' AND ', $this->procedure);
}
if (!empty($this->root) && is_array($this->root)) {
$query .= (!empty($this->procedure) ? " AND " : " WHERE ") . "id IN(" . implode(',', array_map('intval', $this->root)) . ")";
}
if (is_array($orderBy) && $orderBy[0] != '') {
foreach ($orderBy as $k => $v) {
list($key, $direction) = explode(' ', $v, 2);
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['eval']['findInSet']) {
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'])) {
$strClass = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'][0];
$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'][1];
$this->import($strClass);
$keys = $this->{$strClass}->{$strMethod}($this);
} elseif (is_callable($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'])) {
$keys = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback']($this);
} else {
$keys = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options'];
}
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['eval']['isAssociative'] || array_is_assoc($keys)) {
$keys = array_keys($keys);
}
$orderBy[$k] = $this->Database->findInSet($v, $keys);
} elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['flag'], array(5, 6, 7, 8, 9, 10))) {
$orderBy[$k] = "CAST({$key} AS SIGNED)" . ($direction ? " {$direction}" : "");
// see #5503
}
}
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 3) {
$firstOrderBy = 'pid';
$showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields'];
$query .= " ORDER BY (SELECT " . $showFields[0] . " FROM " . $this->ptable . " WHERE " . $this->ptable . ".id=" . $this->strTable . ".pid), " . implode(', ', $orderBy);
// Set the foreignKey so that the label is translated
if ($GLOBALS['TL_DCA'][$table]['fields']['pid']['foreignKey'] == '') {
$GLOBALS['TL_DCA'][$table]['fields']['pid']['foreignKey'] = $this->ptable . '.' . $showFields[0];
}
// Remove the parent field from label fields
array_shift($showFields);
$GLOBALS['TL_DCA'][$table]['list']['label']['fields'] = $showFields;
} else {
$query .= " ORDER BY " . implode(', ', $orderBy);
}
}
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 1 && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] % 2 == 0) {
$query .= " DESC";
}
$objRowStmt = $this->Database->prepare($query);
if ($this->limit != '') {
$arrLimit = explode(',', $this->limit);
$objRowStmt->limit($arrLimit[1], $arrLimit[0]);
}
$objRow = $objRowStmt->execute($this->values);
$this->bid = $return != '' ? $this->bid : 'tl_buttons';
// Display buttos
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] || !empty($GLOBALS['TL_DCA'][$this->strTable]['list']['global_operations'])) {
$return .= '
<div id="' . $this->bid . '">' . (\Input::get('act') == 'select' || $this->ptable ? '
<a href="' . $this->getReferer(true, $this->ptable) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> ' : (isset($GLOBALS['TL_DCA'][$this->strTable]['config']['backlink']) ? '
<a href="contao/main.php?' . $GLOBALS['TL_DCA'][$this->strTable]['config']['backlink'] . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> ' : '')) . (\Input::get('act') != 'select' && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable'] ? '
<a href="' . ($this->ptable != '' ? $this->addToUrl('act=create' . ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] < 4 ? '&mode=2' : '') . '&pid=' . $this->intId) : $this->addToUrl('act=create')) . '" class="header_new" title="' . specialchars($GLOBALS['TL_LANG'][$this->strTable]['new'][1]) . '" accesskey="n" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG'][$this->strTable]['new'][0] . '</a> ' : '') . $this->generateGlobalButtons() . '
</div>' . \Message::generate(true);
}
// Return "no records found" message
if ($objRow->numRows < 1) {
$return .= '
<p class="tl_empty">' . $GLOBALS['TL_LANG']['MSC']['noResult'] . '</p>';
} else {
$result = $objRow->fetchAllAssoc();
$return .= (\Input::get('act') == 'select' ? '
<form action="' . ampersand(\Environment::get('request'), true) . '" id="tl_select" class="tl_form' . (\Input::get('act') == 'select' ? ' unselectable' : '') . '" method="post" novalidate>
<div class="tl_formbody">
<input type="hidden" name="FORM_SUBMIT" value="tl_select">
<input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">' : '') . '
<div class="tl_listing_container list_view">' . (\Input::get('act') == 'select' ? '
<div class="tl_select_trigger">
<label for="tl_select_trigger" class="tl_select_label">' . $GLOBALS['TL_LANG']['MSC']['selectAll'] . '</label> <input type="checkbox" id="tl_select_trigger" onclick="Backend.toggleCheckboxes(this)" class="tl_tree_checkbox">
</div>' : '') . '
<table class="tl_listing' . ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns'] ? ' showColumns' : '') . '">';
// Automatically add the "order by" field as last column if we do not have group headers
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) {
$blnFound = false;
// Extract the real key and compare it to $firstOrderBy
foreach ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'] as $f) {
if (strpos($f, ':') !== false) {
list($f) = explode(':', $f, 2);
}
if ($firstOrderBy == $f) {
$blnFound = true;
break;
}
}
if (!$blnFound) {
$GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][] = $firstOrderBy;
}
}
// Generate the table header if the "show columns" option is active
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) {
$return .= '
<tr>';
foreach ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'] as $f) {
if (strpos($f, ':') !== false) {
list($f) = explode(':', $f, 2);
}
$return .= '
<th class="tl_folder_tlist col_' . $f . ($f == $firstOrderBy ? ' ordered_by' : '') . '">' . (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label']) . '</th>';
}
$return .= '
<th class="tl_folder_tlist tl_right_nowrap"> </th>
</tr>';
}
// Process result and add label and buttons
$remoteCur = false;
$groupclass = 'tl_folder_tlist';
$eoCount = -1;
foreach ($result as $row) {
$args = array();
$this->current[] = $row['id'];
$showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields'];
// Label
foreach ($showFields as $k => $v) {
// Decrypt the value
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['encrypt']) {
$row[$v] = \Encryption::decrypt(deserialize($row[$v]));
}
if (strpos($v, ':') !== false) {
list($strKey, $strTable) = explode(':', $v);
list($strTable, $strField) = explode('.', $strTable);
$objRef = $this->Database->prepare("SELECT " . $strField . " FROM " . $strTable . " WHERE id=?")->limit(1)->execute($row[$strKey]);
$args[$k] = $objRef->numRows ? $objRef->{$strField} : '';
} elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['flag'], array(5, 6, 7, 8, 9, 10))) {
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['rgxp'] == 'date') {
$args[$k] = $row[$v] ? \Date::parse(\Config::get('dateFormat'), $row[$v]) : '-';
} elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['rgxp'] == 'time') {
$args[$k] = $row[$v] ? \Date::parse(\Config::get('timeFormat'), $row[$v]) : '-';
} else {
$args[$k] = $row[$v] ? \Date::parse(\Config::get('datimFormat'), $row[$v]) : '-';
}
} elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['multiple']) {
$args[$k] = $row[$v] != '' ? $GLOBALS['TL_DCA'][$table]['fields'][$v]['label'][0] : '';
} else {
$row_v = deserialize($row[$v]);
if (is_array($row_v)) {
$args_k = array();
foreach ($row_v as $option) {
$args_k[] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$option] ?: $option;
}
$args[$k] = implode(', ', $args_k);
} elseif (isset($GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]])) {
$args[$k] = is_array($GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]]) ? $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]][0] : $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]];
} elseif (($GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$table]['fields'][$v]['options'])) && isset($GLOBALS['TL_DCA'][$table]['fields'][$v]['options'][$row[$v]])) {
$args[$k] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['options'][$row[$v]];
} else {
$args[$k] = $row[$v];
}
}
}
// Shorten the label it if it is too long
$label = vsprintf($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['format'] ?: '%s', $args);
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'] > 0 && $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'] < strlen(strip_tags($label))) {
$label = trim(\StringUtil::substrHtml($label, $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'])) . ' …';
}
// Remove empty brackets (), [], {}, <> and empty tags from the label
$label = preg_replace('/\\( *\\) ?|\\[ *\\] ?|\\{ *\\} ?|< *> ?/', '', $label);
$label = preg_replace('/<[^>]+>\\s*<\\/[^>]+>/', '', $label);
// Build the sorting groups
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] > 0) {
$current = $row[$firstOrderBy];
$orderBy = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields'];
$sortingMode = count($orderBy) == 1 && $firstOrderBy == $orderBy[0] && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] != '' && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['flag'] == '' ? $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['flag'];
$remoteNew = $this->formatCurrentValue($firstOrderBy, $current, $sortingMode);
// Add the group header
if (!$GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns'] && !$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['disableGrouping'] && ($remoteNew != $remoteCur || $remoteCur === false)) {
$eoCount = -1;
$group = $this->formatGroupHeader($firstOrderBy, $remoteNew, $sortingMode, $row);
$remoteCur = $remoteNew;
$return .= '
<tr>
<td colspan="2" class="' . $groupclass . '">' . $group . '</td>
</tr>';
$groupclass = 'tl_folder_list';
}
}
$return .= '
<tr class="' . (++$eoCount % 2 == 0 ? 'even' : 'odd') . ' click2edit toggle_select hover-row">
';
$colspan = 1;
// Call the label_callback ($row, $label, $this)
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback']) || is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) {
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) {
$strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'][0];
$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'][1];
$this->import($strClass);
$args = $this->{$strClass}->{$strMethod}($row, $label, $this, $args);
} elseif (is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) {
$args = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback']($row, $label, $this, $args);
}
// Handle strings and arrays
if (!$GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) {
$label = is_array($args) ? implode(' ', $args) : $args;
} elseif (!is_array($args)) {
$args = array($args);
$colspan = count($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields']);
}
}
// Show columns
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) {
foreach ($args as $j => $arg) {
$return .= '<td colspan="' . $colspan . '" class="tl_file_list col_' . $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][$j] . ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][$j] == $firstOrderBy ? ' ordered_by' : '') . '">' . ($arg ?: '-') . '</td>';
}
} else {
$return .= '<td class="tl_file_list">' . $label . '</td>';
}
// Buttons ($row, $table, $root, $blnCircularReference, $childs, $previous, $next)
$return .= (\Input::get('act') == 'select' ? '
<td class="tl_file_list tl_right_nowrap"><input type="checkbox" name="IDS[]" id="ids_' . $row['id'] . '" class="tl_tree_checkbox" value="' . $row['id'] . '"></td>' : '
<td class="tl_file_list tl_right_nowrap">' . $this->generateButtons($row, $this->strTable, $this->root) . '</td>') . '
</tr>';
}
// Close the table
$return .= '
</table>
</div>';
// Close the form
if (\Input::get('act') == 'select') {
// Submit buttons
$arrButtons = array();
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable']) {
$arrButtons['delete'] = '<button type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(\'' . $GLOBALS['TL_LANG']['MSC']['delAllConfirm'] . '\')">' . $GLOBALS['TL_LANG']['MSC']['deleteSelected'] . '</button>';
}
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable']) {
$arrButtons['copy'] = '<button type="submit" name="copy" id="copy" class="tl_submit" accesskey="c">' . $GLOBALS['TL_LANG']['MSC']['copySelected'] . '</button>';
}
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable']) {
$arrButtons['override'] = '<button type="submit" name="override" id="override" class="tl_submit" accesskey="v">' . $GLOBALS['TL_LANG']['MSC']['overrideSelected'] . '</button>';
$arrButtons['edit'] = '<button type="submit" name="edit" id="edit" class="tl_submit" accesskey="s">' . $GLOBALS['TL_LANG']['MSC']['editSelected'] . '</button>';
}
// Call the buttons_callback (see #4691)
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'])) {
foreach ($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'] as $callback) {
if (is_array($callback)) {
$this->import($callback[0]);
$arrButtons = $this->{$callback[0]}->{$callback[1]}($arrButtons, $this);
} elseif (is_callable($callback)) {
$arrButtons = $callback($arrButtons, $this);
}
}
}
$return .= '
<div class="tl_formbody_submit" style="text-align:right">
<div class="tl_submit_container">
' . implode(' ', $arrButtons) . '
</div>
</div>
</div>
</form>';
}
}
return $return;
}