Вход Регистрация
Файл: contao-3.5.8/system/modules/core/drivers/DC_Table.php
Строк: 3894
<?php

/**
 * Contao Open Source CMS
 *
 * Copyright (c) 2005-2016 Leo Feyer
 *
 * @license LGPL-3.0+
 */

namespace Contao;


/**
 * Provide methods to modify the database.
 *
 * @author Leo Feyer <https://github.com/leofeyer>
 * @author Andreas Schempp <https://github.com/aschempp>
 */
class DC_Table extends DataContainer implements listableeditable
{

    
/**
     * Name of the parent table
     * @var string
     */
    
protected $ptable;

    
/**
     * Names of the child tables
     * @var array
     */
    
protected $ctable;

    
/**
     * IDs of all root records
     * @var array
     */
    
protected $root;

    
/**
     * ID of the button container
     * @var string
     */
    
protected $bid;

    
/**
     * Limit (database query)
     * @var string
     */
    
protected $limit;

    
/**
     * Total (database query)
     * @var string
     */
    
protected $total;

    
/**
     * First sorting field
     * @var string
     */
    
protected $firstOrderBy;

    
/**
     * Order by (database query)
     * @var array
     */
    
protected $orderBy = array();

    
/**
     * Fields of a new or duplicated record
     * @var array
     */
    
protected $set = array();

    
/**
     * IDs of all records that are currently displayed
     * @var array
     */
    
protected $current = array();

    
/**
     * Show the current table as tree
     * @var boolean
     */
    
protected $treeView false;

    
/**
     * True if a new version has to be created
     * @var boolean
     */
    
protected $blnCreateNewVersion false;

    
/**
     * True if one of the form fields is uploadable
     * @var boolean
     */
    
protected $blnUploadable false;

    
/**
     * The current back end module
     * @var array
     */
    
protected $arrModule = array();


    
/**
     * Initialize the object
     *
     * @param string $strTable
     * @param array  $arrModule
     */
    
public function __construct($strTable$arrModule=array())
    {
        
parent::__construct();

        
// Check the request token (see #4007)
        
if (isset($_GET['act']))
        {
            if (!isset(
$_GET['rt']) || !RequestToken::validate(Input::get('rt')))
            {
                
$this->Session->set('INVALID_TOKEN_URL'Environment::get('request'));
                
$this->redirect('contao/confirm.php');
            }
        }

        
$this->intId Input::get('id');

        
// Clear the clipboard
        
if (isset($_GET['clipboard']))
        {
            
$this->Session->set('CLIPBOARD', array());
            
$this->redirect($this->getReferer());
        }

        
// Check whether the table is defined
        
if ($strTable == '' || !isset($GLOBALS['TL_DCA'][$strTable]))
        {
            
$this->log('Could not load the data container configuration for "' $strTable '"'__METHOD__TL_ERROR);
            
trigger_error('Could not load the data container configuration'E_USER_ERROR);
        }

        
// Set IDs and redirect
        
if (Input::post('FORM_SUBMIT') == 'tl_select')
        {
            
$ids Input::post('IDS');

            if (empty(
$ids) || !is_array($ids))
            {
                
$this->reload();
            }

            
$session $this->Session->getData();
            
$session['CURRENT']['IDS'] = $ids;
            
$this->Session->setData($session);

            if (isset(
$_POST['edit']))
            {
                
$this->redirect(str_replace('act=select''act=editAll'Environment::get('request')));
            }
            elseif (isset(
$_POST['delete']))
            {
                
$this->redirect(str_replace('act=select''act=deleteAll'Environment::get('request')));
            }
            elseif (isset(
$_POST['override']))
            {
                
$this->redirect(str_replace('act=select''act=overrideAll'Environment::get('request')));
            }
            elseif (isset(
$_POST['cut']) || isset($_POST['copy']))
            {
                
$arrClipboard $this->Session->get('CLIPBOARD');

                
$arrClipboard[$strTable] = array
                (
                    
'id' => $ids,
                    
'mode' => (isset($_POST['cut']) ? 'cutAll' 'copyAll')
                );

                
$this->Session->set('CLIPBOARD'$arrClipboard);

                
// Support copyAll in the list view (see #7499)
                
if (isset($_POST['copy']) && $GLOBALS['TL_DCA'][$strTable]['list']['sorting']['mode'] < 4)
                {
                    
$this->redirect(str_replace('act=select''act=copyAll'Environment::get('request')));
                }

                
$this->redirect($this->getReferer());
            }
        }

        
$this->strTable $strTable;
        
$this->ptable $GLOBALS['TL_DCA'][$this->strTable]['config']['ptable'];
        
$this->ctable $GLOBALS['TL_DCA'][$this->strTable]['config']['ctable'];
        
$this->treeView in_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'], array(56));
        
$this->root null;
        
$this->arrModule $arrModule;

        
// Call onload_callback (e.g. to check permissions)
        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onload_callback']))
        {
            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onload_callback'] as $callback)
            {
                if (
is_array($callback))
                {
                    
$this->import($callback[0]);
                    
$this->{$callback[0]}->{$callback[1]}($this);
                }
                elseif (
is_callable($callback))
                {
                    
$callback($this);
                }
            }
        }

        
// Get the IDs of all root records (tree view)
        
if ($this->treeView)
        {
            
$table = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->ptable $this->strTable;

             
// Unless there are any root records specified, use all records with parent ID 0
            
if (!isset($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']) || $GLOBALS['TL_DCA'][$table]['list']['sorting']['root'] === false)
            {
                
$objIds $this->Database->prepare("SELECT id FROM " $table " WHERE pid=?" . ($this->Database->fieldExists('sorting'$table) ? ' ORDER BY sorting' ''))
                                         ->
execute(0);

                if (
$objIds->numRows 0)
                {
                    
$this->root $objIds->fetchEach('id');
                }
            }

            
// Get root records from global configuration file
            
elseif (is_array($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']))
            {
                
$this->root $this->eliminateNestedPages($GLOBALS['TL_DCA'][$table]['list']['sorting']['root'], $table$this->Database->fieldExists('sorting'$table));
            }
        }

        
// Get the IDs of all root records (list view or parent view)
        
elseif (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root']))
        {
            
$this->root array_unique($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root']);
        }

        
// Store the current referer
        
if (!empty($this->ctable) && !Input::get('act') && !Input::get('key') && !Input::get('token') && TL_SCRIPT == 'contao/main.php' && !Environment::get('isAjaxRequest'))
        {
            
$session $this->Session->get('referer');
            
$session[TL_REFERER_ID][$this->strTable] = substr(Environment::get('requestUri'), strlen(TL_PATH) + 1);
            
$this->Session->set('referer'$session);
        }
    }


    
/**
     * Set an object property
     *
     * @param string $strKey
     * @param mixed  $varValue
     */
    
public function __set($strKey$varValue)
    {
        switch (
$strKey)
        {
            case 
'createNewVersion':
                
$this->blnCreateNewVersion = (bool) $varValue;
                break;

            default;
                
parent::__set($strKey$varValue);
                break;
        }
    }


    
/**
     * Return an object property
     *
     * @param string $strKey
     *
     * @return mixed
     */
    
public function __get($strKey)
    {
        switch (
$strKey)
        {
            case 
'id':
                return 
$this->intId;
                break;

            case 
'parentTable':
                return 
$this->ptable;
                break;

            case 
'childTable':
                return 
$this->ctable;
                break;

            case 
'rootIds':
                return 
$this->root;
                break;

            case 
'createNewVersion':
                return 
$this->blnCreateNewVersion;
                break;
        }

        return 
parent::__get($strKey);
    }


    
/**
     * List all records of a particular table
     *
     * @return string
     */
    
public function showAll()
    {
        
$return '';
        
$this->limit '';
        
$this->bid 'tl_buttons';

        
// Clean up old tl_undo and tl_log entries
        
if ($this->strTable == 'tl_undo' && strlen(Config::get('undoPeriod')))
        {
            
$this->Database->prepare("DELETE FROM tl_undo WHERE tstamp<?")
                           ->
execute(intval(time() - Config::get('undoPeriod')));
        }
        elseif (
$this->strTable == 'tl_log' && strlen(Config::get('logPeriod')))
        {
            
$this->Database->prepare("DELETE FROM tl_log WHERE tstamp<?")
                           ->
execute(intval(time() - Config::get('logPeriod')));
        }

        
$this->reviseTable();

        
// Add to clipboard
        
if (Input::get('act') == 'paste')
        {
            
$arrClipboard $this->Session->get('CLIPBOARD');

            
$arrClipboard[$this->strTable] = array
            (
                
'id' => Input::get('id'),
                
'childs' => Input::get('childs'),
                
'mode' => Input::get('mode')
            );

            
$this->Session->set('CLIPBOARD'$arrClipboard);
        }

        
// Custom filter
        
if (!empty($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter']) && is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter']))
        {
            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter'] as $filter)
            {
                
$this->procedure[] = $filter[0];
                
$this->values[] = $filter[1];
            }
        }

        
// Render view
        
if ($this->treeView)
        {
            
$return .= $this->panel();
            
$return .= $this->treeView();
        }
        else
        {
            if (
Input::get('table') && $this->ptable && $this->Database->fieldExists('pid'$this->strTable))
            {
                
$this->procedure[] = 'pid=?';
                
$this->values[] = CURRENT_ID;
            }

            
$return .= $this->panel();
            
$return .= ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) ? $this->parentView() : $this->listView();

            
// Add another panel at the end of the page
            
if (strpos($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['panelLayout'], 'limit') !== false)
            {
                
$return .= $this->paginationMenu();
            }
        }

        
// Store the current IDs
        
$session $this->Session->getData();
        
$session['CURRENT']['IDS'] = $this->current;
        
$this->Session->setData($session);

        return 
$return;
    }


    
/**
     * Return all non-excluded fields of a record as HTML table
     *
     * @return string
     */
    
public function show()
    {
        if (!
strlen($this->intId))
        {
            return 
'';
        }

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

        if (
$objRow->numRows 1)
        {
            return 
'';
        }

        
$count 1;
        
$return '';
        
$row $objRow->row();

        
// Get the order fields
        
$objDcaExtractor DcaExtractor::getInstance($this->strTable);
        
$arrOrder $objDcaExtractor->getOrderFields();

        
// Get all fields
        
$fields array_keys($row);
        
$allowedFields = array('id''pid''sorting''tstamp');

        if (
is_array($GLOBALS['TL_DCA'][$this->strTable]['fields']))
        {
            
$allowedFields array_unique(array_merge($allowedFieldsarray_keys($GLOBALS['TL_DCA'][$this->strTable]['fields'])));
        }

        
// Use the field order of the DCA file
        
$fields array_intersect($allowedFields$fields);

        
// Show all allowed fields
        
foreach ($fields as $i)
        {
            if (!
in_array($i$allowedFields) || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'password' || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['doNotShow'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['hideInput'])
            {
                continue;
            }

            
// Special treatment for table tl_undo
            
if ($this->strTable == 'tl_undo' && $i == 'data')
            {
                continue;
            }

            
$value deserialize($row[$i]);

            
// Decrypt the value
            
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['encrypt'])
            {
                
$value Encryption::decrypt($value);
            }

            
$class = (($count++ % 2) == 0) ? ' class="tl_bg"' '';

            
// Get the field value
            
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey']))
            {
                
$temp = array();
                
$chunks explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey'], 2);

                foreach ((array) 
$value as $v)
                {
                    
$objKey $this->Database->prepare("SELECT " $chunks[1] . " AS value FROM " $chunks[0] . " WHERE id=?")
                                             ->
limit(1)
                                             ->
execute($v);

                    if (
$objKey->numRows)
                    {
                        
$temp[] = $objKey->value;
                    }
                }

                
$row[$i] = implode(', '$temp);
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'fileTree' || in_array($i$arrOrder))
            {
                if (
is_array($value))
                {
                    foreach (
$value as $kk=>$vv)
                    {
                        
$value[$kk] = $vv StringUtil::binToUuid($vv) : '';
                    }

                    
$row[$i] = implode(', '$value);
                }
                else
                {
                    
$row[$i] = $value StringUtil::binToUuid($value) : '';
                }
            }
            elseif (
is_array($value))
            {
                foreach (
$value as $kk=>$vv)
                {
                    if (
is_array($vv))
                    {
                        
$vals array_values($vv);
                        
$value[$kk] = $vals[0].' ('.$vals[1].')';
                    }
                }

                
$row[$i] = implode(', '$value);
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'date')
            {
                
$row[$i] = $value Date::parse(Config::get('dateFormat'), $value) : '-';
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'time')
            {
                
$row[$i] = $value Date::parse(Config::get('timeFormat'), $value) : '-';
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'datim' || in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['flag'], array(5678910)) || $i == 'tstamp')
            {
                
$row[$i] = $value Date::parse(Config::get('datimFormat'), $value) : '-';
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['multiple'])
            {
                
$row[$i] = ($value != '') ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no'];
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'textarea' && ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['allowHtml'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['preserveTags']))
            {
                
$row[$i] = specialchars($value);
            }
            elseif (
is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference']))
            {
                
$row[$i] = isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) ? ((is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]])) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) : $row[$i];
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options']))
            {
                
$row[$i] = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options'][$row[$i]];
            }
            else
            {
                
$row[$i] = $value;
            }

            
// Label
            
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']))
            {
                
$label is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'];
            }
            else
            {
                
$label is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i];
            }

            if (
$label == '')
            {
                
$label $i;
            }

            
$return .= '
  <tr>
    <td'
.$class.'><span class="tl_label">'.$label.': </span></td>
    <td'
.$class.'>'.$row[$i].'</td>
  </tr>'
;
        }

        
// Special treatment for tl_undo
        
if ($this->strTable == 'tl_undo')
        {
            
$arrData deserialize($objRow->data);

            foreach (
$arrData as $strTable=>$arrTableData)
            {
                
System::loadLanguageFile($strTable);
                
$this->loadDataContainer($strTable);

                foreach (
$arrTableData as $arrRow)
                {
                    
$count 0;
                    
$return .= '
  <tr>
    <td colspan="2" style="padding:0"><div style="margin-bottom:26px;line-height:24px;border-bottom:1px dotted #ccc">&nbsp;</div></td>
  </tr>'
;

                    foreach (
$arrRow as $i=>$v)
                    {
                        if (
is_array(deserialize($v)))
                        {
                            continue;
                        }

                        
$class = (($count++ % 2) == 0) ? ' class="tl_bg"' '';

                        
// Get the field label
                        
if (isset($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']))
                        {
                            
$label is_array($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'];
                        }
                        else
                        {
                            
$label is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i];
                        }

                        if (!
strlen($label))
                        {
                            
$label $i;
                        }

                        
// Always encode special characters (thanks to Oliver Klee)
                        
$return .= '
  <tr>
    <td'
.$class.'><span class="tl_label">'.$label.': </span></td>
    <td'
.$class.'>'.specialchars($v).'</td>
  </tr>'
;
                    }
                }
            }
        }

        
// Return table
        
return '
<div id="tl_buttons">' 
. (!Input::get('popup') ? '
<a href="'
.$this->getReferer(true).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>' '') . '
</div>

<table class="tl_show">'
.$return.'
</table>'
;
    }


    
/**
     * Insert a new row into a database table
     *
     * @param array $set
     */
    
public function create($set=array())
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not creatable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
// Get all default values for the new entry
        
foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'] as $k=>$v)
        {
            
// Use array_key_exists here (see #5252)
            
if (array_key_exists('default'$v))
            {
                
$this->set[$k] = is_array($v['default']) ? serialize($v['default']) : $v['default'];

                
// Encrypt the default value (see #3740)
                
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['encrypt'])
                {
                    
$this->set[$k] = Encryption::encrypt($this->set[$k]);
                }
            }
        }

        
// Set passed values
        
if (!empty($set) && is_array($set))
        {
            
$this->set array_merge($this->set$set);
        }

        
// Get the new position
        
$this->getNewPosition('new', (strlen(Input::get('pid')) ? Input::get('pid') : null), (Input::get('mode') == '2' true false));

        
// Dynamically set the parent table of tl_content
        
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
        {
            
$this->set['ptable'] = $this->ptable;
        }

        
// Empty the clipboard
        
$arrClipboard $this->Session->get('CLIPBOARD');
        
$arrClipboard[$this->strTable] = array();
        
$this->Session->set('CLIPBOARD'$arrClipboard);

        
// Insert the record if the table is not closed and switch to edit mode
        
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'])
        {
            
$this->set['tstamp'] = 0;

            
$objInsertStmt $this->Database->prepare("INSERT INTO " $this->strTable " %s")
                                            ->
set($this->set)
                                            ->
execute();

            if (
$objInsertStmt->affectedRows)
            {
                
$s2e $GLOBALS['TL_DCA'][$this->strTable]['config']['switchToEdit'] ? '&s2e=1' '';
                
$insertID $objInsertStmt->insertId;

                
// Save new record in the session
                
$new_records $this->Session->get('new_records');
                
$new_records[$this->strTable][] = $insertID;
                
$this->Session->set('new_records'$new_records);

                
// Call the oncreate_callback
                
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['oncreate_callback']))
                {
                    foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['oncreate_callback'] as $callback)
                    {
                        if (
is_array($callback))
                        {
                            
$this->import($callback[0]);
                            
$this->{$callback[0]}->{$callback[1]}($this->strTable$insertID$this->set$this);
                        }
                        elseif (
is_callable($callback))
                        {
                            
$callback($this->strTable$insertID$this->set$this);
                        }
                    }
                }

                
// Add a log entry
                
$this->log('A new entry "'.$this->strTable.'.id='.$insertID.'" has been created'.$this->getParentEntries($this->strTable$insertID), __METHOD__TL_GENERAL);
                
$this->redirect($this->switchToEdit($insertID).$s2e);
            }
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Assign a new position to an existing record
     *
     * @param boolean $blnDoNotRedirect
     */
    
public function cut($blnDoNotRedirect=false)
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not sortable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$cr = array();

        
// ID and PID are mandatory
        
if (!$this->intId || !strlen(Input::get('pid')))
        {
            
$this->redirect($this->getReferer());
        }

        
// Get the new position
        
$this->getNewPosition('cut'Input::get('pid'), (Input::get('mode') == '2' true false));

        
// Avoid circular references when there is no parent table
        
if ($this->Database->fieldExists('pid'$this->strTable) && !strlen($this->ptable))
        {
            
$cr $this->Database->getChildRecords($this->intId$this->strTable);
            
$cr[] = $this->intId;
        }

        
// Empty clipboard
        
$arrClipboard $this->Session->get('CLIPBOARD');
        
$arrClipboard[$this->strTable] = array();
        
$this->Session->set('CLIPBOARD'$arrClipboard);

        
// Update the record
        
if (in_array($this->set['pid'], $cr))
        {
            
$this->log('Attempt to relate record '.$this->intId.' of table "'.$this->strTable.'" to its child record '.Input::get('pid').' (circular reference)'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$this->set['tstamp'] = time();

        
// HOOK: style sheet category
        
if ($this->strTable == 'tl_style')
        {
            
$filter $this->Session->get('filter');
            
$category $filter['tl_style_' CURRENT_ID]['category'];

            if (
$category != '')
            {
                
$this->set['category'] = $category;
            }
        }

        
// Dynamically set the parent table of tl_content
        
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
        {
            
$this->set['ptable'] = $this->ptable;
        }

        
$this->Database->prepare("UPDATE " $this->strTable " %s WHERE id=?")
                       ->
set($this->set)
                       ->
execute($this->intId);

        
// Call the oncut_callback
        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['oncut_callback']))
        {
            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['oncut_callback'] as $callback)
            {
                if (
is_array($callback))
                {
                    
$this->import($callback[0]);
                    
$this->{$callback[0]}->{$callback[1]}($this);
                }
                elseif (
is_callable($callback))
                {
                    
$callback($this);
                }
            }
        }

        if (!
$blnDoNotRedirect)
        {
            
$this->redirect($this->getReferer());
        }
    }


    
/**
     * Move all selected records
     */
    
public function cutAll()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not sortable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$arrClipboard $this->Session->get('CLIPBOARD');

        if (isset(
$arrClipboard[$this->strTable]) && is_array($arrClipboard[$this->strTable]['id']))
        {
            foreach (
$arrClipboard[$this->strTable]['id'] as $id)
            {
                
$this->intId $id;
                
$this->cut(true);
                
Input::setGet('pid'$id);
                
Input::setGet('mode'1);
            }
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Duplicate a particular record of the current table
     *
     * @param boolean $blnDoNotRedirect
     *
     * @return integer|boolean
     */
    
public function copy($blnDoNotRedirect=false)
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not copyable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        if (!
$this->intId)
        {
            
$this->redirect($this->getReferer());
        }

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

        
// Copy the values if the record contains data
        
if ($objRow->numRows)
        {
            foreach (
$objRow->row() as $k=>$v)
            {
                if (
in_array($karray_keys($GLOBALS['TL_DCA'][$this->strTable]['fields'])))
                {
                    
// Never copy passwords
                    
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['inputType'] == 'password')
                    {
                        
$v Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['sql']);
                    }

                    
// Empty unique fields or add a unique identifier in copyAll mode
                    
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['unique'])
                    {
                        
$v = (Input::get('act') == 'copyAll') ? $v .'-'substr(md5(uniqid(mt_rand(), true)), 08) : Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['sql']);
                    }

                    
// Reset doNotCopy and fallback fields to their default value
                    
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['doNotCopy'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['fallback'])
                    {
                        
$v '';

                        
// Use array_key_exists to allow NULL (see #5252)
                        
if (array_key_exists('default'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]))
                        {
                            
$v is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['default']) ? serialize($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['default']) : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['default'];
                        }

                        
// Encrypt the default value (see #3740)
                        
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['encrypt'])
                        {
                            
$v Encryption::encrypt($v);
                        }
                    }

                    
$this->set[$k] = $v;
                }
            }

            
// HOOK: style sheet category
            
if ($this->strTable == 'tl_style')
            {
                
$filter $this->Session->get('filter');
                
$category $filter['tl_style_' CURRENT_ID]['category'];

                if (
$category != '')
                {
                    
$this->set['category'] = $category;
                }
            }
        }

        
// Get the new position
        
$this->getNewPosition('copy', (strlen(Input::get('pid')) ? Input::get('pid') : null), (Input::get('mode') == '2' true false));

        
// Dynamically set the parent table of tl_content
        
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
        {
            
$this->set['ptable'] = $this->ptable;
        }

        
// Empty clipboard
        
$arrClipboard $this->Session->get('CLIPBOARD');
        
$arrClipboard[$this->strTable] = array();
        
$this->Session->set('CLIPBOARD'$arrClipboard);

        
// Insert the record if the table is not closed and switch to edit mode
        
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'])
        {
            
$this->set['tstamp'] = ($blnDoNotRedirect time() : 0);

            
// Mark the new record with "copy of" (see #2938)
            
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields']['name']))
            {
                if (
$this->set['name'] != '')
                {
                    
$this->set['name'] = sprintf($GLOBALS['TL_LANG']['MSC']['copyOf'], $this->set['name']);
                }
            }
            elseif (isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields']['title']))
            {
                if (
$this->set['title'] != '')
                {
                    
$this->set['title'] = sprintf($GLOBALS['TL_LANG']['MSC']['copyOf'], $this->set['title']);
                }
            }
            elseif (isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields']['headline']))
            {
                
$headline deserialize($this->set['headline']);

                if (!
is_array($headline))
                {
                    if (
$this->set['headline'] != '')
                    {
                        
$this->set['headline'] = sprintf($GLOBALS['TL_LANG']['MSC']['copyOf'], $this->set['headline']);
                    }
                }
            }

            
// Remove the ID field from the data array
            
unset($this->set['id']);

            
$objInsertStmt $this->Database->prepare("INSERT INTO " $this->strTable " %s")
                                            ->
set($this->set)
                                            ->
execute();

            if (
$objInsertStmt->affectedRows)
            {
                
$insertID $objInsertStmt->insertId;

                
// Save the new record in the session
                
if (!$blnDoNotRedirect)
                {
                    
$new_records $this->Session->get('new_records');
                    
$new_records[$this->strTable][] = $insertID;
                    
$this->Session->set('new_records'$new_records);
                }

                
// Duplicate the records of the child table
                
$this->copyChilds($this->strTable$insertID$this->intId$insertID);

                
// Call the oncopy_callback after all new records have been created
                
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['oncopy_callback']))
                {
                    foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['oncopy_callback'] as $callback)
                    {
                        if (
is_array($callback))
                        {
                            
$this->import($callback[0]);
                            
$this->{$callback[0]}->{$callback[1]}($insertID$this);
                        }
                        elseif (
is_callable($callback))
                        {
                            
$callback($insertID$this);
                        }
                    }
                }

                
// Add a log entry
                
$this->log('A new entry "'.$this->strTable.'.id='.$insertID.'" has been created by duplicating record "'.$this->strTable.'.id='.$this->intId.'"'.$this->getParentEntries($this->strTable$insertID), __METHOD__TL_GENERAL);

                
// Switch to edit mode
                
if (!$blnDoNotRedirect)
                {
                    
$this->redirect($this->switchToEdit($insertID));
                }

                return 
$insertID;
            }
        }

        if (!
$blnDoNotRedirect)
        {
            
$this->redirect($this->getReferer());
        }

        return 
false;
    }


    
/**
     * Duplicate all child records of a duplicated record
     *
     * @param string  $table
     * @param integer $insertID
     * @param integer $id
     * @param integer $parentId
     */
    
protected function copyChilds($table$insertID$id$parentId)
    {
        
$time time();
        
$copy = array();
        
$cctable = array();
        
$ctable $GLOBALS['TL_DCA'][$table]['config']['ctable'];

        if (!
$GLOBALS['TL_DCA'][$table]['config']['ptable'] && strlen(Input::get('childs')) && $this->Database->fieldExists('pid'$table) && $this->Database->fieldExists('sorting'$table))
        {
            
$ctable[] = $table;
        }

        if (!
is_array($ctable))
        {
            return;
        }

        
// Walk through each child table
        
foreach ($ctable as $v)
        {
            
$this->loadDataContainer($v);
            
$cctable[$v] = $GLOBALS['TL_DCA'][$v]['config']['ctable'];

            if (!
$GLOBALS['TL_DCA'][$v]['config']['doNotCopyRecords'] && strlen($v))
            {
                
// Consider the dynamic parent table (see #4867)
                
if ($GLOBALS['TL_DCA'][$v]['config']['dynamicPtable'])
                {
                    
$ptable $GLOBALS['TL_DCA'][$v]['config']['ptable'];
                    
$cond = ($ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?"// backwards compatibility

                    
$objCTable $this->Database->prepare("SELECT * FROM $v WHERE pid=? AND $cond. ($this->Database->fieldExists('sorting'$v) ? " ORDER BY sorting" ""))
                                                ->
execute($id$ptable);
                }
                else
                {
                    
$objCTable $this->Database->prepare("SELECT * FROM $v WHERE pid=?" . ($this->Database->fieldExists('sorting'$v) ? " ORDER BY sorting" ""))
                                                ->
execute($id);
                }

                while (
$objCTable->next())
                {
                    
// Exclude the duplicated record itself
                    
if ($v == $table && $objCTable->id == $parentId)
                    {
                        continue;
                    }

                    foreach (
$objCTable->row() as $kk=>$vv)
                    {
                        if (
$kk == 'id')
                        {
                            continue;
                        }

                        
// Never copy passwords
                        
if ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['inputType'] == 'password')
                        {
                            
$vv Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$v]['fields'][$kk]['sql']);
                        }

                        
// Empty unique fields or add a unique identifier in copyAll mode
                        
elseif ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['unique'])
                        {
                            
$vv = (Input::get('act') == 'copyAll') ? $vv .'-'substr(md5(uniqid(mt_rand(), true)), 08) : Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$v]['fields'][$kk]['sql']);
                        }

                        
// Reset doNotCopy and fallback fields to their default value
                        
elseif ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['doNotCopy'] || $GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['fallback'])
                        {
                            
$vv '';

                            
// Use array_key_exists to allow NULL (see #5252)
                            
if (array_key_exists('default'$GLOBALS['TL_DCA'][$v]['fields'][$kk]))
                            {
                                
$vv is_array($GLOBALS['TL_DCA'][$v]['fields'][$kk]['default']) ? serialize($GLOBALS['TL_DCA'][$v]['fields'][$kk]['default']) : $GLOBALS['TL_DCA'][$v]['fields'][$kk]['default'];
                            }

                            
// Encrypt the default value (see #3740)
                            
if ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['encrypt'])
                            {
                                
$vv Encryption::encrypt($vv);
                            }
                        }

                        
$copy[$v][$objCTable->id][$kk] = $vv;
                    }

                    
$copy[$v][$objCTable->id]['pid'] = $insertID;
                    
$copy[$v][$objCTable->id]['tstamp'] = $time;
                }
            }
        }

        
// Duplicate the child records
        
foreach ($copy as $k=>$v)
        {
            if (!empty(
$v))
            {
                foreach (
$v as $kk=>$vv)
                {
                    
$objInsertStmt $this->Database->prepare("INSERT INTO " $k " %s")
                                                    ->
set($vv)
                                                    ->
execute();

                    if (
$objInsertStmt->affectedRows)
                    {
                        
$insertID $objInsertStmt->insertId;

                        if ((!empty(
$cctable[$k]) || $GLOBALS['TL_DCA'][$k]['list']['sorting']['mode'] == 5) && $kk != $parentId)
                        {
                            
$this->copyChilds($k$insertID$kk$parentId);
                        }
                    }
                }
            }
        }
    }


    
/**
     * Move all selected records
     */
    
public function copyAll()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not copyable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$arrClipboard $this->Session->get('CLIPBOARD');

        if (isset(
$arrClipboard[$this->strTable]) && is_array($arrClipboard[$this->strTable]['id']))
        {
            foreach (
$arrClipboard[$this->strTable]['id'] as $id)
            {
                
$this->intId $id;
                
$id $this->copy(true);
                
Input::setGet('pid'$id);
                
Input::setGet('mode'1);
            }
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Calculate the new position of a moved or inserted record
     *
     * @param string  $mode
     * @param integer $pid
     * @param boolean $insertInto
     */
    
protected function getNewPosition($mode$pid=null$insertInto=false)
    {
        
// If there is pid and sorting
        
if ($this->Database->fieldExists('pid'$this->strTable) && $this->Database->fieldExists('sorting'$this->strTable))
        {
            
// PID is not set - only valid for duplicated records, as they get the same parent ID as the original record!
            
if ($pid === null && $this->intId && $mode == 'copy')
            {
                
$pid $this->intId;
            }

            
// PID is set (insert after or into the parent record)
            
if (is_numeric($pid))
            {
                
$newPID null;
                
$newSorting null;
                
$session $this->Session->getData();
                
$filter = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) ? $this->strTable.'_'.CURRENT_ID $this->strTable;

                
// Consider the pagination menu when inserting at the top (see #7895)
                
if ($insertInto && isset($session['filter'][$filter]['limit']))
                {
                    
$limit substr($session['filter'][$filter]['limit'], 0strpos($session['filter'][$filter]['limit'], ','));

                    if (
$limit 0)
                    {
                        
$objInsertAfter $this->Database->prepare("SELECT id FROM " $this->strTable " WHERE pid=? ORDER BY sorting" )
                                                         ->
limit(1$limit 1)
                                                         ->
execute($pid);

                        if (
$objInsertAfter->numRows)
                        {
                            
$insertInto false;
                            
$pid $objInsertAfter->id;
                        }
                    }
                }

                
// Insert the current record at the beginning when inserting into the parent record
                
if ($insertInto)
                {
                    
$newPID $pid;

                    
$objSorting $this->Database->prepare("SELECT MIN(sorting) AS sorting FROM " $this->strTable " WHERE pid=?")
                                                 ->
execute($pid);

                    
// Select sorting value of the first record
                    
if ($objSorting->numRows)
                    {
                        
$curSorting $objSorting->sorting;

                        
// Resort if the new sorting value is not an integer or smaller than 1
                        
if (($curSorting 2) != || $curSorting 1)
                        {
                            
$objNewSorting $this->Database->prepare("SELECT id FROM " $this->strTable " WHERE pid=? ORDER BY sorting" )
                                                            ->
execute($pid);

                            
$count 2;
                            
$newSorting 128;

                            while (
$objNewSorting->next())
                            {
                                
$this->Database->prepare("UPDATE " $this->strTable " SET sorting=? WHERE id=?")
                                               ->
limit(1)
                                               ->
execute(($count++ * 128), $objNewSorting->id);
                            }
                        }

                        
// Else new sorting = (current sorting / 2)
                        
else $newSorting = ($curSorting 2);
                    }

                    
// Else new sorting = 128
                    
else $newSorting 128;
                }

                
// Else insert the current record after the parent record
                
elseif ($pid 0)
                {
                    
$objSorting $this->Database->prepare("SELECT pid, sorting FROM " $this->strTable " WHERE id=?")
                                                 ->
limit(1)
                                                 ->
execute($pid);

                    
// Set parent ID of the current record as new parent ID
                    
if ($objSorting->numRows)
                    {
                        
$newPID $objSorting->pid;
                        
$curSorting $objSorting->sorting;

                        
// Do not proceed without a parent ID
                        
if (is_numeric($newPID))
                        {
                            
$objNextSorting $this->Database->prepare("SELECT MIN(sorting) AS sorting FROM " $this->strTable " WHERE pid=? AND sorting>?")
                                                             ->
execute($newPID$curSorting);

                            
// Select sorting value of the next record
                            
if ($objNextSorting->sorting !== null)
                            {
                                
$nxtSorting $objNextSorting->sorting;

                                
// Resort if the new sorting value is no integer or bigger than a MySQL integer
                                
if ((($curSorting $nxtSorting) % 2) != || $nxtSorting >= 4294967295)
                                {
                                    
$count 1;

                                    
$objNewSorting $this->Database->prepare("SELECT id, sorting FROM " $this->strTable " WHERE pid=? ORDER BY sorting")
                                                                    ->
execute($newPID);

                                    while (
$objNewSorting->next())
                                    {
                                        
$this->Database->prepare("UPDATE " $this->strTable " SET sorting=? WHERE id=?")
                                                       ->
execute(($count++ * 128), $objNewSorting->id);

                                        if (
$objNewSorting->sorting == $curSorting)
                                        {
                                            
$newSorting = ($count++ * 128);
                                        }
                                    }
                                }

                                
// Else new sorting = (current sorting + next sorting) / 2
                                
else $newSorting = (($curSorting $nxtSorting) / 2);
                            }

                            
// Else new sorting = (current sorting + 128)
                            
else $newSorting = ($curSorting 128);
                        }
                    }

                    
// Use the given parent ID as parent ID
                    
else
                    {
                        
$newPID $pid;
                        
$newSorting 128;
                    }
                }

                
// Set new sorting and new parent ID
                
$this->set['pid'] = intval($newPID);
                
$this->set['sorting'] = intval($newSorting);
            }
        }

        
// If there is only pid
        
elseif ($this->Database->fieldExists('pid'$this->strTable))
        {
            
// PID is not set - only valid for duplicated records, as they get the same parent ID as the original record!
            
if ($pid === null && $this->intId && $mode == 'copy')
            {
                
$pid $this->intId;
            }

            
// PID is set (insert after or into the parent record)
            
if (is_numeric($pid))
            {
                
// Insert the current record into the parent record
                
if ($insertInto)
                {
                    
$this->set['pid'] = $pid;
                }

                
// Else insert the current record after the parent record
                
elseif ($pid 0)
                {
                    
$objParentRecord $this->Database->prepare("SELECT pid FROM " $this->strTable " WHERE id=?")
                                                      ->
limit(1)
                                                      ->
execute($pid);

                    if (
$objParentRecord->numRows)
                    {
                        
$this->set['pid'] = $objParentRecord->pid;
                    }
                }
            }
        }

        
// If there is only sorting
        
elseif ($this->Database->fieldExists('sorting'$this->strTable))
        {
            
// ID is set (insert after the current record)
            
if ($this->intId)
            {
                
$objCurrentRecord $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                                   ->
limit(1)
                                                   ->
execute($this->intId);

                
// Select current record
                
if ($objCurrentRecord->numRows)
                {
                    
$newSorting null;
                    
$curSorting $objCurrentRecord->sorting;

                    
$objNextSorting $this->Database->prepare("SELECT MIN(sorting) AS sorting FROM " $this->strTable " WHERE sorting>?")
                                                     ->
execute($curSorting);

                    
// Select sorting value of the next record
                    
if ($objNextSorting->numRows)
                    {
                        
$nxtSorting $objNextSorting->sorting;

                        
// Resort if the new sorting value is no integer or bigger than a MySQL integer field
                        
if ((($curSorting $nxtSorting) % 2) != || $nxtSorting >= 4294967295)
                        {
                            
$count 1;

                            
$objNewSorting $this->Database->execute("SELECT id, sorting FROM " $this->strTable " ORDER BY sorting");

                            while (
$objNewSorting->next())
                            {
                                
$this->Database->prepare("UPDATE " $this->strTable " SET sorting=? WHERE id=?")
                                               ->
execute(($count++ * 128), $objNewSorting->id);

                                if (
$objNewSorting->sorting == $curSorting)
                                {
                                    
$newSorting = ($count++ * 128);
                                }
                            }
                        }

                        
// Else new sorting = (current sorting + next sorting) / 2
                        
else $newSorting = (($curSorting $nxtSorting) / 2);
                    }

                    
// Else new sorting = (current sorting + 128)
                    
else $newSorting = ($curSorting 128);

                    
// Set new sorting
                    
$this->set['sorting'] = intval($newSorting);

                    return;
                }
            }

            
// ID is not set or not found (insert at the end)
            
$objNextSorting $this->Database->execute("SELECT MAX(sorting) AS sorting FROM " $this->strTable);
            
$this->set['sorting'] = (intval($objNextSorting->sorting) + 128);
        }
    }


    
/**
     * Delete a record of the current table table and save it to tl_undo
     *
     * @param boolean $blnDoNotRedirect
     */
    
public function delete($blnDoNotRedirect=false)
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not deletable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        if (!
$this->intId)
        {
            
$this->redirect($this->getReferer());
        }

        
$delete = array();

        
// Do not save records from tl_undo itself
        
if ($this->strTable == 'tl_undo')
        {
            
$this->Database->prepare("DELETE FROM " $this->strTable " WHERE id=?")
                           ->
limit(1)
                           ->
execute($this->intId);

            
$this->redirect($this->getReferer());
        }

        
// If there is a PID field but no parent table
        
if ($this->Database->fieldExists('pid'$this->strTable) && !strlen($this->ptable))
        {
            
$delete[$this->strTable] = $this->Database->getChildRecords($this->intId$this->strTable);
            
array_unshift($delete[$this->strTable], $this->intId);
        }
        else
        {
            
$delete[$this->strTable] = array($this->intId);
        }

        
// Delete all child records if there is a child table
        
if (!empty($this->ctable))
        {
            foreach (
$delete[$this->strTable] as $id)
            {
                
$this->deleteChilds($this->strTable$id$delete);
            }
        }

        
$affected 0;
        
$data = array();

        
// Save each record of each table
        
foreach ($delete as $table=>$fields)
        {
            foreach (
$fields as $k=>$v)
            {
                
$objSave $this->Database->prepare("SELECT * FROM " $table " WHERE id=?")
                                          ->
limit(1)
                                          ->
execute($v);

                if (
$objSave->numRows)
                {
                    
$data[$table][$k] = $objSave->row();

                    
// Store the active record
                    
if ($table == $this->strTable && $v == $this->intId)
                    {
                        
$this->objActiveRecord $objSave;
                    }
                }

                
$affected++;
            }
        }

        
$this->import('BackendUser''User');

        
$objUndoStmt $this->Database->prepare("INSERT INTO tl_undo (pid, tstamp, fromTable, query, affectedRows, data) VALUES (?, ?, ?, ?, ?, ?)")
                                      ->
execute($this->User->idtime(), $this->strTable'DELETE FROM '.$this->strTable.' WHERE id='.$this->intId$affectedserialize($data));

        
// Delete the records
        
if ($objUndoStmt->affectedRows)
        {
            
$insertID $objUndoStmt->insertId;

            
// Call ondelete_callback
            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['ondelete_callback']))
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['ondelete_callback'] as $callback)
                {
                    if (
is_array($callback))
                    {
                        
$this->import($callback[0]);
                        
$this->{$callback[0]}->{$callback[1]}($this$insertID);
                    }
                    elseif (
is_callable($callback))
                    {
                        
$callback($this$insertID);
                    }
                }
            }

            
// Delete the records
            
foreach ($delete as $table=>$fields)
            {
                foreach (
$fields as $v)
                {
                    
$this->Database->prepare("DELETE FROM " $table " WHERE id=?")
                                   ->
limit(1)
                                   ->
execute($v);
                }
            }

            
// Add a log entry unless we are deleting from tl_log itself
            
if ($this->strTable != 'tl_log')
            {
                
$this->log('DELETE FROM '.$this->strTable.' WHERE id='.$data[$this->strTable][0]['id'], __METHOD__TL_GENERAL);
            }
        }

        if (!
$blnDoNotRedirect)
        {
            
$this->redirect($this->getReferer());
        }
    }


    
/**
     * Delete all selected records
     */
    
public function deleteAll()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not deletable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$session $this->Session->getData();
        
$ids $session['CURRENT']['IDS'];

        if (
is_array($ids) && strlen($ids[0]))
        {
            foreach (
$ids as $id)
            {
                
$this->intId $id;
                
$this->delete(true);
            }
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Recursively get all related table names and records
     *
     * @param string  $table
     * @param integer $id
     * @param array   $delete
     */
    
public function deleteChilds($table$id, &$delete)
    {
        
$cctable = array();
        
$ctable $GLOBALS['TL_DCA'][$table]['config']['ctable'];

        if (!
is_array($ctable))
        {
            return;
        }

        
// Walk through each child table
        
foreach ($ctable as $v)
        {
            
$this->loadDataContainer($v);
            
$cctable[$v] = $GLOBALS['TL_DCA'][$v]['config']['ctable'];

            
// Consider the dynamic parent table (see #4867)
            
if ($GLOBALS['TL_DCA'][$v]['config']['dynamicPtable'])
            {
                
$ptable $GLOBALS['TL_DCA'][$v]['config']['ptable'];
                
$cond = ($ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?"// backwards compatibility

                
$objDelete $this->Database->prepare("SELECT id FROM $v WHERE pid=? AND $cond")
                                            ->
execute($id$ptable);
            }
            else
            {
                
$objDelete $this->Database->prepare("SELECT id FROM $v WHERE pid=?")
                                            ->
execute($id);
            }

            if (!
$GLOBALS['TL_DCA'][$v]['config']['doNotDeleteRecords'] && strlen($v) && $objDelete->numRows)
            {
                foreach (
$objDelete->fetchAllAssoc() as $row)
                {
                    
$delete[$v][] = $row['id'];

                    if (!empty(
$cctable[$v]))
                    {
                        
$this->deleteChilds($v$row['id'], $delete);
                    }
                }
            }
        }
    }


    
/**
     * Restore one or more deleted records
     */
    
public function undo()
    {
        
$objRecords $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                     ->
limit(1)
                                     ->
execute($this->intId);

        
// Check whether there is a record
        
if ($objRecords->numRows 1)
        {
            
$this->redirect($this->getReferer());
        }

        
$error false;
        
$query $objRecords->query;
        
$data deserialize($objRecords->data);

        if (!
is_array($data))
        {
            
$this->redirect($this->getReferer());
        }

        
$arrFields = array();

        
// Restore the data
        
foreach ($data as $table=>$fields)
        {
            
$this->loadDataContainer($table);

            
// Get the currently available fields
            
if (!isset($arrFields[$table]))
            {
                
$arrFields[$table] = array_flip($this->Database->getFieldnames($table));
            }

            foreach (
$fields as $row)
            {
                
// Unset fields that no longer exist in the database
                
$row array_intersect_key($row$arrFields[$table]);

                
// Re-insert the data
                
$objInsertStmt $this->Database->prepare("INSERT INTO " $table " %s")
                                                ->
set($row)
                                                ->
execute();

                
// Do not delete record from tl_undo if there is an error
                
if ($objInsertStmt->affectedRows 1)
                {
                    
$error true;
                }

                
// Trigger the undo_callback
                
if (is_array($GLOBALS['TL_DCA'][$table]['config']['onundo_callback']))
                {
                    foreach (
$GLOBALS['TL_DCA'][$table]['config']['onundo_callback'] as $callback)
                    {
                        if (
is_array($callback))
                        {
                            
$this->import($callback[0]);
                            
$this->{$callback[0]}->{$callback[1]}($table$row$this);
                        }
                        elseif (
is_callable($callback))
                        {
                            
$callback($table$row$this);
                        }
                    }
                }
            }
        }

        
// Add log entry and delete record from tl_undo if there was no error
        
if (!$error)
        {
            
$this->log('Undone '$query__METHOD__TL_GENERAL);

            
$this->Database->prepare("DELETE FROM " $this->strTable " WHERE id=?")
                           ->
limit(1)
                           ->
execute($this->intId);
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Change the order of two neighbour database records
     */
    
public function move()
    {
        
// Proceed only if all mandatory variables are set
        
if ($this->intId && Input::get('sid') && (!$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root'] || !in_array($this->intId$this->root)))
        {
            
$objRow $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=? OR id=?")
                                     ->
limit(2)
                                     ->
execute($this->intIdInput::get('sid'));

            
$row $objRow->fetchAllAssoc();

            if (
$row[0]['pid'] == $row[1]['pid'])
            {
                
$this->Database->prepare("UPDATE " $this->strTable " SET sorting=? WHERE id=?")
                               ->
execute($row[0]['sorting'], $row[1]['id']);

                
$this->Database->prepare("UPDATE " $this->strTable " SET sorting=? WHERE id=?")
                               ->
execute($row[1]['sorting'], $row[0]['id']);
            }
        }

        
$this->redirect($this->getReferer());
    }


    
/**
     * Auto-generate a form to edit the current database record
     *
     * @param integer $intId
     * @param integer $ajaxId
     *
     * @return string
     */
    
public function edit($intId=null$ajaxId=null)
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not editable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        if (
$intId != '')
        {
            
$this->intId $intId;
        }

        
// Get the current record
        
$objRow $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                 ->
limit(1)
                                 ->
execute($this->intId);

        
// Redirect if there is no record with the given ID
        
if ($objRow->numRows 1)
        {
            
$this->log('Could not load record "'.$this->strTable.'.id='.$this->intId.'"'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$this->objActiveRecord $objRow;

        
$return '';
        
$this->values[] = $this->intId;
        
$this->procedure[] = 'id=?';

        
$this->blnCreateNewVersion false;
        
$objVersions = new Versions($this->strTable$this->intId);

        if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['hideVersionMenu'])
        {
            
// Compare versions
            
if (Input::get('versions'))
            {
                
$objVersions->compare();
            }

            
// Restore a version
            
if (Input::post('FORM_SUBMIT') == 'tl_version' && Input::post('version') != '')
            {
                
$objVersions->restore(Input::post('version'));
                
$this->reload();
            }
        }

        
$objVersions->initialize();

        
// Build an array from boxes and rows
        
$this->strPalette $this->getPalette();
        
$boxes trimsplit(';'$this->strPalette);
        
$legends = array();

        if (!empty(
$boxes))
        {
            foreach (
$boxes as $k=>$v)
            {
                
$eCount 1;
                
$boxes[$k] = trimsplit(','$v);

                foreach (
$boxes[$k] as $kk=>$vv)
                {
                    if (
preg_match('/^[.*]$/'$vv))
                    {
                        ++
$eCount;
                        continue;
                    }

                    if (
preg_match('/^{.*}$/'$vv))
                    {
                        
$legends[$k] = substr($vv1, -1);
                        unset(
$boxes[$k][$kk]);
                    }
                    elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$vv]['exclude'] || !is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$vv]))
                    {
                        unset(
$boxes[$k][$kk]);
                    }
                }

                
// Unset a box if it does not contain any fields
                
if (count($boxes[$k]) < $eCount)
                {
                    unset(
$boxes[$k]);
                }
            }

            
$class 'tl_tbox';
            
$fs $this->Session->get('fieldset_states');
            
$blnIsFirst true;

            
// Render boxes
            
foreach ($boxes as $k=>$v)
            {
                
$strAjax '';
                
$blnAjax false;
                
$key '';
                
$cls '';
                
$legend '';

                if (isset(
$legends[$k]))
                {
                    list(
$key$cls) = explode(':'$legends[$k]);
                    
$legend "n" '<legend onclick="AjaxRequest.toggleFieldset(this,'' . $key . '','' . $this->strTable . '')">' . (isset($GLOBALS['TL_LANG'][$this->strTable][$key]) ? $GLOBALS['TL_LANG'][$this->strTable][$key] : $key) . '</legend>';
                }

                if (isset(
$fs[$this->strTable][$key]))
                {
                    
$class .= ($fs[$this->strTable][$key] ? '' ' collapsed');
                }
                else
                {
                    
$class .= (($cls && $legend) ? ' ' $cls '');
                }

                
$return .= "nn" '<fieldset' . ($key ' id="pal_'.$key.'"' '') . ' class="' $class . ($legend '' ' nolegend') . '">' $legend;

                
// Build rows of the current box
                
foreach ($v as $vv)
                {
                    if (
$vv == '[EOF]')
                    {
                        if (
$blnAjax && Environment::get('isAjaxRequest'))
                        {
                            return 
$strAjax '<input type="hidden" name="FORM_FIELDS[]" value="'.specialchars($this->strPalette).'">';
                        }

                        
$blnAjax false;
                        
$return .= "n" '</div>';

                        continue;
                    }

                    if (
preg_match('/^[.*]$/'$vv))
                    {
                        
$thisId 'sub_' substr($vv1, -1);
                        
$blnAjax = ($ajaxId == $thisId && Environment::get('isAjaxRequest')) ? true false;
                        
$return .= "n" '<div id="'.$thisId.'">';

                        continue;
                    }

                    
$this->strField $vv;
                    
$this->strInputName $vv;
                    
$this->varValue $objRow->$vv;

                    
// Autofocus the first field
                    
if ($blnIsFirst && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'text')
                    {
                        
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['autofocus'] = 'autofocus';
                        
$blnIsFirst false;
                    }

                    
// Convert CSV fields (see #2890)
                    
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['multiple'] && isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['csv']))
                    {
                        
$this->varValue trimsplit($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['csv'], $this->varValue);
                    }

                    
// Call load_callback
                    
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback']))
                    {
                        foreach (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback'] as $callback)
                        {
                            if (
is_array($callback))
                            {
                                
$this->import($callback[0]);
                                
$this->varValue $this->{$callback[0]}->{$callback[1]}($this->varValue$this);
                            }
                            elseif (
is_callable($callback))
                            {
                                
$this->varValue $callback($this->varValue$this);
                            }
                        }
                    }

                    
// Re-set the current value
                    
$this->objActiveRecord->{$this->strField} = $this->varValue;

                    
// Build the row and pass the current palette string (thanks to Tristan Lins)
                    
$blnAjax $strAjax .= $this->row($this->strPalette) : $return .= $this->row($this->strPalette);
                }

                
$class 'tl_box';
                
$return .= "n" '</fieldset>';
            }
        }

        
// Versions overview
        
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['enableVersioning'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['hideVersionMenu'])
        {
            
$version $objVersions->renderDropdown();
        }
        else
        {
            
$version '';
        }

        
// Submit buttons
        
$arrButtons = array();
        
$arrButtons['save'] = '<input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['save']).'">';

        if (!
Input::get('nb'))
        {
            
$arrButtons['saveNclose'] = '<input type="submit" name="saveNclose" id="saveNclose" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNclose']).'">';
        }

        if (!
Input::get('popup') && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable'])
        {
            
$arrButtons['saveNcreate'] = '<input type="submit" name="saveNcreate" id="saveNcreate" class="tl_submit" accesskey="n" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNcreate']).'">';
        }

        if (
Input::get('s2e'))
        {
            
$arrButtons['saveNedit'] = '<input type="submit" name="saveNedit" id="saveNedit" class="tl_submit" accesskey="e" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNedit']).'">';
        }
        elseif (!
Input::get('popup') && ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == || strlen($this->ptable) || $GLOBALS['TL_DCA'][$this->strTable]['config']['switchToEdit']))
        {
            
$arrButtons['saveNback'] = '<input type="submit" name="saveNback" id="saveNback" class="tl_submit" accesskey="g" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNback']).'">';
        }

        
// Call the buttons_callback (see #4691)
        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['edit']['buttons_callback']))
        {
            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['edit']['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);
                }
            }
        }

        
// Add the buttons and end the form
        
$return .= '
</div>

<div class="tl_formbody_submit">

<div class="tl_submit_container">
  ' 
implode(' '$arrButtons) . '
</div>

</div>
</form>

<script>
  window.addEvent('
domready', function() {
    Theme.focusInput("'
.$this->strTable.'");
  });
</script>'
;

        
// Begin the form (-> DO NOT CHANGE THIS ORDER -> this way the onsubmit attribute of the form can be changed by a field)
        
$return $version '
<div id="tl_buttons">' 
. (Input::get('nb') ? '&nbsp;' '
<a href="'
.$this->getReferer(true).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>') . '
</div>
'
.Message::generate().'
<form action="'
.ampersand(Environment::get('request'), true).'" id="'.$this->strTable.'" class="tl_form" method="post" enctype="' . ($this->blnUploadable 'multipart/form-data' 'application/x-www-form-urlencoded') . '"'.(!empty($this->onsubmit) ? ' onsubmit="'.implode(' '$this->onsubmit).'"' '').'>
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'
.specialchars($this->strTable).'">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">
<input type="hidden" name="FORM_FIELDS[]" value="'
.specialchars($this->strPalette).'">'.($this->noReload '

<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' '').$return;

        
// Reload the page to prevent _POST variables from being sent twice
        
if (Input::post('FORM_SUBMIT') == $this->strTable && !$this->noReload)
        {
            
$arrValues $this->values;
            
array_unshift($arrValuestime());

            
// Trigger the onsubmit_callback
            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback']))
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback'] as $callback)
                {
                    if (
is_array($callback))
                    {
                        
$this->import($callback[0]);
                        
$this->{$callback[0]}->{$callback[1]}($this);
                    }
                    elseif (
is_callable($callback))
                    {
                        
$callback($this);
                    }
                }
            }

            
// Save the current version
            
if ($this->blnCreateNewVersion)
            {
                
$objVersions->create();

                
// Call the onversion_callback
                
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback']))
                {
                    @
trigger_error('Using the onversion_callback has been deprecated and will no longer work in Contao 5.0. Use the oncreate_version_callback instead.'E_USER_DEPRECATED);

                    foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback'] as $callback)
                    {
                        if (
is_array($callback))
                        {
                            
$this->import($callback[0]);
                            
$this->{$callback[0]}->{$callback[1]}($this->strTable$this->intId$this);
                        }
                        elseif (
is_callable($callback))
                        {
                            
$callback($this->strTable$this->intId$this);
                        }
                    }
                }
            }

            
// Set the current timestamp (-> DO NOT CHANGE THE ORDER version - timestamp)
            
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
            {
                
$this->Database->prepare("UPDATE " $this->strTable " SET ptable=?, tstamp=? WHERE id=?")
                               ->
execute($this->ptabletime(), $this->intId);
            }
            else
            {
                
$this->Database->prepare("UPDATE " $this->strTable " SET tstamp=? WHERE id=?")
                               ->
execute(time(), $this->intId);
            }

            
// Redirect
            
if (isset($_POST['saveNclose']))
            {
                
Message::reset();
                
System::setCookie('BE_PAGE_OFFSET'00);

                
$this->redirect($this->getReferer());
            }
            elseif (isset(
$_POST['saveNedit']))
            {
                
Message::reset();
                
System::setCookie('BE_PAGE_OFFSET'00);

                
$strUrl $this->addToUrl($GLOBALS['TL_DCA'][$this->strTable]['list']['operations']['edit']['href'], false);
                
$strUrl preg_replace('/(&amp;)?(s2e|act)=[^&]*/i'''$strUrl);

                
$this->redirect($strUrl);
            }
            elseif (isset(
$_POST['saveNback']))
            {
                
Message::reset();
                
System::setCookie('BE_PAGE_OFFSET'00);

                if (
$this->ptable == '')
                {
                    
$this->redirect(TL_SCRIPT '?do=' Input::get('do'));
                }
                
// TODO: try to abstract this
                
elseif (($this->ptable == 'tl_theme' && $this->strTable == 'tl_style_sheet') || ($this->ptable == 'tl_page' && $this->strTable == 'tl_article'))
                {
                    
$this->redirect($this->getReferer(false$this->strTable));
                }
                else
                {
                    
$this->redirect($this->getReferer(false$this->ptable));
                }
            }
            elseif (isset(
$_POST['saveNcreate']))
            {
                
Message::reset();
                
System::setCookie('BE_PAGE_OFFSET'00);

                
$strUrl TL_SCRIPT '?do=' Input::get('do');

                if (isset(
$_GET['table']))
                {
                    
$strUrl .= '&amp;table=' Input::get('table');
                }

                
// Tree view
                
if ($this->treeView)
                {
                    
$strUrl .= '&amp;act=create&amp;mode=1&amp;pid=' $this->intId;
                }

                
// Parent view
                
elseif ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4)
                {
                    
$strUrl .= $this->Database->fieldExists('sorting'$this->strTable) ? '&amp;act=create&amp;mode=1&amp;pid=' $this->intId '&amp;id=' $this->activeRecord->pid '&amp;act=create&amp;mode=2&amp;pid=' $this->activeRecord->pid;
                }

                
// List view
                
else
                {
                    
$strUrl .= ($this->ptable != '') ? '&amp;act=create&amp;mode=2&amp;pid=' CURRENT_ID '&amp;act=create';
                }

                
$this->redirect($strUrl '&amp;rt=' REQUEST_TOKEN);
            }

            
$this->reload();
        }

        
// Set the focus if there is an error
        
if ($this->noReload)
        {
            
$return .= '

<script>
  window.addEvent('
domready', function() {
    Backend.vScrollTo(($('' . $this->strTable . '').getElement('
label.error').getPosition().y - 20));
  });
</script>'
;
        }

        return 
$return;
    }


    
/**
     * Auto-generate a form to edit all records that are currently shown
     *
     * @param integer $intId
     * @param integer $ajaxId
     *
     * @return string
     */
    
public function editAll($intId=null$ajaxId=null)
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not editable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$return '';
        
$this->import('BackendUser''User');

        
// Get current IDs from session
        
$session $this->Session->getData();
        
$ids $session['CURRENT']['IDS'];

        if (
$intId != '' && Environment::get('isAjaxRequest'))
        {
            
$ids = array($intId);
        }

        
// Save field selection in session
        
if (Input::post('FORM_SUBMIT') == $this->strTable.'_all' && Input::get('fields'))
        {
            
$session['CURRENT'][$this->strTable] = Input::post('all_fields');
            
$this->Session->setData($session);
        }

        
// Add fields
        
$fields $session['CURRENT'][$this->strTable];

        if (!empty(
$fields) && is_array($fields) && Input::get('fields'))
        {
            
$class 'tl_tbox';

            
// Walk through each record
            
foreach ($ids as $id)
            {
                
$this->intId $id;
                
$this->procedure = array('id=?');
                
$this->values = array($this->intId);
                
$this->blnCreateNewVersion false;
                
$this->strPalette trimsplit('[;,]'$this->getPalette());

                
$objVersions = new Versions($this->strTable$this->intId);
                
$objVersions->initialize();

                
// Add meta fields if the current user is an administrator
                
if ($this->User->isAdmin)
                {
                    if (
$this->Database->fieldExists('sorting'$this->strTable))
                    {
                        
array_unshift($this->strPalette'sorting');
                    }

                    if (
$this->Database->fieldExists('pid'$this->strTable))
                    {
                        
array_unshift($this->strPalette'pid');
                    }

                    
// Ensure a minimum configuration
                    
foreach (array('pid''sorting') as $f)
                    {
                        if (!isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label']))
                        {
                            
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label'] = &$GLOBALS['TL_LANG']['MSC'][$f];
                        }
                        if (!isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['inputType']))
                        {
                            
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['inputType'] = 'text';
                        }
                        if (!isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['eval']))
                        {
                            
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['eval'] = array('rgxp' => 'natural');
                        }
                    }
                }

                
// Begin current row
                
$strAjax '';
                
$blnAjax false;
                
$return .= '
<div class="'
.$class.'">';

                
$class 'tl_box';
                
$formFields = array();

                
// Get the field values
                
$objRow $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                         ->
limit(1)
                                         ->
execute($this->intId);

                
// Store the active record
                
$this->objActiveRecord $objRow;
                
$blnIsFirst true;

                foreach (
$this->strPalette as $v)
                {
                    
// Check whether field is excluded
                    
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['exclude'])
                    {
                        continue;
                    }

                    if (
$v == '[EOF]')
                    {
                        if (
$blnAjax && Environment::get('isAjaxRequest'))
                        {
                            return 
$strAjax '<input type="hidden" name="FORM_FIELDS_'.$id.'[]" value="'.specialchars(implode(','$formFields)).'">';
                        }

                        
$blnAjax false;
                        
$return .= "n  " '</div>';

                        continue;
                    }

                    if (
preg_match('/^[.*]$/'$v))
                    {
                        
$thisId 'sub_' substr($v1, -1) . '_' $id;
                        
$blnAjax = ($ajaxId == $thisId && Environment::get('isAjaxRequest')) ? true false;
                        
$return .= "n  " '<div id="'.$thisId.'">';

                        continue;
                    }

                    if (!
in_array($v$fields))
                    {
                        continue;
                    }

                    
$this->strField $v;
                    
$this->strInputName $v.'_'.$this->intId;
                    
$formFields[] = $v.'_'.$this->intId;

                    
// Set the default value and try to load the current value from DB (see #5252)
                    
if (array_key_exists('default'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]))
                    {
                        
$this->varValue is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['default']) ? serialize($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['default']) : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['default'];
                    }

                    if (
$objRow->$v !== false)
                    {
                        
$this->varValue $objRow->$v;
                    }

                    
// Autofocus the first field
                    
if ($blnIsFirst && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'text')
                    {
                        
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['autofocus'] = 'autofocus';
                        
$blnIsFirst false;
                    }

                    
// Convert CSV fields (see #2890)
                    
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['multiple'] && isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['csv']))
                    {
                        
$this->varValue trimsplit($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['csv'], $this->varValue);
                    }

                    
// Call load_callback
                    
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback']))
                    {
                        foreach (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback'] as $callback)
                        {
                            if (
is_array($callback))
                            {
                                
$this->import($callback[0]);
                                
$this->varValue $this->{$callback[0]}->{$callback[1]}($this->varValue$this);
                            }
                            elseif (
is_callable($callback))
                            {
                                
$this->varValue $callback($this->varValue$this);
                            }
                        }
                    }

                    
// Re-set the current value
                    
$this->objActiveRecord->{$this->strField} = $this->varValue;

                    
// Build the row and pass the current palette string (thanks to Tristan Lins)
                    
$blnAjax $strAjax .= $this->row($this->strPalette) : $return .= $this->row($this->strPalette);
                }

                
// Close box
                
$return .= '
  <input type="hidden" name="FORM_FIELDS_'
.$this->intId.'[]" value="'.specialchars(implode(','$formFields)).'">
</div>'
;

                
// Save record
                
if (Input::post('FORM_SUBMIT') == $this->strTable && !$this->noReload)
                {
                    
// Call the onsubmit_callback
                    
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback']))
                    {
                        foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback'] as $callback)
                        {
                            if (
is_array($callback))
                            {
                                
$this->import($callback[0]);
                                
$this->{$callback[0]}->{$callback[1]}($this);
                            }
                            elseif (
is_callable($callback))
                            {
                                
$callback($this);
                            }
                        }
                    }

                    
// Create a new version
                    
if ($this->blnCreateNewVersion)
                    {
                        
$objVersions->create();

                        
// Call the onversion_callback
                        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback']))
                        {
                            @
trigger_error('Using the onversion_callback has been deprecated and will no longer work in Contao 5.0. Use the oncreate_version_callback instead.'E_USER_DEPRECATED);

                            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback'] as $callback)
                            {
                                if (
is_array($callback))
                                {
                                    
$this->import($callback[0]);
                                    
$this->{$callback[0]}->{$callback[1]}($this->strTable$this->intId$this);
                                }
                                elseif (
is_callable($callback))
                                {
                                    
$callback($this->strTable$this->intId$this);
                                }
                            }
                        }
                    }

                    
// Set the current timestamp (-> DO NOT CHANGE ORDER version - timestamp)
                    
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
                    {
                        
$this->Database->prepare("UPDATE " $this->strTable " SET ptable=?, tstamp=? WHERE id=?")
                                       ->
execute($this->ptabletime(), $this->intId);
                    }
                    else
                    {
                        
$this->Database->prepare("UPDATE " $this->strTable " SET tstamp=? WHERE id=?")
                                       ->
execute(time(), $this->intId);
                    }
                }
            }

            
// Submit buttons
            
$arrButtons = array();
            
$arrButtons['save'] = '<input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['save']).'">';
            
$arrButtons['saveNclose'] = '<input type="submit" name="saveNclose" id="saveNclose" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNclose']).'">';

            
// Call the buttons_callback (see #4691)
            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['edit']['buttons_callback']))
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['edit']['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);
                    }
                }
            }

            
// Add the form
            
$return '

<form action="'
.ampersand(Environment::get('request'), true).'" id="'.$this->strTable.'" class="tl_form" method="post" enctype="' . ($this->blnUploadable 'multipart/form-data' 'application/x-www-form-urlencoded') . '">
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'
.$this->strTable.'">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">'.($this->noReload '

<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' '').$return.'

</div>

<div class="tl_formbody_submit">

<div class="tl_submit_container">
  ' 
implode(' '$arrButtons) . '
</div>

</div>
</form>

<script>
  window.addEvent('
domready', function() {
    Theme.focusInput("'
.$this->strTable.'");
  });
</script>'
;

            
// Set the focus if there is an error
            
if ($this->noReload)
            {
                
$return .= '

<script>
  window.addEvent('
domready', function() {
    Backend.vScrollTo(($('' . $this->strTable . '').getElement('
label.error').getPosition().y - 20));
  });
</script>'
;
            }

            
// Reload the page to prevent _POST variables from being sent twice
            
if (Input::post('FORM_SUBMIT') == $this->strTable && !$this->noReload)
            {
                if (
Input::post('saveNclose'))
                {
                    
System::setCookie('BE_PAGE_OFFSET'00);
                    
$this->redirect($this->getReferer());
                }

                
$this->reload();
            }
        }

        
// Else show a form to select the fields
        
else
        {
            
$options '';
            
$fields = array();

            
// Add fields of the current table
            
$fields array_merge($fieldsarray_keys($GLOBALS['TL_DCA'][$this->strTable]['fields']));

            
// Add meta fields if the current user is an administrator
            
if ($this->User->isAdmin)
            {
                if (
$this->Database->fieldExists('sorting'$this->strTable) && !in_array('sorting'$fields))
                {
                    
array_unshift($fields'sorting');
                }

                if (
$this->Database->fieldExists('pid'$this->strTable) && !in_array('pid'$fields))
                {
                    
array_unshift($fields'pid');
                }
            }

            
// Show all non-excluded fields
            
foreach ($fields as $field)
            {
                if (
$field == 'pid' || $field == 'sorting' || (!$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['exclude'] && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['doNotShow'] && (strlen($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['inputType']) || is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['input_field_callback']))))
                {
                    
$options .= '
  <input type="checkbox" name="all_fields[]" id="all_'
.$field.'" class="tl_checkbox" value="'.specialchars($field).'"> <label for="all_'.$field.'" class="tl_checkbox_label">'.($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] ?: $GLOBALS['TL_LANG']['MSC'][$field][0]).'</label><br>';
                }
            }

            
$blnIsError = ($_POST && empty($_POST['all_fields']));

            
// Return the select menu
            
$return .= '

<form action="'
.ampersand(Environment::get('request'), true).'&amp;fields=1" id="'.$this->strTable.'_all" class="tl_form" method="post">
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'
.$this->strTable.'_all">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">'.($blnIsError '

<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' '').'

<div class="tl_tbox">
<fieldset class="tl_checkbox_container">
  <legend'
.($blnIsError ' class="error"' '').'>'.$GLOBALS['TL_LANG']['MSC']['all_fields'][0].'</legend>
  <input type="checkbox" id="check_all" class="tl_checkbox" onclick="Backend.toggleCheckboxes(this)"> <label for="check_all" style="color:#a6a6a6"><em>'
.$GLOBALS['TL_LANG']['MSC']['selectAll'].'</em></label><br>'.$options.'
</fieldset>'
.($blnIsError '
<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['all_fields'].'</p>' : ((Config::get('showHelp') && strlen($GLOBALS['TL_LANG']['MSC']['all_fields'][1])) ? '
<p class="tl_help tl_tip">'
.$GLOBALS['TL_LANG']['MSC']['all_fields'][1].'</p>' '')).'
</div>

</div>

<div class="tl_formbody_submit">

<div class="tl_submit_container">
  <input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'
.specialchars($GLOBALS['TL_LANG']['MSC']['continue']).'">
</div>

</div>
</form>'
;
        }

        
// Return
        
return '
<div id="tl_buttons">
<a href="'
.$this->getReferer(true).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
</div>'
.$return;
    }


    
/**
     * Auto-generate a form to override all records that are currently shown
     *
     * @return string
     */
    
public function overrideAll()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
        {
            
$this->log('Table "'.$this->strTable.'" is not editable'__METHOD__TL_ERROR);
            
$this->redirect('contao/main.php?act=error');
        }

        
$return '';
        
$this->import('BackendUser''User');

        
// Get current IDs from session
        
$session $this->Session->getData();
        
$ids $session['CURRENT']['IDS'];

        
// Save field selection in session
        
if (Input::post('FORM_SUBMIT') == $this->strTable.'_all' && Input::get('fields'))
        {
            
$session['CURRENT'][$this->strTable] = Input::post('all_fields');
            
$this->Session->setData($session);
        }

        
// Add fields
        
$fields $session['CURRENT'][$this->strTable];

        if (!empty(
$fields) && is_array($fields) && Input::get('fields'))
        {
            
$class 'tl_tbox';
            
$formFields = array();

            
// Save record
            
if (Input::post('FORM_SUBMIT') == $this->strTable)
            {
                foreach (
$ids as $id)
                {
                    
$this->intId $id;
                    
$this->procedure = array('id=?');
                    
$this->values = array($this->intId);
                    
$this->blnCreateNewVersion false;

                    
// Get the field values
                    
$objRow $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                             ->
limit(1)
                                             ->
execute($this->intId);

                    
// Store the active record
                    
$this->objActiveRecord $objRow;

                    
$objVersions = new Versions($this->strTable$this->intId);
                    
$objVersions->initialize();

                    
// Store all fields
                    
foreach ($fields as $v)
                    {
                        
// Check whether field is excluded
                        
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['exclude'])
                        {
                            continue;
                        }

                        
$this->strField $v;
                        
$this->strInputName $v;
                        
$this->varValue '';

                        
// Make sure the new value is applied
                        
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['alwaysSave'] = true;

                        
// Store value
                        
$this->row();
                    }

                    
// Post processing
                    
if (!$this->noReload)
                    {
                        
// Call the onsubmit_callback
                        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback']))
                        {
                            foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback'] as $callback)
                            {
                                if (
is_array($callback))
                                {
                                    
$this->import($callback[0]);
                                    
$this->{$callback[0]}->{$callback[1]}($this);
                                }
                                elseif (
is_callable($callback))
                                {
                                    
$callback($this);
                                }
                            }
                        }

                        
// Create a new version
                        
if ($this->blnCreateNewVersion)
                        {
                            
$objVersions->create();

                            
// Call the onversion_callback
                            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback']))
                            {
                                @
trigger_error('Using the onversion_callback has been deprecated and will no longer work in Contao 5.0. Use the oncreate_version_callback instead.'E_USER_DEPRECATED);

                                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['config']['onversion_callback'] as $callback)
                                {
                                    if (
is_array($callback))
                                    {
                                        
$this->import($callback[0]);
                                        
$this->{$callback[0]}->{$callback[1]}($this->strTable$this->intId$this);
                                    }
                                    elseif (
is_callable($callback))
                                    {
                                        
$callback($this->strTable$this->intId$this);
                                    }
                                }
                            }
                        }

                        
// Set the current timestamp (-> DO NOT CHANGE ORDER version - timestamp)
                        
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
                        {
                            
$this->Database->prepare("UPDATE " $this->strTable " SET ptable=?, tstamp=? WHERE id=?")
                                           ->
execute($this->ptabletime(), $this->intId);
                        }
                        else
                        {
                            
$this->Database->prepare("UPDATE " $this->strTable " SET tstamp=? WHERE id=?")
                                           ->
execute(time(), $this->intId);
                        }
                    }
                }
            }

            
$blnIsFirst true;

            
// Begin current row
            
$return .= '
<div class="'
.$class.'">';

            foreach (
$fields as $v)
            {
                
// Check whether field is excluded
                
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['exclude'])
                {
                    continue;
                }

                
$formFields[] = $v;

                
$this->intId 0;
                
$this->procedure = array('id=?');
                
$this->values = array($this->intId);
                
$this->strField $v;
                
$this->strInputName $v;
                
$this->varValue '';

                
// Autofocus the first field
                
if ($blnIsFirst && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'text')
                {
                    
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['autofocus'] = 'autofocus';
                    
$blnIsFirst false;
                }

                
// Disable auto-submit
                
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['submitOnChange'] = false;
                
$return .= $this->row();
            }

            
// Close box
            
$return .= '
<input type="hidden" name="FORM_FIELDS[]" value="'
.specialchars(implode(','$formFields)).'">
</div>'
;

            
// Submit buttons
            
$arrButtons = array();
            
$arrButtons['save'] = '<input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['save']).'">';
            
$arrButtons['saveNclose'] = '<input type="submit" name="saveNclose" id="saveNclose" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNclose']).'">';

            
// Call the buttons_callback (see #4691)
            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['edit']['buttons_callback']))
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['edit']['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);
                    }
                }
            }

            
// Add the form
            
$return '

<form action="'
.ampersand(Environment::get('request'), true).'" id="'.$this->strTable.'" class="tl_form" method="post" enctype="' . ($this->blnUploadable 'multipart/form-data' 'application/x-www-form-urlencoded') . '">
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'
.$this->strTable.'">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">'.($this->noReload '

<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' '').$return.'

</div>

<div class="tl_formbody_submit">

<div class="tl_submit_container">
  ' 
implode(' '$arrButtons) . '
</div>

</div>
</form>'
;

            
// Set the focus if there is an error
            
if ($this->noReload)
            {
                
$return .= '

<script>
  window.addEvent('
domready', function() {
    Backend.vScrollTo(($('' . $this->strTable . '').getElement('
label.error').getPosition().y - 20));
  });
</script>'
;
            }

            
// Reload the page to prevent _POST variables from being sent twice
            
if (Input::post('FORM_SUBMIT') == $this->strTable && !$this->noReload)
            {
                if (
Input::post('saveNclose'))
                {
                    
System::setCookie('BE_PAGE_OFFSET'00);
                    
$this->redirect($this->getReferer());
                }

                
$this->reload();
            }
        }

        
// Else show a form to select the fields
        
else
        {
            
$options '';
            
$fields = array();

            
// Add fields of the current table
            
$fields array_merge($fieldsarray_keys($GLOBALS['TL_DCA'][$this->strTable]['fields']));

            
// Add meta fields if the current user is an administrator
            
if ($this->User->isAdmin)
            {
                if (
$this->Database->fieldExists('sorting'$this->strTable) && !in_array('sorting'$fields))
                {
                    
array_unshift($fields'sorting');
                }

                if (
$this->Database->fieldExists('pid'$this->strTable) && !in_array('pid'$fields))
                {
                    
array_unshift($fields'pid');
                }
            }

            
// Show all non-excluded fields
            
foreach ($fields as $field)
            {
                if (
$field == 'pid' || $field == 'sorting' || (!$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['exclude'] && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['doNotShow'] && (strlen($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['inputType']) || is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['input_field_callback']))))
                {
                    
$options .= '
  <input type="checkbox" name="all_fields[]" id="all_'
.$field.'" class="tl_checkbox" value="'.specialchars($field).'"> <label for="all_'.$field.'" class="tl_checkbox_label">'.($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] ?: $GLOBALS['TL_LANG']['MSC'][$field][0]).'</label><br>';
                }
            }

            
$blnIsError = ($_POST && empty($_POST['all_fields']));

            
// Return the select menu
            
$return .= '

<form action="'
.ampersand(Environment::get('request'), true).'&amp;fields=1" id="'.$this->strTable.'_all" class="tl_form" method="post">
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'
.$this->strTable.'_all">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">'.($blnIsError '

<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' '').'

<div class="tl_tbox">
<fieldset class="tl_checkbox_container">
  <legend'
.($blnIsError ' class="error"' '').'>'.$GLOBALS['TL_LANG']['MSC']['all_fields'][0].'</legend>
  <input type="checkbox" id="check_all" class="tl_checkbox" onclick="Backend.toggleCheckboxes(this)"> <label for="check_all" style="color:#a6a6a6"><em>'
.$GLOBALS['TL_LANG']['MSC']['selectAll'].'</em></label><br>'.$options.'
</fieldset>'
.($blnIsError '
<p class="tl_error">'
.$GLOBALS['TL_LANG']['ERR']['all_fields'].'</p>' : ((Config::get('showHelp') && strlen($GLOBALS['TL_LANG']['MSC']['all_fields'][1])) ? '
<p class="tl_help tl_tip">'
.$GLOBALS['TL_LANG']['MSC']['all_fields'][1].'</p>' '')).'
</div>

</div>

<div class="tl_formbody_submit">

<div class="tl_submit_container">
  <input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'
.specialchars($GLOBALS['TL_LANG']['MSC']['continue']).'">
</div>

</div>
</form>'
;
        }

        
// Return
        
return '
<div id="tl_buttons">
<a href="'
.$this->getReferer(true).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
</div>'
.$return;
    }


    
/**
     * Save the current value
     *
     * @param mixed $varValue
     *
     * @throws Exception
     */
    
protected function save($varValue)
    {
        if (
Input::post('FORM_SUBMIT') != $this->strTable)
        {
            return;
        }

        
$arrData $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField];

        
// Convert date formats into timestamps
        
if ($varValue != '' && in_array($arrData['eval']['rgxp'], array('date''time''datim')))
        {
            
$objDate = new Date($varValueDate::getFormatFromRgxp($arrData['eval']['rgxp']));
            
$varValue $objDate->tstamp;
        }

        
// Make sure unique fields are unique
        
if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue($this->strTable$this->strField$varValue$this->objActiveRecord->id))
        {
            throw new 
Exception(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $this->strField));
        }

        
// Handle multi-select fields in "override all" mode
        
if (Input::get('act') == 'overrideAll' && ($arrData['inputType'] == 'checkbox' || $arrData['inputType'] == 'checkboxWizard') && $arrData['eval']['multiple'])
        {
            if (
$this->objActiveRecord !== null)
            {
                
$new deserialize($varValuetrue);
                
$old deserialize($this->objActiveRecord->{$this->strField}, true);

                
// Call load_callback
                
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback']))
                {
                    foreach (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback'] as $callback)
                    {
                        if (
is_array($callback))
                        {
                            
$this->import($callback[0]);
                            
$old $this->{$callback[0]}->{$callback[1]}($old$this);
                        }
                        elseif (
is_callable($callback))
                        {
                            
$old $callback($old$this);
                        }
                    }
                }

                switch (
Input::post($this->strInputName '_update'))
                {
                    case 
'add':
                        
$varValue array_values(array_unique(array_merge($old$new)));
                        break;

                    case 
'remove':
                        
$varValue array_values(array_diff($old$new));
                        break;

                    case 
'replace':
                        
$varValue $new;
                        break;
                }

                if (!
is_array($varValue) || empty($varValue))
                {
                    
$varValue $arrData['eval']['nullIfEmpty'] ? null '';
                }
                elseif (isset(
$arrData['eval']['csv']))
                {
                    
$varValue implode($arrData['eval']['csv'], $varValue); // see #2890
                
}
                else
                {
                    
$varValue serialize($varValue);
                }
            }
        }

        
// Convert arrays (see #2890)
        
if ($arrData['eval']['multiple'] && isset($arrData['eval']['csv']))
        {
            
$varValue implode($arrData['eval']['csv'], deserialize($varValuetrue));
        }

        
// Trigger the save_callback
        
if (is_array($arrData['save_callback']))
        {
            foreach (
$arrData['save_callback'] as $callback)
            {
                if (
is_array($callback))
                {
                    
$this->import($callback[0]);
                    
$varValue $this->{$callback[0]}->{$callback[1]}($varValue$this);
                }
                elseif (
is_callable($callback))
                {
                    
$varValue $callback($varValue$this);
                }
            }
        }

        
// Save the value if there was no error
        
if (($varValue != '' || !$arrData['eval']['doNotSaveEmpty']) && ($this->varValue !== $varValue || $arrData['eval']['alwaysSave']))
        {
            
// If the field is a fallback field, empty all other columns (see #6498)
            
if ($arrData['eval']['fallback'] && $varValue != '')
            {
                if (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4)
                {
                    
$this->Database->prepare("UPDATE " $this->strTable " SET " $this->strField "='' WHERE pid=?")
                                   ->
execute($this->activeRecord->pid);
                }
                else
                {
                    
$this->Database->execute("UPDATE " $this->strTable " SET " $this->strField "=''");
                }
            }

            
// Set the correct empty value (see #6284, #6373)
            
if ($varValue === '')
            {
                
$varValue Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['sql']);
            }

            
$arrValues $this->values;
            
array_unshift($arrValues$varValue);

            
$objUpdateStmt $this->Database->prepare("UPDATE " $this->strTable " SET " $this->strField "=? WHERE " implode(' AND '$this->procedure))
                                            ->
execute($arrValues);

            if (
$objUpdateStmt->affectedRows)
            {
                
$this->blnCreateNewVersion true;
                
$this->varValue deserialize($varValue);

                if (
is_object($this->objActiveRecord))
                {
                    
$this->objActiveRecord->{$this->strField} = $this->varValue;
                }
            }
        }
    }


    
/**
     * Return the name of the current palette
     *
     * @return string
     */
    
public function getPalette()
    {
        
$palette 'default';
        
$strPalette $GLOBALS['TL_DCA'][$this->strTable]['palettes'][$palette];

        
// Check whether there are selector fields
        
if (!empty($GLOBALS['TL_DCA'][$this->strTable]['palettes']['__selector__']))
        {
            
$sValues = array();
            
$subpalettes = array();

            
$objFields $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE id=?")
                                        ->
limit(1)
                                        ->
execute($this->intId);

            
// Get selector values from DB
            
if ($objFields->numRows 0)
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['palettes']['__selector__'] as $name)
                {
                    
$trigger $objFields->$name;

                    
// Overwrite the trigger
                    
if (Input::post('FORM_SUBMIT') == $this->strTable)
                    {
                        
$key = (Input::get('act') == 'editAll') ? $name.'_'.$this->intId $name;

                        if (isset(
$_POST[$key]))
                        {
                            
$trigger Input::post($key);
                        }
                    }

                    if (
$trigger != '')
                    {
                        if (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$name]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$name]['eval']['multiple'])
                        {
                            
$sValues[] = $name;

                            
// Look for a subpalette
                            
if (strlen($GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$name]))
                            {
                                
$subpalettes[$name] = $GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$name];
                            }
                        }
                        else
                        {
                            
$sValues[] = $trigger;
                            
$key $name .'_'$trigger;

                            
// Look for a subpalette
                            
if (strlen($GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$key]))
                            {
                                
$subpalettes[$name] = $GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$key];
                            }
                        }
                    }
                }
            }

            
// Build possible palette names from the selector values
            
if (!count($sValues))
            {
                
$names = array('default');
            }
            elseif (
count($sValues) > 1)
            {
                foreach (
$sValues as $k=>$v)
                {
                    
// Unset selectors that just trigger subpalettes (see #3738)
                    
if (isset($GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$v]))
                    {
                        unset(
$sValues[$k]);
                    }
                }

                
$names $this->combiner($sValues);
            }
            else
            {
                
$names = array($sValues[0]);
            }

            
// Get an existing palette
            
foreach ($names as $paletteName)
            {
                if (
strlen($GLOBALS['TL_DCA'][$this->strTable]['palettes'][$paletteName]))
                {
                    
$strPalette $GLOBALS['TL_DCA'][$this->strTable]['palettes'][$paletteName];
                    break;
                }
            }

            
// Include subpalettes
            
foreach ($subpalettes as $k=>$v)
            {
                
$strPalette preg_replace('/b'preg_quote($k'/').'b/i'$k.',['.$k.'],'.$v.',[EOF]'$strPalette);
            }
        }

        return 
$strPalette;
    }


    
/**
     * Delete all incomplete and unrelated records
     */
    
protected function reviseTable()
    {
        
$reload false;
        
$ptable $GLOBALS['TL_DCA'][$this->strTable]['config']['ptable'];
        
$ctable $GLOBALS['TL_DCA'][$this->strTable]['config']['ctable'];

        
$new_records $this->Session->get('new_records');

        
// HOOK: add custom logic
        
if (isset($GLOBALS['TL_HOOKS']['reviseTable']) && is_array($GLOBALS['TL_HOOKS']['reviseTable']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['reviseTable'] as $callback)
            {
                
$status null;

                if (
is_array($callback))
                {
                    
$this->import($callback[0]);
                    
$status $this->{$callback[0]}->{$callback[1]}($this->strTable$new_records[$this->strTable], $ptable$ctable);
                }
                elseif (
is_callable($callback))
                {
                    
$status $callback($this->strTable$new_records[$this->strTable], $ptable$ctable);
                }

                if (
$status === true)
                {
                    
$reload true;
                }
            }
        }

        
// Delete all new but incomplete records (tstamp=0)
        
if (!empty($new_records[$this->strTable]) && is_array($new_records[$this->strTable]))
        {
            
$objStmt $this->Database->execute("DELETE FROM " $this->strTable " WHERE id IN(" implode(','array_map('intval'$new_records[$this->strTable])) . ") AND tstamp=0");

            if (
$objStmt->affectedRows 0)
            {
                
$reload true;
            }
        }

        
// Delete all records of the current table that are not related to the parent table
        
if ($ptable != '')
        {
            if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
            {
                
$objStmt $this->Database->execute("DELETE FROM " $this->strTable " WHERE ptable='" $ptable "' AND NOT EXISTS (SELECT * FROM " $ptable " WHERE " $this->strTable ".pid = " $ptable ".id)");
            }
            else
            {
                
$objStmt $this->Database->execute("DELETE FROM " $this->strTable " WHERE NOT EXISTS (SELECT * FROM " $ptable " WHERE " $this->strTable ".pid = " $ptable ".id)");
            }

            if (
$objStmt->affectedRows 0)
            {
                
$reload true;
            }
        }

        
// Delete all records of the child table that are not related to the current table
        
if (!empty($ctable) && is_array($ctable))
        {
            foreach (
$ctable as $v)
            {
                if (
$v != '')
                {
                    
// Load the DCA configuration so we can check for "dynamicPtable"
                    
if (!isset($GLOBALS['loadDataContainer'][$v]))
                    {
                        
$this->loadDataContainer($v);
                    }

                    if (
$GLOBALS['TL_DCA'][$v]['config']['dynamicPtable'])
                    {
                        
$objStmt $this->Database->execute("DELETE FROM $v WHERE ptable='" $this->strTable "' AND NOT EXISTS (SELECT * FROM " $this->strTable " WHERE $v.pid = " $this->strTable ".id)");
                    }
                    else
                    {
                        
$objStmt $this->Database->execute("DELETE FROM $v WHERE NOT EXISTS (SELECT * FROM " $this->strTable " WHERE $v.pid = " $this->strTable ".id)");
                    }

                    if (
$objStmt->affectedRows 0)
                    {
                        
$reload true;
                    }
                }
            }
        }

        
// Reload the page
        
if ($reload)
        {
            
$this->reload();
        }
    }


    
/**
     * List all records of the current table as tree and return them as HTML string
     *
     * @return string
     */
    
protected function treeView()
    {
        
$table $this->strTable;
        
$treeClass 'tl_tree';

        if (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6)
        {
            
$table $this->ptable;
            
$treeClass 'tl_tree_xtnd';

            
System::loadLanguageFile($table);
            
$this->loadDataContainer($table);
        }

        
$session $this->Session->getData();

        
// Toggle the nodes
        
if (Input::get('ptg') == 'all')
        {
            
$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable.'_'.$table.'_tree' $this->strTable.'_tree';

            
// Expand tree
            
if (!is_array($session[$node]) || empty($session[$node]) || current($session[$node]) != 1)
            {
                
$session[$node] = array();
                
$objNodes $this->Database->execute("SELECT DISTINCT pid FROM " $table " WHERE pid>0");

                while (
$objNodes->next())
                {
                    
$session[$node][$objNodes->pid] = 1;
                }
            }

            
// Collapse tree
            
else
            {
                
$session[$node] = array();
            }

            
$this->Session->setData($session);
            
$this->redirect(preg_replace('/(&(amp;)?|?)ptg=[^& ]*/i'''Environment::get('request')));
        }

        
// Return if a mandatory field (id, pid, sorting) is missing
        
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && (!$this->Database->fieldExists('id'$table) || !$this->Database->fieldExists('pid'$table) || !$this->Database->fieldExists('sorting'$table)))
        {
            return 
'
<p class="tl_empty">Table "'
.$table.'" can not be shown as tree, because the "id", "pid" or "sorting" field is missing!</p>';
        }

        
// Return if there is no parent table
        
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && !strlen($this->ptable))
        {
            return 
'
<p class="tl_empty">Table "'
.$table.'" can not be shown as extended tree, because there is no parent table!</p>';
        }

        
$blnClipboard false;
        
$arrClipboard $this->Session->get('CLIPBOARD');

        
// Check the clipboard
        
if (!empty($arrClipboard[$this->strTable]))
        {
            
$blnClipboard true;
            
$arrClipboard $arrClipboard[$this->strTable];
        }

        
// Load the fonts to display the paste hint
        
Config::set('loadGoogleFonts'$blnClipboard);

        
$label $GLOBALS['TL_DCA'][$table]['config']['label'];
        
$icon $GLOBALS['TL_DCA'][$table]['list']['sorting']['icon'] ?: 'pagemounts.gif';
        
$label Image::getHtml($icon).' <label>'.$label.'</label>';

        
// Begin buttons container
        
$return '
<div id="tl_buttons">'
.((Input::get('act') == 'select') ? '
<a href="'
.$this->getReferer(true).'" 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' && !$blnClipboard && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) ? '
<a href="'
.$this->addToUrl('act=paste&amp;mode=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> ' '') . ($blnClipboard '
<a href="'
.$this->addToUrl('clipboard=1').'" class="header_clipboard" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['clearClipboard']).'" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['clearClipboard'].'</a> ' $this->generateGlobalButtons()) . '
</div>' 
Message::generate(true);

        
$tree '';
        
$blnHasSorting $this->Database->fieldExists('sorting'$table);
        
$blnNoRecursion false;

        
// Limit the results by modifying $this->root
        
if ($session['search'][$this->strTable]['value'] != '')
        {
            
$for = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? 'pid' 'id';

            if (
$session['search'][$this->strTable]['field'] == 'id')
            {
                
$objRoot $this->Database->prepare("SELECT $for FROM {$this->strTable} WHERE id=?")
                                          ->
execute($session['search'][$this->strTable]['value']);
            }
            else
            {
                
$strPattern "CAST(%s AS CHAR) REGEXP ?";

                if (
substr(Config::get('dbCollation'), -3) == '_ci')
                {
                    
$strPattern "LOWER(CAST(%s AS CHAR)) REGEXP LOWER(?)";
                }

                
$fld $session['search'][$this->strTable]['field'];

                if (isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey']))
                {
                    list(
$t$f) = explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey']);

                    
$objRoot $this->Database->prepare("SELECT $for FROM {$this->strTable} WHERE (" sprintf($strPattern$fld) . " OR " sprintf($strPattern"(SELECT $f FROM $t WHERE $t.id={$this->strTable}.$fld)") . ") GROUP BY $for")
                                              ->
execute($session['search'][$this->strTable]['value'], $session['search'][$this->strTable]['value']);
                }
                else
                {
                    
$objRoot $this->Database->prepare("SELECT $for FROM {$this->strTable} WHERE " sprintf($strPattern$fld) . " GROUP BY $for")
                                              ->
execute($session['search'][$this->strTable]['value']);
                }
            }

            if (
$objRoot->numRows 1)
            {
                
$this->root = array();
            }
            else
            {
                
// Respect existing limitations (root IDs)
                
if (is_array($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']))
                {
                    
$arrRoot = array();

                    while (
$objRoot->next())
                    {
                        if (
count(array_intersect($this->root$this->Database->getParentRecords($objRoot->$for$table))) > 0)
                        {
                            
$arrRoot[] = $objRoot->$for;
                        }
                    }

                    
$this->root $arrRoot;
                }
                else
                {
                    
$blnNoRecursion true;
                    
$this->root $objRoot->fetchEach($for);
                }
            }
        }

        
// Call a recursive function that builds the tree
        
for ($i=0$c=count($this->root); $i<$c$i++)
        {
            
$tree .= $this->generateTree($table$this->root[$i], array('p'=>$this->root[($i-1)], 'n'=>$this->root[($i+1)]), $blnHasSorting, -20, ($blnClipboard $arrClipboard false), ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && $blnClipboard && $this->root[$i] == $arrClipboard['id']), false$blnNoRecursion);
        }

        
// Return if there are no records
        
if ($tree == '' && Input::get('act') != 'paste')
        {
            return 
$return '
<p class="tl_empty">'
.$GLOBALS['TL_LANG']['MSC']['noResult'].'</p>';
        }

        
$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.'">' '').($blnClipboard '

<div id="paste_hint">
  <p>'
.$GLOBALS['TL_LANG']['MSC']['selectNewPosition'].'</p>
</div>' 
'').'

<div class="tl_listing_container tree_view" id="tl_listing">'
.(isset($GLOBALS['TL_DCA'][$table]['list']['sorting']['breadcrumb']) ? $GLOBALS['TL_DCA'][$table]['list']['sorting']['breadcrumb'] : '').((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>' 
'').'

<ul class="tl_listing '
$treeClass .'">
  <li class="tl_folder_top"><div class="tl_left">'
.$label.'</div> <div class="tl_right">';

        
$_buttons '&nbsp;';

        
// Show paste button only if there are no root records specified
        
if (Input::get('act') != 'select' && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && $blnClipboard && ((!count($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']) && $GLOBALS['TL_DCA'][$table]['list']['sorting']['root'] !== false) || $GLOBALS['TL_DCA'][$table]['list']['sorting']['rootPaste']))
        {
            
// Call paste_button_callback (&$dc, $row, $table, $cr, $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, array('id'=>0), $tablefalse$arrClipboard);
            }
            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, array('id'=>0), $tablefalse$arrClipboard);
            }
            else
            {
                
$imagePasteInto Image::getHtml('pasteinto.gif'$GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]);
                
$_buttons '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid=0'.(!is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.specialchars($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ';
            }
        }

        
// End table
        
$return .= $_buttons '</div><div style="clear:both"></div></li>'.$tree.'
</ul>

</div>'
;

        
// Close the form
        
if (Input::get('act') == 'select')
        {
            
// Submit buttons
            
$arrButtons = array();

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
            {
                
$arrButtons['delete'] = '<input type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(''.$GLOBALS['TL_LANG']['MSC']['delAllConfirm'].'')" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['deleteSelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
            {
                
$arrButtons['cut'] = '<input type="submit" name="cut" id="cut" class="tl_submit" accesskey="x" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['moveSelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
            {
                
$arrButtons['copy'] = '<input type="submit" name="copy" id="copy" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['copySelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
            {
                
$arrButtons['override'] = '<input type="submit" name="override" id="override" class="tl_submit" accesskey="v" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['overrideSelected']).'">';
                
$arrButtons['edit'] = '<input type="submit" name="edit" id="edit" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['editSelected']).'">';
            }

            
// 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;
    }


    
/**
     * Generate a particular subpart of the tree and return it as HTML string
     *
     * @param integer $id
     * @param integer $level
     *
     * @return string
     */
    
public function ajaxTreeView($id$level)
    {
        if (!
Environment::get('isAjaxRequest'))
        {
            return 
'';
        }

        
$return '';
        
$table $this->strTable;
        
$blnPtable false;

        
// Load parent table
        
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6)
        {
            
$table $this->ptable;

            
System::loadLanguageFile($table);
            
$this->loadDataContainer($table);

            
$blnPtable true;
        }

        
$blnProtected false;

        
// Check protected pages
        
if ($table == 'tl_page')
        {
            
$objParent PageModel::findWithDetails($id);
            
$blnProtected $objParent->protected true false;
        }

        
$margin = ($level 20);
        
$hasSorting $this->Database->fieldExists('sorting'$table);
        
$arrIds = array();

        
// Get records
        
$objRows $this->Database->prepare("SELECT id FROM " $table " WHERE pid=?" . ($hasSorting " ORDER BY sorting" ""))
                                  ->
execute($id);

        while (
$objRows->next())
        {
            
$arrIds[] = $objRows->id;
        }

        
$blnClipboard false;
        
$arrClipboard $this->Session->get('CLIPBOARD');

        
// Check clipboard
        
if (!empty($arrClipboard[$this->strTable]))
        {
            
$blnClipboard true;
            
$arrClipboard $arrClipboard[$this->strTable];
        }

        for (
$i=0$c=count($arrIds); $i<$c$i++)
        {
            
$return .= ' ' trim($this->generateTree($table$arrIds[$i], array('p'=>$arrIds[($i-1)], 'n'=>$arrIds[($i+1)]), $hasSorting$margin, ($blnClipboard $arrClipboard false), ($id == $arrClipboard ['id'] || (is_array($arrClipboard ['id']) && in_array($id$arrClipboard ['id'])) || (!$blnPtable && !is_array($arrClipboard['id']) && in_array($id$this->Database->getChildRecords($arrClipboard['id'], $table)))), $blnProtected));
        }

        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
     *
     * @return string
     */
    
protected function generateTree($table$id$arrPrevNext$blnHasSorting$intMargin=0$arrClipboard=null$blnCircularReference=false$protectedPage=false$blnNoRecursion=false)
    {
        static 
$session;

        
$session $this->Session->getData();
        
$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) ? 1;
            
$this->Session->setData($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)
        {
            
$this->Session->setData($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'] == || $this->strTable != $table)
            {
                
$objChilds $this->Database->prepare("SELECT id FROM " $table " WHERE pid=?" . ($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'] == || $table == $this->strTable) ? ' toggle_select" onmouseover="Theme.hoverDiv(this,1)" onmouseout="Theme.hoverDiv(this,0)"' '"';

        
$return .= "n  " '<li class="'.((($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && $objRow->type == 'root') || $table != $this->strTable) ? 'tl_folder' 'tl_file').' click2edit'.$mouseover.'><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);

        if (!empty(
$childs))
        {
            
$folderAttribute '';
            
$img = ($session[$node][$id] == 1) ? 'folMinus.gif' 'folPlus.gif';
            
$alt = ($session[$node][$id] == 1) ? $GLOBALS['TL_LANG']['MSC']['collapseNode'] : $GLOBALS['TL_LANG']['MSC']['expandNode'];
            
$return .= '<a href="'.$this->addToUrl('ptg='.$id).'" title="'.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(deserialize($objRow->$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($objRow->$strKey);

                
$args[$k] = $objRef->numRows $objRef->$strField '';
            }
            elseif (
in_array($GLOBALS['TL_DCA'][$table]['fields'][$v]['flag'], array(5678910)))
            {
                
$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 != '') ? (isset($GLOBALS['TL_DCA'][$table]['fields'][$v]['label'][0]) ? $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'] > && $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$folderAttributefalse$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$folderAttributefalse$blnProtected);
        }
        else
        {
            
$return .= Image::getHtml('iconPLAIN.gif''') . ' ' $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);
        }

        
// 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.gif'sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id));
                
$imagePasteInto Image::getHtml('pasteinto.gif'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_.gif').' ' '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a> ';
                    
$_buttons .= ($arrClipboard['mode'] == 'paste' && ($blnCircularReference || $arrClipboard['id'] == $id) || $arrClipboard['mode'] == 'cutAll' && ($blnCircularReference || in_array($id$arrClipboard['id']))) ? Image::getHtml('pasteinto_.gif').' ' '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$id.(!is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.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_.gif') : '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$id.(!is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.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="'.specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][1], $id)).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ' '';
                }
            }
        }

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

        
// Add the records of the table itself
        
if ($table != $this->strTable)
        {
            
$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), $arrClipboardfalse, ($j<(count($ids)-1) || !empty($childs)));
                }
            }
        }

        
// Begin a new submenu
        
if (!$blnNoRecursion)
        {
            if (!empty(
$childs) && $session[$node][$id] == 1)
            {
                
$return .= '<li class="parent" id="'.$node.'_'.$id.'"><ul class="level_'.$level.'">';
            }

            
// Add the records of the parent table
            
if ($session[$node][$id] == 1)
            {
                if (
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'] == && $childs[$k] == $arrClipboard['id']) || $blnCircularReference) ? true false), ($blnProtected || $protectedPage));
                    }
                }
            }

            
// Close the submenu
            
if (!empty($childs) && $session[$node][$id] == 1)
            {
                
$return .= '</ul></li>';
            }
        }

        
$this->Session->setData($session);

        return 
$return;
    }


    
/**
      * Show header of the parent table and list all records of the current table
     *
     * @return string
     */
    
protected function parentView()
    {
        
$blnClipboard false;
        
$arrClipboard $this->Session->get('CLIPBOARD');
        
$table = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->ptable $this->strTable;
        
$blnHasSorting $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields'][0] == 'sorting';
        
$blnMultiboard false;

        
// Check clipboard
        
if (!empty($arrClipboard[$table]))
        {
            
$blnClipboard true;
            
$arrClipboard $arrClipboard[$table];

            if (
is_array($arrClipboard['id']))
            {
                
$blnMultiboard true;
            }
        }

        
// Load the fonts to display the paste hint
        
Config::set('loadGoogleFonts'$blnClipboard);

        
// Load the language file and data container array of the parent table
        
System::loadLanguageFile($this->ptable);
        
$this->loadDataContainer($this->ptable);

        
$return '
<div id="tl_buttons">' 
. (Input::get('nb') ? '&nbsp;' : ($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' && !$blnClipboard && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) ? '
<a href="'
.$this->addToUrl(($blnHasSorting 'act=paste&amp;mode=create' 'act=create&amp;mode=2&amp;pid='.$this->intId)).'" 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> ' '') . ($blnClipboard '
<a href="'
.$this->addToUrl('clipboard=1').'" class="header_clipboard" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['clearClipboard']).'" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['clearClipboard'].'</a> ' $this->generateGlobalButtons()) . '
</div>' 
Message::generate(true);

        
// Get all details of the parent record
        
$objParent $this->Database->prepare("SELECT * FROM " $this->ptable " WHERE id=?")
                                    ->
limit(1)
                                    ->
execute(CURRENT_ID);

        if (
$objParent->numRows 1)
        {
            return 
$return;
        }

        
$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.'">' '').($blnClipboard '

<div id="paste_hint">
  <p>'
.$GLOBALS['TL_LANG']['MSC']['selectNewPosition'].'</p>
</div>' 
'').'

<div class="tl_listing_container parent_view">

<div class="tl_header click2edit toggle_select" onmouseover="Theme.hoverDiv(this,1)" onmouseout="Theme.hoverDiv(this,0)">'
;

        
// List all records of the child table
        
if (!Input::get('act') || Input::get('act') == 'paste' || Input::get('act') == 'select')
        {
            
$this->import('BackendUser''User');

            
// Header
            
$imagePasteNew Image::getHtml('new.gif'$GLOBALS['TL_LANG'][$this->strTable]['pastenew'][0]);
            
$imagePasteAfter Image::getHtml('pasteafter.gif'$GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][0]);
            
$imageEditHeader Image::getHtml('header.gif'$GLOBALS['TL_LANG'][$this->strTable]['editheader'][0]);

            
$return .= '
<div class="tl_content_right">'
.((Input::get('act') == 'select') ? '
<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">' : ($blnClipboard ' <a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid='.$objParent->id . (!$blnMultiboard '&amp;id='.$arrClipboard['id'] : '')).'" title="'.specialchars($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][0]).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a>' : ((!$GLOBALS['TL_DCA'][$this->ptable]['config']['notEditable'] && $this->User->canEditFieldsOf($this->ptable)) ? '
<a href="'
.preg_replace('/&(amp;)?table=[^& ]*/i', (($this->ptable != '') ? '&amp;table='.$this->ptable ''), $this->addToUrl('act=edit')).'" class="edit" title="'.specialchars($GLOBALS['TL_LANG'][$this->strTable]['editheader'][1]).'">'.$imageEditHeader.'</a>' '') . (($blnHasSorting && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) ? ' <a href="'.$this->addToUrl('act=create&amp;mode=2&amp;pid='.$objParent->id.'&amp;id='.$this->intId).'" title="'.specialchars($GLOBALS['TL_LANG'][$this->strTable]['pastenew'][0]).'">'.$imagePasteNew.'</a>' ''))) . '
</div>'
;

            
// Format header fields
            
$add = array();
            
$headerFields $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['headerFields'];

            foreach (
$headerFields as $v)
            {
                
$_v deserialize($objParent->$v);

                
// Translate UUIDs to paths
                
if ($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['inputType'] == 'fileTree')
                {
                    
$objFiles FilesModel::findMultipleByUuids((array) $_v);

                    if (
$objFiles !== null)
                    {
                        
$_v $objFiles->fetchEach('path');
                    }
                }

                if (
is_array($_v))
                {
                    
$_v implode(', '$_v);
                }
                elseif (
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['eval']['multiple'])
                {
                    
$_v = ($_v != '') ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no'];
                }
                elseif (
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['eval']['rgxp'] == 'date')
                {
                    
$_v $_v Date::parse(Config::get('dateFormat'), $_v) : '-';
                }
                elseif (
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['eval']['rgxp'] == 'time')
                {
                    
$_v $_v Date::parse(Config::get('timeFormat'), $_v) : '-';
                }
                elseif (
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['eval']['rgxp'] == 'datim')
                {
                    
$_v $_v Date::parse(Config::get('datimFormat'), $_v) : '-';
                }
                elseif (
$v == 'tstamp')
                {
                    if (
$GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
                    {
                        
$ptable $GLOBALS['TL_DCA'][$this->strTable]['config']['ptable'];
                        
$cond = ($ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?"// backwards compatibility

                        
$objMaxTstamp $this->Database->prepare("SELECT MAX(tstamp) AS tstamp FROM " $this->strTable " WHERE pid=? AND $cond")
                                                       ->
execute($objParent->id$ptable);
                    }
                    else
                    {
                        
$objMaxTstamp $this->Database->prepare("SELECT MAX(tstamp) AS tstamp FROM " $this->strTable " WHERE pid=?")
                                                       ->
execute($objParent->id);
                    }

                    if (!
$objMaxTstamp->tstamp)
                    {
                        
$objMaxTstamp->tstamp $objParent->tstamp;
                    }

                    
$_v Date::parse(Config::get('datimFormat'), max($objParent->tstamp$objMaxTstamp->tstamp));
                }
                elseif (isset(
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['foreignKey']))
                {
                    
$arrForeignKey explode('.'$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['foreignKey'], 2);

                    
$objLabel $this->Database->prepare("SELECT " $arrForeignKey[1] . " AS value FROM " $arrForeignKey[0] . " WHERE id=?")
                                               ->
limit(1)
                                               ->
execute($_v);

                    if (
$objLabel->numRows)
                    {
                        
$_v $objLabel->value;
                    }
                }
                elseif (
is_array($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['reference'][$_v]))
                {
                    
$_v $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['reference'][$_v][0];
                }
                elseif (isset(
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['reference'][$_v]))
                {
                    
$_v $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['reference'][$_v];
                }
                elseif (
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options']))
                {
                    
$_v $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options'][$_v];
                }
                elseif (
is_array($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options_callback']))
                {
                    
$strClass $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options_callback'][0];
                    
$strMethod $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options_callback'][1];

                    
$this->import($strClass);
                    
$options_callback $this->$strClass->$strMethod($this);

                    
$_v $options_callback[$_v];
                }
                elseif (
is_callable($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options_callback']))
                {
                    
$options_callback $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['options_callback']($this);

                    
$_v $options_callback[$_v];
                }

                
// Add the sorting field
                
if ($_v != '')
                {
                    if (isset(
$GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['label']))
                    {
                        
$key is_array($GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['label']) ? $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['label'][0] : $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['label'];
                    }
                    else
                    {
                        
$key = isset($GLOBALS['TL_LANG'][$this->ptable][$v][0]) ? $GLOBALS['TL_LANG'][$this->ptable][$v][0] : $v;
                    }

                    
$add[$key] = $_v;
                }
            }

            
// Trigger the header_callback (see #3417)
            
if (is_array($GLOBALS['TL_DCA'][$table]['list']['sorting']['header_callback']))
            {
                
$strClass $GLOBALS['TL_DCA'][$table]['list']['sorting']['header_callback'][0];
                
$strMethod $GLOBALS['TL_DCA'][$table]['list']['sorting']['header_callback'][1];

                
$this->import($strClass);
                
$add $this->$strClass->$strMethod($add$this);
            }
            elseif (
is_callable($GLOBALS['TL_DCA'][$table]['list']['sorting']['header_callback']))
            {
                
$add $GLOBALS['TL_DCA'][$table]['list']['sorting']['header_callback']($add$this);
            }

            
// Output the header data
            
$return .= '

<table class="tl_header_table">'
;

            foreach (
$add as $k=>$v)
            {
                if (
is_array($v))
                {
                    
$v $v[0];
                }

                
$return .= '
  <tr>
    <td><span class="tl_label">'
.$k.':</span> </td>
    <td>'
.$v.'</td>
  </tr>'
;
            }

            
$return .= '
</table>
</div>'
;

            
$orderBy = array();
            
$firstOrderBy = array();

            
// Add all records of the current table
            
$query "SELECT * FROM " $this->strTable;

            if (
is_array($this->orderBy) && strlen($this->orderBy[0]))
            {
                
$orderBy $this->orderBy;
                
$firstOrderBy preg_replace('/s+.*$/'''$orderBy[0]);

                
// Order by the foreign key
                
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['foreignKey']))
                {
                    
$key explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['foreignKey'], 2);
                    
$query "SELECT *, (SELECT "$key[1] ." FROM "$key[0] ." WHERE "$this->strTable ."."$firstOrderBy ."="$key[0] .".id) AS foreignKey FROM " $this->strTable;
                    
$orderBy[0] = 'foreignKey';
                }
            }
            elseif (
is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields']))
            {
                
$orderBy $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields'];
                
$firstOrderBy preg_replace('/s+.*$/'''$orderBy[0]);
            }

            
$arrProcedure $this->procedure;
            
$arrValues $this->values;

            
// Support empty ptable fields (backwards compatibility)
            
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
            {
                
$arrProcedure[] = ($this->ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?";
                
$arrValues[] = $this->ptable;
            }

            
// WHERE
            
if (!empty($arrProcedure))
            {
                
$query .= " WHERE " implode(' AND '$arrProcedure);
            }
            if (!empty(
$this->root) && is_array($this->root))
            {
                
$query .= (!empty($arrProcedure) ? " AND " " WHERE ") . "id IN(" implode(','array_map('intval'$this->root)) . ")";
            }

            
// ORDER BY
            
if (!empty($orderBy) && is_array($orderBy))
            {
                
$query .= " ORDER BY " implode(', '$orderBy);
            }

            
$objOrderByStmt $this->Database->prepare($query);

            
// LIMIT
            
if (strlen($this->limit))
            {
                
$arrLimit explode(','$this->limit);
                
$objOrderByStmt->limit($arrLimit[1], $arrLimit[0]);
            }

            
$objOrderBy $objOrderByStmt->execute($arrValues);

            if (
$objOrderBy->numRows 1)
            {
                return 
$return '
<p class="tl_empty_parent_view">'
.$GLOBALS['TL_LANG']['MSC']['noResult'].'</p>

</div>'
;
            }

            
// Call the child_record_callback
            
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_callback']) || is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_callback']))
            {
                
$strGroup '';
                
$blnIndent false;
                
$intWrapLevel 0;
                
$row $objOrderBy->fetchAllAssoc();

                
// Make items sortable
                
if ($blnHasSorting)
                {
                    
$return .= '

<ul id="ul_' 
CURRENT_ID '">';
                }

                for (
$i=0$c=count($row); $i<$c$i++)
                {
                    
$this->current[] = $row[$i]['id'];
                    
$imagePasteAfter Image::getHtml('pasteafter.gif'sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $row[$i]['id']));
                    
$imagePasteNew Image::getHtml('new.gif'sprintf($GLOBALS['TL_LANG'][$this->strTable]['pastenew'][1], $row[$i]['id']));

                    
// Decrypt encrypted value
                    
foreach ($row[$i] as $k=>$v)
                    {
                        if (
$GLOBALS['TL_DCA'][$table]['fields'][$k]['eval']['encrypt'])
                        {
                            
$row[$i][$k] = Encryption::decrypt(deserialize($v));
                        }
                    }

                    
// Make items sortable
                    
if ($blnHasSorting)
                    {
                        
$return .= '
<li id="li_' 
$row[$i]['id'] . '">';
                    }

                    
// Add the group header
                    
if (!$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['disableGrouping'] && $firstOrderBy != 'sorting')
                    {
                        
$sortingMode = (count($orderBy) == && $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$row[$i][$firstOrderBy], $sortingMode);
                        
$group $this->formatGroupHeader($firstOrderBy$remoteNew$sortingMode$row);

                        if (
$group != $strGroup)
                        {
                            
$return .= "nn" '<div class="tl_content_header">'.$group.'</div>';
                            
$strGroup $group;
                        }
                    }

                    
$blnWrapperStart in_array($row[$i]['type'], $GLOBALS['TL_WRAPPERS']['start']);
                    
$blnWrapperSeparator in_array($row[$i]['type'], $GLOBALS['TL_WRAPPERS']['separator']);
                    
$blnWrapperStop in_array($row[$i]['type'], $GLOBALS['TL_WRAPPERS']['stop']);

                    
// Closing wrappers
                    
if ($blnWrapperStop)
                    {
                        if (--
$intWrapLevel 1)
                        {
                            
$blnIndent false;
                        }
                    }

                    
$return .= '

<div class="tl_content'
.($blnWrapperStart ' wrapper_start' '').($blnWrapperSeparator ' wrapper_separator' '').($blnWrapperStop ' wrapper_stop' '').($blnIndent ' indent indent_'.$intWrapLevel '').(($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_class'] != '') ? ' ' $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_class'] : '').(($i%== 0) ? ' even' ' odd').' click2edit toggle_select" onmouseover="Theme.hoverDiv(this,1)" onmouseout="Theme.hoverDiv(this,0)">
<div class="tl_content_right">'
;

                    
// Opening wrappers
                    
if ($blnWrapperStart)
                    {
                        if (++
$intWrapLevel 0)
                        {
                            
$blnIndent true;
                        }
                    }

                    
// Edit multiple
                    
if (Input::get('act') == 'select')
                    {
                        
$return .= '<input type="checkbox" name="IDS[]" id="ids_'.$row[$i]['id'].'" class="tl_tree_checkbox" value="'.$row[$i]['id'].'">';
                    }

                    
// Regular buttons
                    
else
                    {
                        
$return .= $this->generateButtons($row[$i], $this->strTable$this->rootfalsenull$row[($i-1)]['id'], $row[($i+1)]['id']);

                        
// Sortable table
                        
if ($blnHasSorting)
                        {
                            
// Create new button
                            
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable'])
                            {
                                
$return .= ' <a href="'.$this->addToUrl('act=create&amp;mode=1&amp;pid='.$row[$i]['id'].'&amp;id='.$objParent->id).'" title="'.specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pastenew'][1], $row[$i]['id'])).'">'.$imagePasteNew.'</a>';
                            }

                            
// Prevent circular references
                            
if ($blnClipboard && $arrClipboard['mode'] == 'cut' && $row[$i]['id'] == $arrClipboard['id'] || $blnMultiboard && $arrClipboard['mode'] == 'cutAll' && in_array($row[$i]['id'], $arrClipboard['id']))
                            {
                                
$return .= ' ' Image::getHtml('pasteafter_.gif');
                            }

                            
// Copy/move multiple
                            
elseif ($blnMultiboard)
                            {
                                
$return .= ' <a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$row[$i]['id']).'" title="'.specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $row[$i]['id'])).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a>';
                            }

                            
// Paste buttons
                            
elseif ($blnClipboard)
                            {
                                
$return .= ' <a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=1&amp;pid='.$row[$i]['id'].'&amp;id='.$arrClipboard['id']).'" title="'.specialchars(sprintf($GLOBALS['TL_LANG'][$this->strTable]['pasteafter'][1], $row[$i]['id'])).'" onclick="Backend.getScrollOffset()">'.$imagePasteAfter.'</a>';
                            }

                            
// Drag handle
                            
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
                            {
                                
$return .= ' ' Image::getHtml('drag.gif''''class="drag-handle" title="' sprintf($GLOBALS['TL_LANG'][$this->strTable]['cut'][1], $row[$i]['id']) . '"');
                            }
                        }
                    }

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

                        
$this->import($strClass);
                        
$return .= '</div>'.$this->$strClass->$strMethod($row[$i]).'</div>';
                    }
                    elseif (
is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_callback']))
                    {
                        
$return .= '</div>'.$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['child_record_callback']($row[$i]).'</div>';
                    }

                    
// Make items sortable
                    
if ($blnHasSorting)
                    {
                        
$return .= '

</li>'
;
                    }
                }
            }
        }

        
// Make items sortable
        
if ($blnHasSorting && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'] && Input::get('act') != 'select')
        {
            
$return .= '
</ul>

<script>
  Backend.makeParentViewSortable("ul_' 
CURRENT_ID '");
</script>'
;
        }

        
$return .= '

</div>'
;

        
// Close form
        
if (Input::get('act') == 'select')
        {
            
// Submit buttons
            
$arrButtons = array();

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
            {
                
$arrButtons['delete'] = '<input type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(''.$GLOBALS['TL_LANG']['MSC']['delAllConfirm'].'')" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['deleteSelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
            {
                
$arrButtons['cut'] = '<input type="submit" name="cut" id="cut" class="tl_submit" accesskey="x" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['moveSelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
            {
                
$arrButtons['copy'] = '<input type="submit" name="copy" id="copy" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['copySelected']).'">';
            }

            if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
            {
                
$arrButtons['override'] = '<input type="submit" name="override" id="override" class="tl_submit" accesskey="v" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['overrideSelected']).'">';
                
$arrButtons['edit'] = '<input type="submit" name="edit" id="edit" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['editSelected']).'">';
            }

            
// 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;
    }


    
/**
     * 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(' '$v2);

                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(5678910)))
                {
                    
$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 (also for backwards compatibility)
                
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'] == && ($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) ? '&amp;mode=2' '') . '&amp;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>';
        }

        
// List records
        
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(':'$f2);
                    }

                    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(':'$f2);
                    }

                    
$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">&nbsp;</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(5678910)))
                    {
                        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_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no'];
                    }
                    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'] > && $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) == && $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 == 0) ? 'even' 'odd').' click2edit toggle_select" onmouseover="Theme.hoverRow(this,1)" onmouseout="Theme.hoverRow(this,0)">
    '
;

                
$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 (backwards compatibility)
                    
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'] = '<input type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(''.$GLOBALS['TL_LANG']['MSC']['delAllConfirm'].'')" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['deleteSelected']).'">';
                }

                if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
                {
                    
$arrButtons['copy'] = '<input type="submit" name="copy" id="copy" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['copySelected']).'">';
                }

                if (!
$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
                {
                    
$arrButtons['override'] = '<input type="submit" name="override" id="override" class="tl_submit" accesskey="v" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['overrideSelected']).'">';
                    
$arrButtons['edit'] = '<input type="submit" name="edit" id="edit" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['editSelected']).'">';
                }

                
// 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;
    }


    
/**
     * Build the sort panel and return it as string
     *
     * @return string
     */
    
protected function panel()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['panelLayout'] == '')
        {
            return 
'';
        }

        
$intFilterPanel 0;
        
$arrPanels = array();

        foreach (
trimsplit(';'$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['panelLayout']) as $strPanel)
        {
            
$panels '';
            
$arrSubPanels trimsplit(','$strPanel);

            foreach (
$arrSubPanels as $strSubPanel)
            {
                
$panel '';

                
// Regular panels
                
if ($strSubPanel == 'search' || $strSubPanel == 'limit' || $strSubPanel == 'sort')
                {
                    
$panel $this->{$strSubPanel 'Menu'}();
                }

                
// Multiple filter subpanels can be defined to split the fields across panels
                
elseif ($strSubPanel == 'filter')
                {
                    
$panel $this->{$strSubPanel 'Menu'}(++$intFilterPanel);
                }

                
// Call the panel_callback
                
else
                {
                    
$arrCallback $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['panel_callback'][$strSubPanel];

                    if (
is_array($arrCallback))
                    {
                        
$this->import($arrCallback[0]);
                        
$panel $this->{$arrCallback[0]}->{$arrCallback[1]}($this);
                    }
                    elseif (
is_callable($arrCallback))
                    {
                        
$panel $arrCallback($this);
                    }
                }

                
// Add the panel if it is not empty
                
if ($panel != '')
                {
                    
$panels $panel $panels;
                }
            }

            
// Add the group if it is not empty
            
if ($panels != '')
            {
                
$arrPanels[] = $panels;
            }
        }

        if (empty(
$arrPanels))
        {
            return 
'';
        }

        if (
Input::post('FORM_SUBMIT') == 'tl_filters')
        {
            
$this->reload();
        }

        
$return '';
        
$intTotal count($arrPanels);
        
$intLast $intTotal 1;

        for (
$i=0$i<$intTotal$i++)
        {
            
$submit '';

            if (
$i == $intLast)
            {
                
$submit '

<div class="tl_submit_panel tl_subpanel">
<input type="image" name="filter" id="filter" src="' 
TL_FILES_URL 'system/themes/' Backend::getTheme() . '/images/reload.gif" class="tl_img_submit" title="' specialchars($GLOBALS['TL_LANG']['MSC']['applyTitle']) . '" alt="' specialchars($GLOBALS['TL_LANG']['MSC']['apply']) . '">
</div>'
;
            }

            
$return .= '
<div class="tl_panel">' 
$submit $arrPanels[$i] . '

<div class="clear"></div>

</div>'
;
        }

        
$return '
<form action="'
.ampersand(Environment::get('request'), true).'" class="tl_form" method="post">
<div class="tl_formbody">
<input type="hidden" name="FORM_SUBMIT" value="tl_filters">
<input type="hidden" name="REQUEST_TOKEN" value="'
.REQUEST_TOKEN.'">
$return '
</div>
</form>
'
;

        return 
$return;
    }


    
/**
     * Return a search form that allows to search results using regular expressions
     *
     * @return string
     */
    
protected function searchMenu()
    {
        
$searchFields = array();
        
$session $this->Session->getData();

        
// Get search fields
        
foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'] as $k=>$v)
        {
            if (
$v['search'])
            {
                
$searchFields[] = $k;
            }
        }

        
// Return if there are no search fields
        
if (empty($searchFields))
        {
            return 
'';
        }

        
// Store search value in the current session
        
if (Input::post('FORM_SUBMIT') == 'tl_filters')
        {
            
$session['search'][$this->strTable]['value'] = '';
            
$session['search'][$this->strTable]['field'] = Input::post('tl_field'true);

            
// Make sure the regular expression is valid
            
if (Input::postRaw('tl_value') != '')
            {
                try
                {
                    
$this->Database->prepare("SELECT * FROM " $this->strTable " WHERE " Input::post('tl_field'true) . " REGEXP ?")
                                   ->
limit(1)
                                   ->
execute(Input::postRaw('tl_value'));

                    
$session['search'][$this->strTable]['value'] = Input::postRaw('tl_value');
                }
                catch (
Exception $e) {}
            }

            
$this->Session->setData($session);
        }

        
// Set the search value from the session
        
elseif ($session['search'][$this->strTable]['value'] != '')
        {
            
$strPattern "CAST(%s AS CHAR) REGEXP ?";

            if (
substr(Config::get('dbCollation'), -3) == '_ci')
            {
                
$strPattern "LOWER(CAST(%s AS CHAR)) REGEXP LOWER(?)";
            }

            
$fld $session['search'][$this->strTable]['field'];

            if (isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey']))
            {
                list(
$t$f) = explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey']);
                
$this->procedure[] = "(" sprintf($strPattern$fld) . " OR " sprintf($strPattern"(SELECT $f FROM $t WHERE $t.id={$this->strTable}.$fld)") . ")";
                
$this->values[] = $session['search'][$this->strTable]['value'];
            }
            else
            {
                
$this->procedure[] = sprintf($strPattern$fld);
            }

            
$this->values[] = $session['search'][$this->strTable]['value'];
        }

        
$options_sorter = array();

        foreach (
$searchFields as $field)
        {
            
$option_label $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] ?: (is_array($GLOBALS['TL_LANG']['MSC'][$field]) ? $GLOBALS['TL_LANG']['MSC'][$field][0] : $GLOBALS['TL_LANG']['MSC'][$field]);
            
$options_sorter[utf8_romanize($option_label).'_'.$field] = '  <option value="'.specialchars($field).'"'.(($field == $session['search'][$this->strTable]['field']) ? ' selected="selected"' '').'>'.$option_label.'</option>';
        }

        
// Sort by option values
        
$options_sorter natcaseksort($options_sorter);
        
$active = ($session['search'][$this->strTable]['value'] != '') ? true false;

        return 
'

<div class="tl_search tl_subpanel">
<strong>' 
$GLOBALS['TL_LANG']['MSC']['search'] . ':</strong>
<select name="tl_field" class="tl_select' 
. ($active ' active' '') . '">
'
.implode("n"$options_sorter).'
</select>
<span> = </span>
<input type="search" name="tl_value" class="tl_text' 
. ($active ' active' '') . '" value="'.specialchars($session['search'][$this->strTable]['value']).'">
</div>'
;
    }


    
/**
     * Return a select menu that allows to sort results by a particular field
     *
     * @return string
     */
    
protected function sortMenu()
    {
        if (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] != && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] != 4)
        {
            return 
'';
        }

        
$sortingFields = array();

        
// Get sorting fields
        
foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'] as $k=>$v)
        {
            if (
$v['sorting'])
            {
                
$sortingFields[] = $k;
            }
        }

        
// Return if there are no sorting fields
        
if (empty($sortingFields))
        {
            return 
'';
        }

        
$this->bid 'tl_buttons_a';
        
$session $this->Session->getData();
        
$orderBy $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields'];
        
$firstOrderBy preg_replace('/s+.*$/'''$orderBy[0]);

        
// Add PID to order fields
        
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == && $this->Database->fieldExists('pid'$this->strTable))
        {
            
array_unshift($orderBy'pid');
        }

        
// Set sorting from user input
        
if (Input::post('FORM_SUBMIT') == 'tl_filters')
        {
            
$strSort Input::post('tl_sort');

            
// Validate the user input (thanks to aulmn) (see #4971)
            
if (in_array($strSort$sortingFields))
            {
                
$session['sorting'][$this->strTable] = in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$strSort]['flag'], array(24681012)) ? "$strSort DESC" $strSort;
                
$this->Session->setData($session);
            }
        }

        
// Overwrite the "orderBy" value with the session value
        
elseif (strlen($session['sorting'][$this->strTable]))
        {
            
$overwrite preg_quote(preg_replace('/s+.*$/'''$session['sorting'][$this->strTable]), '/');
            
$orderBy array_diff($orderBypreg_grep('/^'.$overwrite.'/i'$orderBy));

            
array_unshift($orderBy$session['sorting'][$this->strTable]);

            
$this->firstOrderBy $overwrite;
            
$this->orderBy $orderBy;
        }

        
$options_sorter = array();

        
// Sorting fields
        
foreach ($sortingFields as $field)
        {
            
$options_label strlen(($lbl is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'])) ? $lbl $GLOBALS['TL_LANG']['MSC'][$field];

            if (
is_array($options_label))
            {
                
$options_label $options_label[0];
            }

            
$options_sorter[$options_label] = '  <option value="'.specialchars($field).'"'.((!strlen($session['sorting'][$this->strTable]) && $field == $firstOrderBy || $field == str_replace(' DESC'''$session['sorting'][$this->strTable])) ? ' selected="selected"' '').'>'.$options_label.'</option>';
        }

        
// Sort by option values
        
uksort($options_sorter'strcasecmp');

        return 
'

<div class="tl_sorting tl_subpanel">
<strong>' 
$GLOBALS['TL_LANG']['MSC']['sortBy'] . ':</strong>
<select name="tl_sort" id="tl_sort" class="tl_select">
'
.implode("n"$options_sorter).'
</select>
</div>'
;
    }


    
/**
     * Return a select menu to limit results
     *
     * @param boolean $blnOptional
     *
     * @return string
     */
    
protected function limitMenu($blnOptional=false)
    {
        
$session $this->Session->getData();
        
$filter = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) ? $this->strTable.'_'.CURRENT_ID $this->strTable;
        
$fields '';

        
// Set limit from user input
        
if (Input::post('FORM_SUBMIT') == 'tl_filters' || Input::post('FORM_SUBMIT') == 'tl_filters_limit')
        {
            
$strLimit Input::post('tl_limit');

            if (
$strLimit == 'tl_limit')
            {
                unset(
$session['filter'][$filter]['limit']);
            }
            else
            {
                
// Validate the user input (thanks to aulmn) (see #4971)
                
if ($strLimit == 'all' || preg_match('/^[0-9]+,[0-9]+$/'$strLimit))
                {
                    
$session['filter'][$filter]['limit'] = $strLimit;
                }
            }

            
$this->Session->setData($session);

            if (
Input::post('FORM_SUBMIT') == 'tl_filters_limit')
            {
                
$this->reload();
            }
        }

        
// Set limit from table configuration
        
else
        {
            
$this->limit = ($session['filter'][$filter]['limit'] != '') ? (($session['filter'][$filter]['limit'] == 'all') ? null $session['filter'][$filter]['limit']) : '0,' Config::get('resultsPerPage');

            
$arrProcedure $this->procedure;
            
$arrValues $this->values;
            
$query "SELECT COUNT(*) AS count FROM " $this->strTable;

            if (!empty(
$this->root) && is_array($this->root))
            {
                
$arrProcedure[] = 'id IN(' implode(','$this->root) . ')';
            }

            
// Support empty ptable fields (backwards compatibility)
            
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
            {
                
$arrProcedure[] = ($this->ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?";
                
$arrValues[] = $this->ptable;
            }

            if (!empty(
$arrProcedure))
            {
                
$query .= " WHERE " implode(' AND '$arrProcedure);
            }

            
$objTotal $this->Database->prepare($query)->execute($arrValues);
            
$this->total $objTotal->count;
            
$options_total 0;
            
$blnIsMaxResultsPerPage false;

            
// Overall limit
            
if ($this->total Config::get('maxResultsPerPage') && ($this->limit === null || preg_replace('/^.*,/'''$this->limit) == Config::get('maxResultsPerPage')))
            {
                if (
$this->limit === null)
                {
                    
$this->limit '0,' Config::get('maxResultsPerPage');
                }

                
$blnIsMaxResultsPerPage true;
                
Config::set('resultsPerPage'Config::get('maxResultsPerPage'));
                
$session['filter'][$filter]['limit'] = Config::get('maxResultsPerPage');
            }

            
$options '';

            
// Build options
            
if ($this->total 0)
            {
                
$options '';
                
$options_total ceil($this->total Config::get('resultsPerPage'));

                
// Reset limit if other parameters have decreased the number of results
                
if ($this->limit !== null && ($this->limit == '' || preg_replace('/,.*$/'''$this->limit) > $this->total))
                {
                    
$this->limit '0,'.Config::get('resultsPerPage');
                }

                
// Build options
                
for ($i=0$i<$options_total$i++)
                {
                    
$this_limit = ($i*Config::get('resultsPerPage')).','.Config::get('resultsPerPage');
                    
$upper_limit = ($i*Config::get('resultsPerPage')+Config::get('resultsPerPage'));

                    if (
$upper_limit $this->total)
                    {
                        
$upper_limit $this->total;
                    }

                    
$options .= '
  <option value="'
.$this_limit.'"' Widget::optionSelected($this->limit$this_limit) . '>'.($i*Config::get('resultsPerPage')+1).' - '.$upper_limit.'</option>';
                }

                if (!
$blnIsMaxResultsPerPage)
                {
                    
$options .= '
  <option value="all"' 
Widget::optionSelected($this->limitnull) . '>'.$GLOBALS['TL_LANG']['MSC']['filterAll'].'</option>';
                }
            }

            
// Return if there is only one page
            
if ($blnOptional && ($this->total || $options_total 2))
            {
                return 
'';
            }

            
$fields '
<select name="tl_limit" class="tl_select' 
. (($session['filter'][$filter]['limit'] != 'all' && $this->total Config::get('resultsPerPage')) ? ' active' '') . '" onchange="this.form.submit()">
  <option value="tl_limit">'
.$GLOBALS['TL_LANG']['MSC']['filterRecords'].'</option>'.$options.'
</select> '
;
        }

        return 
'

<div class="tl_limit tl_subpanel">
<strong>' 
$GLOBALS['TL_LANG']['MSC']['showOnly'] . ':</strong> '.$fields.'
</div>'
;
    }


    
/**
     * Generate the filter panel and return it as HTML string
     *
     * @param integer $intFilterPanel
     *
     * @return string
     */
    
protected function filterMenu($intFilterPanel)
    {
        
$fields '';
        
$this->bid 'tl_buttons_a';
        
$sortingFields = array();
        
$session $this->Session->getData();
        
$filter = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) ? $this->strTable.'_'.CURRENT_ID $this->strTable;

        
// Get the sorting fields
        
foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'] as $k=>$v)
        {
            if (
intval($v['filter']) == $intFilterPanel)
            {
                
$sortingFields[] = $k;
            }
        }

        
// Return if there are no sorting fields
        
if (empty($sortingFields))
        {
            return 
'';
        }

        
// Set filter from user input
        
if (Input::post('FORM_SUBMIT') == 'tl_filters')
        {
            foreach (
$sortingFields as $field)
            {
                if (
Input::post($fieldtrue) != 'tl_'.$field)
                {
                    
$session['filter'][$filter][$field] = Input::post($fieldtrue);
                }
                else
                {
                    unset(
$session['filter'][$filter][$field]);
                }
            }

            
$this->Session->setData($session);
        }

        
// Set filter from table configuration
        
else
        {
            foreach (
$sortingFields as $field)
            {
                if (isset(
$session['filter'][$filter][$field]))
                {
                    
// Sort by day
                    
if (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(56)))
                    {
                        if (
$session['filter'][$filter][$field] == '')
                        {
                            
$this->procedure[] = $field "=''";
                        }
                        else
                        {
                            
$objDate = new Date($session['filter'][$filter][$field]);
                            
$this->procedure[] = $field ' BETWEEN ? AND ?';
                            
$this->values[] = $objDate->dayBegin;
                            
$this->values[] = $objDate->dayEnd;
                        }
                    }

                    
// Sort by month
                    
elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(78)))
                    {
                        if (
$session['filter'][$filter][$field] == '')
                        {
                            
$this->procedure[] = $field "=''";
                        }
                        else
                        {
                            
$objDate = new Date($session['filter'][$filter][$field]);
                            
$this->procedure[] = $field ' BETWEEN ? AND ?';
                            
$this->values[] = $objDate->monthBegin;
                            
$this->values[] = $objDate->monthEnd;
                        }
                    }

                    
// Sort by year
                    
elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(910)))
                    {
                        if (
$session['filter'][$filter][$field] == '')
                        {
                            
$this->procedure[] = $field "=''";
                        }
                        else
                        {
                            
$objDate = new Date($session['filter'][$filter][$field]);
                            
$this->procedure[] = $field ' BETWEEN ? AND ?';
                            
$this->values[] = $objDate->yearBegin;
                            
$this->values[] = $objDate->yearEnd;
                        }
                    }

                    
// Manual filter
                    
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['multiple'])
                    {
                        
// CSV lists (see #2890)
                        
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['csv']))
                        {
                            
$this->procedure[] = $this->Database->findInSet('?'$fieldtrue);
                            
$this->values[] = $session['filter'][$filter][$field];
                        }
                        else
                        {
                            
$this->procedure[] = $field ' LIKE ?';
                            
$this->values[] = '%"' $session['filter'][$filter][$field] . '"%';
                        }
                    }

                    
// Other sort algorithm
                    
else
                    {
                        
$this->procedure[] = $field '=?';
                        
$this->values[] = $session['filter'][$filter][$field];
                    }
                }
            }
        }

        
// Add sorting options
        
foreach ($sortingFields as $cnt=>$field)
        {
            
$arrValues = array();
            
$arrProcedure = array();

            if (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4)
            {
                
$arrProcedure[] = 'pid=?';
                
$arrValues[] = CURRENT_ID;
            }

            if (!empty(
$this->root) && is_array($this->root))
            {
                
$arrProcedure[] = "id IN(" implode(','array_map('intval'$this->root)) . ")";
            }

            
// Check for a static filter (see #4719)
            
if (!empty($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter']) && is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter']))
            {
                foreach (
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter'] as $fltr)
                {
                    
$arrProcedure[] = $fltr[0];
                    
$arrValues[] = $fltr[1];
                }
            }

            
// Support empty ptable fields (backwards compatibility)
            
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['dynamicPtable'])
            {
                
$arrProcedure[] = ($this->ptable == 'tl_article') ? "(ptable=? OR ptable='')" "ptable=?";
                
$arrValues[] = $this->ptable;
            }

            
$objFields $this->Database->prepare("SELECT DISTINCT " $field " FROM " $this->strTable . ((is_array($arrProcedure) && strlen($arrProcedure[0])) ? ' WHERE ' implode(' AND '$arrProcedure) : ''))
                                        ->
execute($arrValues);

            
// Begin select menu
            
$fields .= '
<select name="'
.$field.'" id="'.$field.'" class="tl_select' . (isset($session['filter'][$filter][$field]) ? ' active' '') . '">
  <option value="tl_'
.$field.'">'.(is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label']).'</option>
  <option value="tl_'
.$field.'">---</option>';

            if (
$objFields->numRows)
            {
                
$options $objFields->fetchEach($field);

                
// Sort by day
                
if (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(56)))
                {
                    (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'] == 6) ? rsort($options) : sort($options);

                    foreach (
$options as $k=>$v)
                    {
                        if (
$v == '')
                        {
                            
$options[$v] = '-';
                        }
                        else
                        {
                            
$options[$v] = Date::parse(Config::get('dateFormat'), $v);
                        }

                        unset(
$options[$k]);
                    }
                }

                
// Sort by month
                
elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(78)))
                {
                    (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'] == 8) ? rsort($options) : sort($options);

                    foreach (
$options as $k=>$v)
                    {
                        if (
$v == '')
                        {
                            
$options[$v] = '-';
                        }
                        else
                        {
                            
$options[$v] = date('Y-m'$v);
                            
$intMonth = (date('m'$v) - 1);

                            if (isset(
$GLOBALS['TL_LANG']['MONTHS'][$intMonth]))
                            {
                                
$options[$v] = $GLOBALS['TL_LANG']['MONTHS'][$intMonth] . ' ' date('Y'$v);
                            }
                        }

                        unset(
$options[$k]);
                    }
                }

                
// Sort by year
                
elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(910)))
                {
                    (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'] == 10) ? rsort($options) : sort($options);

                    foreach (
$options as $k=>$v)
                    {
                        if (
$v == '')
                        {
                            
$options[$v] = '-';
                        }
                        else
                        {
                            
$options[$v] = date('Y'$v);
                        }

                        unset(
$options[$k]);
                    }
                }

                
// Manual filter
                
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['multiple'])
                {
                    
$moptions = array();

                    
// TODO: find a more effective solution
                    
foreach($options as $option)
                    {
                        
// CSV lists (see #2890)
                        
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['csv']))
                        {
                            
$doptions trimsplit($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['csv'], $option);
                        }
                        else
                        {
                            
$doptions deserialize($option);
                        }

                        if (
is_array($doptions))
                        {
                            
$moptions array_merge($moptions$doptions);
                        }
                    }

                    
$options $moptions;
                }

                
$options array_unique($options);
                
$options_callback = array();

                
// Call the options_callback
                
if ((is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback']) || is_callable($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback'])) && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'])
                {
                    if (
is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback']))
                    {
                        
$strClass $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback'][0];
                        
$strMethod $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback'][1];

                        
$this->import($strClass);
                        
$options_callback $this->$strClass->$strMethod($this);
                    }
                    elseif (
is_callable($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback']))
                    {
                        
$options_callback $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback']($this);
                    }

                    
// Sort options according to the keys of the callback array
                    
$options array_intersect(array_keys($options_callback), $options);
                }

                
$options_sorter = array();
                
$blnDate in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(5678910));

                
// Options
                
foreach ($options as $kk=>$vv)
                {
                    
$value $blnDate $kk $vv;

                    
// Options callback
                    
if (!empty($options_callback) && is_array($options_callback))
                    {
                        
$vv $options_callback[$vv];
                    }

                    
// Replace the ID with the foreign key
                    
elseif (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey']))
                    {
                        
$key explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey'], 2);

                        
$objParent $this->Database->prepare("SELECT " $key[1] . " AS value FROM " $key[0] . " WHERE id=?")
                                                    ->
limit(1)
                                                    ->
execute($vv);

                        if (
$objParent->numRows)
                        {
                            
$vv $objParent->value;
                        }
                    }

                    
// Replace boolean checkbox value with "yes" and "no"
                    
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['isBoolean'] || ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['multiple']))
                    {
                        
$vv = ($vv != '') ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no'];
                    }

                    
// Get the name of the parent record (see #2703)
                    
elseif ($field == 'pid')
                    {
                        
$this->loadDataContainer($this->ptable);
                        
$showFields $GLOBALS['TL_DCA'][$this->ptable]['list']['label']['fields'];

                        if (!
$showFields[0])
                        {
                            
$showFields[0] = 'id';
                        }

                        
$objShowFields $this->Database->prepare("SELECT " $showFields[0] . " FROM "$this->ptable " WHERE id=?")
                                                        ->
limit(1)
                                                        ->
execute($vv);

                        if (
$objShowFields->numRows)
                        {
                            
$vv $objShowFields->{$showFields[0]};
                        }
                    }

                    
$option_label '';

                    
// Use reference array
                    
if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference']))
                    {
                        
$option_label is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$vv]) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$vv][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$vv];
                    }

                    
// Associative array
                    
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options']))
                    {
                        
$option_label $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options'][$vv];
                    }

                    
// No empty options allowed
                    
if (!strlen($option_label))
                    {
                        
$option_label $vv ?: '-';
                    }

                    
$options_sorter['  <option value="' specialchars($value) . '"' . ((isset($session['filter'][$filter][$field]) && $value == $session['filter'][$filter][$field]) ? ' selected="selected"' '').'>'.$option_label.'</option>'] = utf8_romanize($option_label);
                }

                
// Sort by option values
                
if (!$blnDate)
                {
                    
natcasesort($options_sorter);

                    if (
in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(2412)))
                    {
                        
$options_sorter array_reverse($options_sortertrue);
                    }
                }

                
$fields .= "n" implode("n"array_keys($options_sorter));
            }

            
// End select menu
            
$fields .= '
</select> '
;

            
// Force a line-break after six elements (see #3777)
            
if ((($cnt 1) % 6) == 0)
            {
                
$fields .= '<br>';
            }
        }

        return 
'

<div class="tl_filter tl_subpanel">
<strong>' 
$GLOBALS['TL_LANG']['MSC']['filter'] . ':</strong> ' $fields '
</div>'
;
    }


    
/**
     * Return a pagination menu to browse results
     *
     * @return string
     */
    
protected function paginationMenu()
    {
        
$session $this->Session->getData();
        
$filter = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) ? $this->strTable.'_'.CURRENT_ID $this->strTable;

        list(
$offset$limit) = explode(','$this->limit);

        
// Set the limit filter based on the page number
        
if (isset($_GET['lp']))
        {
            
$lp intval(Input::get('lp')) - 1;

            if (
$lp >= && $lp ceil($this->total $limit))
            {
                
$session['filter'][$filter]['limit'] = ($lp $limit) . ',' $limit;
                
$this->Session->setData($session);
            }

            
$this->redirect(preg_replace('/&(amp;)?lp=[^&]+/i'''Environment::get('request')));
        }

        if (
$limit// see #6923
        
{
            
Input::setGet('lp'$offset $limit 1);
        }

        
$objPagination = new Pagination($this->total$limit7'lp', new BackendTemplate('be_pagination'), true);

        return 
$objPagination->generate();
    }


    
/**
     * Return the formatted group header as string
     *
     * @param string  $field
     * @param mixed   $value
     * @param integer $mode
     *
     * @return string
     */
    
protected function formatCurrentValue($field$value$mode)
    {
        
$remoteNew $value// see #3861

        
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['multiple'])
        {
            
$remoteNew = ($value != '') ? ucfirst($GLOBALS['TL_LANG']['MSC']['yes']) : ucfirst($GLOBALS['TL_LANG']['MSC']['no']);
        }
        elseif (isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey']))
        {
            
$key explode('.'$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey'], 2);

            
$objParent $this->Database->prepare("SELECT " $key[1] . " AS value FROM " $key[0] . " WHERE id=?")
                                        ->
limit(1)
                                        ->
execute($value);

            if (
$objParent->numRows)
            {
                
$remoteNew $objParent->value;
            }
        }
        elseif (
in_array($mode, array(12)))
        {
            
$remoteNew = ($value != '') ? ucfirst(utf8_substr($value 01)) : '-';
        }
        elseif (
in_array($mode, array(34)))
        {
            if (!isset(
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['length']))
            {
                
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['length'] = 2;
            }

            
$remoteNew = ($value != '') ? ucfirst(utf8_substr($value 0$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['length'])) : '-';
        }
        elseif (
in_array($mode, array(56)))
        {
            
$remoteNew = ($value != '') ? Date::parse(Config::get('dateFormat'), $value) : '-';
        }
        elseif (
in_array($mode, array(78)))
        {
            
$remoteNew = ($value != '') ? date('Y-m'$value) : '-';
            
$intMonth = ($value != '') ? (date('m'$value) - 1) : '-';

            if (isset(
$GLOBALS['TL_LANG']['MONTHS'][$intMonth]))
            {
                
$remoteNew = ($value != '') ? $GLOBALS['TL_LANG']['MONTHS'][$intMonth] . ' ' date('Y'$value) : '-';
            }
        }
        elseif (
in_array($mode, array(910)))
        {
            
$remoteNew = ($value != '') ? date('Y'$value) : '-';
        }
        else
        {
            if (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['multiple'])
            {
                
$remoteNew = ($value != '') ? $field '';
            }
            elseif (
is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference']))
            {
                
$remoteNew $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$value];
            }
            elseif (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options']))
            {
                
$remoteNew $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options'][$value];
            }
            else
            {
                
$remoteNew $value;
            }

            if (
is_array($remoteNew))
            {
                
$remoteNew $remoteNew[0];
            }

            if (empty(
$remoteNew))
            {
                
$remoteNew '-';
            }
        }

        return 
$remoteNew;
    }


    
/**
     * Return the formatted group header as string
     *
     * @param string  $field
     * @param mixed   $value
     * @param integer $mode
     * @param array   $row
     *
     * @return string
     */
    
protected function formatGroupHeader($field$value$mode$row)
    {
        static 
$lookup = array();

        if (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options']))
        {
            
$group $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options'][$value];
        }
        elseif (
is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback']))
        {
            if (!isset(
$lookup[$field]))
            {
                
$strClass $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback'][0];
                
$strMethod $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['options_callback'][1];

                
$this->import($strClass);
                
$lookup[$field] = $this->$strClass->$strMethod($this);
            }

            
$group $lookup[$field][$value];
        }
        else
        {
            
$group is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$value]) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$value][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['reference'][$value];
        }

        if (empty(
$group))
        {
            
$group is_array($GLOBALS['TL_LANG'][$this->strTable][$value]) ? $GLOBALS['TL_LANG'][$this->strTable][$value][0] : $GLOBALS['TL_LANG'][$this->strTable][$value];
        }

        if (empty(
$group))
        {
            
$group $value;

            if (
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['eval']['isBoolean'] && $value != '-')
            {
                
$group is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['label'];
            }
        }

        
// Call the group callback ($group, $sortingMode, $firstOrderBy, $row, $this)
        
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['group_callback']))
        {
            
$strClass $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['group_callback'][0];
            
$strMethod $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['group_callback'][1];

            
$this->import($strClass);
            
$group $this->$strClass->$strMethod($group$mode$field$row$this);
        }
        elseif (
is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['group_callback']))
        {
            
$group $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['group_callback']($group$mode$field$row$this);
        }

        return 
$group;
    }
}
Онлайн: 1
Реклама