Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Listing module (Auflistung) corrections and enhancements #6344

Open
wants to merge 2 commits into
base: 3.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion system/modules/listing/dca/tl_module.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
'label' => &$GLOBALS['TL_LANG']['tl_module']['list_info'],
'exclude' => true,
'inputType' => 'text',
'eval' => array('maxlength'=>255, 'tl_class'=>'w50'),
'eval' => array('maxlength'=>255, 'decodeEntities'=>true, 'tl_class'=>'w50'),
'sql' => "varchar(255) NOT NULL default ''"
);

Expand Down
152 changes: 103 additions & 49 deletions system/modules/listing/modules/ModuleListing.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function generate()

$this->strTemplate = $this->list_layout;
$this->list_where = $this->replaceInsertTags($this->list_where);
$this->list_info_where = $this->replaceInsertTags($this->list_info_where);

return parent::generate();
}
Expand All @@ -105,9 +106,16 @@ protected function compile()
* Add the search menu
*/
$strWhere = '';
$strOuterWhere = '';
$varKeyword = '';
$strOptions = '';

// moved in front of search args, added () to protect OR, see #6337
if ($this->list_where)
{
$strWhere .= " WHERE (" . $this->list_where . ")";
}

$this->Template->searchable = false;
$arrSearchFields = trimsplit(',', $this->list_search);

Expand All @@ -117,8 +125,31 @@ protected function compile()

if (\Input::get('search') && \Input::get('for'))
{
$searchCol = \Input::get('search');
$varKeyword = '%' . \Input::get('for') . '%';
$strWhere = (!$this->list_where ? " WHERE " : " AND ") . \Input::get('search') . " LIKE ?";

// try to determine if search column is virtual, see #6337
// algorithm is a bit daring but worked for many test cases
$strCols = ',' . $this->list_fields . ',';
// eliminate (...), instead of a risky loop do 3x:
$strCols = preg_replace('/[a-zA-Z0-9_]*\([^()]*\)/', 'X', $strCols);
$strCols = preg_replace('/[a-zA-Z0-9_]*\([^()]*\)/', 'X', $strCols);
$strCols = preg_replace('/[a-zA-Z0-9_]*\([^()]*\)/', 'X', $strCols);
$strCols = preg_replace('/,\s*/', ',', strrev($strCols));
$strCols = preg_replace('/,"?([a-z0-9_]+)"? +/i', ',!\1!', $strCols);
$strCols = utf8_strtolower(strrev($strCols));
$searchCol = utf8_strtolower($searchCol);
if (preg_match_all('/!([^!]+)!,/', $strCols, $arrVcols) > 0)
{
if (in_array($searchCol, $arrVcols[1]))
{
$strOuterWhere = " WHERE " . \Input::get('search') . " LIKE ?";
}
}
if (!$strOuterWhere)
{
$strWhere .= (!$strWhere ? " WHERE " : " AND ") . \Input::get('search') . " LIKE ?";
}
}

foreach ($arrSearchFields as $field)
Expand All @@ -133,14 +164,15 @@ protected function compile()
/**
* Get the total number of records
*/
$strQuery = "SELECT COUNT(*) AS count FROM " . $this->list_table;

if ($this->list_where)
$strQuery = "SELECT COUNT(*) AS count FROM ";
if ($strOuterWhere)
{
$strQuery .= " WHERE " . $this->list_where;
$strQuery .= "(SELECT " . $this->list_fields . " FROM " . $this->list_table . $strWhere . ") t " . $strOuterWhere;
}
else
{
$strQuery .= $this->list_table . $strWhere;
}

$strQuery .= $strWhere;
$objTotal = $this->Database->prepare($strQuery)->execute($varKeyword);


Expand Down Expand Up @@ -173,14 +205,24 @@ protected function compile()
/**
* Get the selected records
*/
$strQuery = "SELECT " . $this->strPk . "," . $this->list_fields . " FROM " . $this->list_table;
// help detect PK in column list - may fail if PK is used in function argument
// in simple SELECT, double ID col is tolerated, not so if subselect is used
$tmpFields = trimsplit(',', $this->list_fields);
$blnPkInList = in_array($this->strPk, $tmpFields) && $strOuterWhere;

if ($this->list_where)
$strDetailHint = '';

if ($this->list_info_where && $this->list_info)
{
$strQuery .= " WHERE " . $this->list_where;
// add virtual column to tell if detail link needed
$strDetailHint = ",(SELECT 1 FROM " . $this->list_table . " b WHERE b.id = a.id AND " . $this->list_info_where . ") as _detail_hint";
}
$strQuery = "SELECT " . ($blnPkInList ? "" : $this->strPk . ",") . $this->list_fields . $strDetailHint . " FROM " . $this->list_table ." a" . $strWhere;
// take care of search for virtual column (see #6337)
if ($strOuterWhere)
{
$strQuery = "SELECT * FROM (" . $strQuery .") t " . $strOuterWhere;
}

$strQuery .= $strWhere;

// Order by
if (\Input::get('order_by'))
Expand Down Expand Up @@ -231,50 +273,23 @@ protected function compile()
*/
$arrTh = array();
$arrTd = array();
$arrFields = trimsplit(',', $this->list_fields);

// THEAD
for ($i=0, $c=count($arrFields); $i<$c; $i++)
{
// Never show passwords
if ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$arrFields[$i]]['inputType'] == 'password')
{
continue;
}

$class = '';
$sort = 'asc';
$strField = strlen($label = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$arrFields[$i]]['label'][0]) ? $label : $arrFields[$i];

// Add a CSS class to the order_by column
if (\Input::get('order_by') == $arrFields[$i])
{
$sort = (\Input::get('sort') == 'asc') ? 'desc' : 'asc';
$class = ' sorted ' . \Input::get('sort');
}

$arrTh[] = array
(
'link' => $strField,
'href' => (ampersand($strUrl) . $strVarConnector . 'order_by=' . $arrFields[$i]) . '&amp;sort=' . $sort,
'title' => specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['list_orderBy'], $strField)),
'class' => $class . (($i == 0) ? ' col_first' : '') //. ((($i + 1) == count($arrFields)) ? ' col_last' : '')
);
}
$arrFields = array(); // will collect the column names/aliases, see #6337

$j = 0;
$arrRows = $objData->fetchAllAssoc();

// TBODY
// TBODY.
for ($i=0, $c=count($arrRows); $i<$c; $i++)
{
$j = 0;
$class = 'row_' . $i . (($i == 0) ? ' row_first' : '') . ((($i + 1) == count($arrRows)) ? ' row_last' : '') . ((($i % 2) == 0) ? ' even' : ' odd');

$blnDetailHint = empty($strDetailHint) || !empty($arrRows[$i]['_detail_hint']);

foreach ($arrRows[$i] as $k=>$v)
{
// Skip the primary key
if ($k == $this->strPk && !in_array($this->strPk, $arrFields))
if ($k == $this->strPk && !in_array($this->strPk, $tmpFields))
{
continue;
}
Expand All @@ -285,24 +300,59 @@ protected function compile()
continue;
}

// skip the detail hint (see #6332)
if ($k == '_detail_hint')
{
continue;
}

// collect column names for header (see #6337)
if ($i == 0)
{
$arrFields[] =$k;
}

$value = $this->formatValue($k, $v);

$arrTd[$class][$k] = array
(
'raw' => $v,
'content' => ($value ? $value : '&nbsp;'),
'class' => 'col_' . $j . (($j++ == 0) ? ' col_first' : '') . ($this->list_info ? '' : (($j >= (count($arrRows[$i]) - 1)) ? ' col_last' : '')),
'class' => 'col_' . $j . (($j++ == 0) ? ' col_first' : '') . ($this->list_info ? '' : (($j >= (count($arrRows[$i]) - 1)) ? ' col_last' : '')) . (is_numeric($v)? ' numeric' : ''),
'id' => $arrRows[$i][$this->strPk],
'field' => $k,
'url' => $strUrl . $strVarConnector . 'show=' . $arrRows[$i][$this->strPk]
'url' => $blnDetailHint ? $strUrl . $strVarConnector . 'show=' . $arrRows[$i][$this->strPk] : ''
);
}
}

// THEAD
// uses collected column names from TBODY
for ($i=0, $c=count($arrFields); $i<$c; $i++)
{
$class = '';
$sort = 'asc';
$strField = strlen($label = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$arrFields[$i]]['label'][0]) ? $label : ucfirst($arrFields[$i]);

// Add a CSS class to the order_by column
if (\Input::get('order_by') == $arrFields[$i])
{
$sort = (\Input::get('sort') == 'asc') ? 'desc' : 'asc';
$class = ' sorted ' . \Input::get('sort');
}

$arrTh[] = array
(
'link' => $strField,
'href' => (ampersand($strUrl) . $strVarConnector . 'order_by=' . $arrFields[$i]) . '&amp;sort=' . $sort,
'title' => specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['list_orderBy'], $strField)),
'class' => $class . (($i == 0) ? ' col_first' : '') //. ((($i + 1) == count($arrFields)) ? ' col_last' : '')
);
}

$this->Template->thead = $arrTh;
$this->Template->tbody = $arrTd;


/**
* Pagination
*/
Expand Down Expand Up @@ -347,9 +397,13 @@ protected function listSingleRecord($id)
$this->Template->referer = 'javascript:history.go(-1)';
$this->Template->back = $GLOBALS['TL_LANG']['MSC']['goBack'];
$this->list_info = deserialize($this->list_info);
$this->list_info_where = $this->replaceInsertTags($this->list_info_where);
##$this->list_info_where = $this->replaceInsertTags($this->list_info_where);

$objRecord = $this->Database->prepare("SELECT " . $this->list_info . " FROM " . $this->list_table . " WHERE " . (($this->list_info_where != '') ? $this->list_info_where . " AND " : "") . $this->strPk . "=?")
$objRecord = $this->Database->prepare(" SELECT " . $this->list_info
. " FROM " . $this->list_table
. " WHERE " . (($this->list_info_where != '')
? "(" . $this->list_info_where . ") AND "
: "") . $this->strPk . "=?")
->limit(1)
->execute($id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<td class="body <?php echo $col['class']; ?>"><?php echo $col['content']; ?></td>
<?php endforeach; ?>
<?php if ($this->details): ?>
<td class="body <?php echo $this->col_last; ?> col_last"><a href="<?php echo $col['url']; ?>"><img src="<?php echo TL_FILES_URL; ?>assets/contao/images/info.gif" alt=""></a></td>
<td class="body <?php echo $this->col_last; ?> col_last"><?php if ($col['url']): ?><a href="<?php echo $col['url']; ?>"><img src="<?php echo TL_FILES_URL; ?>assets/contao/images/info.gif" alt=""></a><?php endif; ?></td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<td class="body <?php echo $col['class']; ?>"><?php echo $col['content']; ?></td>
<?php endforeach; ?>
<?php if ($this->details): ?>
<td class="body <?php echo $this->col_last; ?> col_last"><a href="<?php echo $col['url']; ?>"><img src="<?php echo TL_FILES_URL; ?>assets/contao/images/info.gif" alt="" /></a></td>
<td class="body <?php echo $this->col_last; ?> col_last"><?php if ($col['url']): ?><a href="<?php echo $col['url']; ?>"><img src="<?php echo TL_FILES_URL; ?>assets/contao/images/info.gif" alt=""></a><?php endif; ?></td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
Expand Down