Contao – manuelles Sortieren im „sorting mode 2“

Ab Contao 4: https://github.com/hh-com/contao-listviewsortable


Bei der Erstellung von Backend-Module bietet Contao einige Möglichkeiten die Datensätze automatisch zu sortieren (Contao Reference).
Unter anderem können im Sortier-Mode 4 die Datensätze manuell via Drag an Drop sortiert werden. Im Mode 2 ist dies nicht möglich.

Nachfolgend ein Script wie man einem Up/Down Button nachrüsten kann (btw. das Script kann gerne optimiert werden). Die Sortierung erfolgt dabei über den Array-Key.

Felder für die Sortierung: groupBy, sorting ASC
Das Feld „groupBy“ liefert ein Select, welches die Datensätze kategorisiert.

/*...*/
'sorting' => array
(
	'sql'                     => "int(10) unsigned NOT NULL default '0'"
),
...
'groupBy' => array
(
	'label'                   => &$GLOBALS['TL_LANG']['tl_example']['groupBy'],
	'default'                 => 'ascending',
	'exclude'                 => true,
	'filter'                  => true,
	'inputType'               => 'select',
	'options'                 => array("Erde","Luft","Wasser","Feuer"),
	'eval'                    => array('tl_class'=>'clr w50', 'includeBlankOption'=>true),
	'sql'                     => "varchar(255) NOT NULL default ''"
),
...

Beide Felder werden im Array  „list->sorting“ eingetragen:
Mode 2 = Sortierung nach einem variablen Feld
Flag 11 = Aufsteigende Sortierung

'sorting' => array
(
	'mode'                    => 2,
	'fields'                  => array('groupBy', 'sorting ASC'),
	'flag'                    => 11,
	'panelLayout'             => 'search,limit',
),

Für den Up/Down – Button wird „operations“ um diese Felder erweitert:

'up' => array
(
	'label'			=> &$GLOBALS['TL_LANG']['tl_example']['up'],
	'href'			=> 'sorting=up',
	'icon'			=> 'up.gif',
	'button_callback'     	=> array('tl_example', 'sortingUp')
),
'down' => array
(
	'label'			=> &$GLOBALS['TL_LANG']['tl_example']['down'],
	'href'			=> 'sorting=down',
	'icon'			=> 'down.gif',
	'button_callback'     	=> array('tl_example', 'sortingDown')
),

Der „button_callback“ ruft die jeweilige Funktion für die Sortierung und gibt gleichzeitig den richtigen Button aus.

/* insert into class tl_example extends Backend */
public function sortingUp($row, $href, $label, $title, $icon, $attributes)
	{
		
		/* Redirect to module home after change position*/
		if ($this->Input->get('sortId') AND $this->Input->get('sorting') == "up")
        {
			$thisId = $this->Input->get('sortId');
			$sortByGroup = $this->Input->get('groupBy');
			
			$dbObj = $this->Database->prepare("SELECT * FROM tl_example WHERE groupBy = ? ORDER BY sorting ASC")
				->execute( $sortByGroup );
			
			if ($dbObj->numRows == NULL)
				return false;
			
			$allData = $dbObj->fetchAllAssoc();
			
			/* Get all data from DB, save temp array, get new position and unset the array by key */
			foreach ( $allData AS $key => $data )
			{
				if ( $data['id'] == $thisId )
				{
					$temp = $data;
					$newPosition = $key - 1;
					unset($allData[$key]);
				}
			}
			
			if ($newPosition < 0)
				$newPosition = 0;
			
			if ($newPosition > count($allData))
				$newPosition = count($allData);
			
			$newPosition = intval($newPosition);
			
			$allData = array_values( $allData );
			
			$newSorting = array();
			$counter = 0;
			foreach ( $allData AS $key => $data )
			{
				
				/* Insert the item on new position in this helper array*/
				/*
				if ($key == $newPosition)
				{
					$newSorting[] = $temp;
				}
				$newSorting[] = $data;
				*/
				
				if ($key == $newPosition)
				{
					$this->Database->prepare("UPDATE tl_example SET sorting=? WHERE id=?")
											->execute( $counter , $temp['id']);
					$counter ++;
				}
				
				$this->Database->prepare("UPDATE tl_example SET sorting=? WHERE id=?")
											->execute( $counter, $data['id']);
				
				$counter ++;
			}
		
			$this->redirect($this->getReferer());
        }
		
		$dbObj = $this->Database->prepare("SELECT * FROM tl_example WHERE groupBy = ? ORDER BY sorting ASC")
				->execute( $row['groupBy'] );
		$anzObj = $dbObj->numRows;
		
		if ( $anzObj != NULL)
		{
			$counter = 0;
			while ($dbObj->next())
			{
				if ($dbObj->id == $row['id'] )
				{
					if ($counter == 0 )
					{
						/* First */
						return '<span>'.$this->generateImage('demagnify.gif', $label).'</span> ';
					}
					else
					{
						$href .= '&sortId='.$row['id'].'&groupBy='.$row['groupBy'].'&sortValue='.$row['sorting'];
						return '<a href="'.$this->addToUrl($href).'" title="'.specialchars($title).'"'.$attributes.'>'.$this->generateImage($icon, $label).'</a> ';
					}
				}
				$counter++;
			}
		}
				
	}
	
	public function sortingDown($row, $href, $label, $title, $icon, $attributes)
	{
		
		/* Redirect to module home after change position*/
		if ($this->Input->get('sortId') AND $this->Input->get('sorting') == "down" )
        {
			$thisId = $this->Input->get('sortId');
			$sortByGroup = $this->Input->get('groupBy');
			
			$dbObj = $this->Database->prepare("SELECT * FROM tl_example WHERE groupBy = ? ORDER BY sorting ASC")
				->execute( $sortByGroup );
			
			if ($dbObj->numRows == NULL)
				return false;
			
			$allData = $dbObj->fetchAllAssoc();
			#echo "<pre>";
			#var_dump($allData);
			/* Get all data from DB, save temp array, get new position and unset the array by key */
			foreach ( $allData AS $key => $data )
			{
				if ( $data['id'] == $thisId )
				{
					$temp = $data;
					$newPosition = $key + 1;
					unset($allData[$key]);
				}
			}
			
			if ($newPosition < 0)
				$newPosition = 0;
			
			if ($newPosition > count($allData))
				$newPosition = count($allData);
			
			$newPosition = intval($newPosition);
			
			$allData = array_values( $allData );
			
			#var_dump($newPosition);
			#exit;
			$newSorting = array();
			$counter = 0;
			foreach ( $allData AS $key => $data )
			{
				
				/* Insert the item on new position in this helper array*/
				/*
				if ($key == $newPosition)
				{
					$newSorting[] = $temp;
				}
				$newSorting[] = $data;
				*/
				if ($key == $newPosition)
				{
					$this->Database->prepare("UPDATE tl_example SET sorting=? WHERE id=?")
											->execute( $counter , $temp['id']);
					$counter ++;
				}
				
				
				$this->Database->prepare("UPDATE tl_example SET sorting=? WHERE id=?")
											->execute( $counter, $data['id']);
				
				$counter ++;
				
			}
		
			$this->redirect($this->getReferer());
        }
		
		
		/* Dont show first and last Arrow*/
		$dbObj = $this->Database->prepare("SELECT * FROM tl_example WHERE groupBy = ? ORDER BY sorting ASC")
				->execute( $row['groupBy'] );
		$anzObj = $dbObj->numRows;
		
		if ( $anzObj != NULL)
		{
			$counter = 0;
			while ($dbObj->next())
			{
				if ($dbObj->id == $row['id'] )
				{
					if ($counter == $anzObj-1 )
					{
						/* Last */
						return '<span>'.$this->generateImage('demagnify.gif', $label).'</span> ';
					}
					else
					{
						$href .= '&sortId='.$row['id'].'&groupBy='.$row['groupBy'].'&sortValue='.$row['sorting'];
						return '<a href="'.$this->addToUrl($href).'" title="'.specialchars($title).'"'.$attributes.'>'.$this->generateImage($icon, $label).'</a> ';
					}
				}
				$counter++;
			}
		}
				
	}

Das Ergebnis sieht dann so aus:

Das Script kann sicher optimiert werden, besonders die Bestimmung der neuen Position – wer möchte. Für mich erfüllt es seinen Zweck.

Contao 3.5

Zurück