core-bundle/src/Resources/contao/classes/Backend.php
protected function getBackendModule($module, PickerInterface $picker = null)
	{
		$arrModule = array();

		foreach ($GLOBALS['BE_MOD'] as &$arrGroup)
		{
			if (isset($arrGroup[$module]))
			{
				$arrModule = &$arrGroup[$module];
				break;
			}
		}

		unset($arrGroup);

		$this->import(BackendUser::class, 'User');
		$blnAccess = (isset($arrModule['disablePermissionChecks']) && $arrModule['disablePermissionChecks'] === true) || $this->User->hasAccess($module, 'modules');

		// Check whether the current user has access to the current module
		if (!$blnAccess)
		{
			throw new AccessDeniedException('Back end module "' . $module . '" is not allowed for user "' . $this->User->username . '".');
		}

		// The module does not exist
		if (empty($arrModule))
		{
			throw new \InvalidArgumentException('Back end module "' . $module . '" is not defined in the BE_MOD array');
		}

		/** @var Session $objSession */
		$objSession = System::getContainer()->get('session');

		$arrTables = (array) $arrModule['tables'];
		$strTable = Input::get('table') ?: $arrTables[0];
		$id = (!Input::get('act') && Input::get('id')) ? Input::get('id') : $objSession->get('CURRENT_ID');

		// Store the current ID in the current session
		if ($id != $objSession->get('CURRENT_ID'))
		{
			$objSession->set('CURRENT_ID', $id);
		}

		\define('CURRENT_ID', (Input::get('table') ? $id : Input::get('id')));
		$this->Template->headline = $GLOBALS['TL_LANG']['MOD'][$module][0];

		// Add the module style sheet
		if (isset($arrModule['stylesheet']))
		{
			foreach ((array) $arrModule['stylesheet'] as $stylesheet)
			{
				$GLOBALS['TL_CSS'][] = $stylesheet;
			}
		}

		// Add module javascript
		if (isset($arrModule['javascript']))
		{
			foreach ((array) $arrModule['javascript'] as $javascript)
			{
				$GLOBALS['TL_JAVASCRIPT'][] = $javascript;
			}
		}

		$dc = null;

		// Create the data container object
		if ($strTable != '')
		{
			if (!\in_array($strTable, $arrTables))
			{
				throw new AccessDeniedException('Table "' . $strTable . '" is not allowed in module "' . $module . '".');
			}

			// Load the language and DCA file
			System::loadLanguageFile($strTable);
			$this->loadDataContainer($strTable);

			// Include all excluded fields which are allowed for the current user
			if ($GLOBALS['TL_DCA'][$strTable]['fields'])
			{
				foreach ($GLOBALS['TL_DCA'][$strTable]['fields'] as $k=>$v)
				{
					if ($v['exclude'])
					{
						if ($this->User->hasAccess($strTable.'::'.$k, 'alexf'))
						{
							if ($strTable == 'tl_user_group')
							{
								$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['orig_exclude'] = $GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'];
							}

							$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'] = false;
						}
					}
				}
			}

			// Fabricate a new data container object
			if ($GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'] == '')
			{
				$this->log('Missing data container for table "' . $strTable . '"', __METHOD__, TL_ERROR);
				trigger_error('Could not create a data container object', E_USER_ERROR);
			}

			$dataContainer = 'DC_' . $GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'];

			/** @var DataContainer $dc */
			$dc = new $dataContainer($strTable, $arrModule);

			if ($picker !== null && $dc instanceof DataContainer)
			{
				$dc->initPicker($picker);
			}
		}

		// Wrap the existing headline
		$this->Template->headline = '<span>' . $this->Template->headline . '</span>';

		// AJAX request
		if ($_POST && Environment::get('isAjaxRequest'))
		{
			$this->objAjax->executePostActions($dc);
		}

		// Trigger the module callback
		elseif (class_exists($arrModule['callback']))
		{
			/** @var Module $objCallback */
			$objCallback = new $arrModule['callback']($dc);

			$this->Template->main .= $objCallback->generate();
		}

		// Custom action (if key is not defined in config.php the default action will be called)
		elseif (Input::get('key') && isset($arrModule[Input::get('key')]))
		{
			$objCallback = System::importStatic($arrModule[Input::get('key')][0]);
			$response = $objCallback->{$arrModule[Input::get('key')][1]}($dc);

			if ($response instanceof RedirectResponse)
			{
				throw new ResponseException($response);
			}
			elseif ($response instanceof Response)
			{
				$response = $response->getContent();
			}

			$this->Template->main .= $response;

			// Add the name of the parent element
			if (isset($_GET['table']) && !empty($GLOBALS['TL_DCA'][$strTable]['config']['ptable']) && \in_array(Input::get('table'), $arrTables) && Input::get('table') != $arrTables[0])
			{
				$objRow = $this->Database->prepare("SELECT * FROM " . $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] . " WHERE id=(SELECT pid FROM $strTable WHERE id=?)")
										 ->limit(1)
										 ->execute(Input::get('id'));

				if ($objRow->title != '')
				{
					$this->Template->headline .= ' › <span>' . $objRow->title . '</span>';
				}
				elseif ($objRow->name != '')
				{
					$this->Template->headline .= ' › <span>' . $objRow->name . '</span>';
				}
			}

			// Add the name of the submodule
			$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][Input::get('key')][1], Input::get('id')) . '</span>';
		}

		// Default action
		elseif (\is_object($dc))
		{
			$act = Input::get('act');

			if ($act == '' || $act == 'paste' || $act == 'select')
			{
				$act = ($dc instanceof \listable) ? 'showAll' : 'edit';
			}

			switch ($act)
			{
				case 'delete':
				case 'show':
				case 'showAll':
				case 'undo':
					if (!$dc instanceof \listable)
					{
						$this->log('Data container ' . $strTable . ' is not listable', __METHOD__, TL_ERROR);
						trigger_error('The current data container is not listable', E_USER_ERROR);
					}
					break;

				case 'create':
				case 'cut':
				case 'cutAll':
				case 'copy':
				case 'copyAll':
				case 'move':
				case 'edit':
					if (!$dc instanceof \editable)
					{
						$this->log('Data container ' . $strTable . ' is not editable', __METHOD__, TL_ERROR);
						trigger_error('The current data container is not editable', E_USER_ERROR);
					}
					break;
			}

			// Add the name of the parent elements
			if ($strTable && \in_array($strTable, $arrTables) && $strTable != $arrTables[0])
			{
				$trail = array();

				$pid = $dc->id;
				$table = $strTable;
				$ptable = (Input::get('act') != 'edit') ? $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] : $strTable;

				while ($ptable && !\in_array($GLOBALS['TL_DCA'][$table]['list']['sorting']['mode'], array(5, 6)))
				{
					$objRow = $this->Database->prepare("SELECT * FROM " . $ptable . " WHERE id=?")
											 ->limit(1)
											 ->execute($pid);

					// Add only parent tables to the trail
					if ($table != $ptable)
					{
						// Add table name
						if (isset($GLOBALS['TL_LANG']['MOD'][$table]))
						{
							$trail[] = ' › <span>'. $GLOBALS['TL_LANG']['MOD'][$table] . '</span>';
						}

						// Add object title or name
						if ($objRow->title != '')
						{
							$trail[] = ' › <span>' . $objRow->title . '</span>';
						}
						elseif ($objRow->name != '')
						{
							$trail[] = ' › <span>' . $objRow->name . '</span>';
						}
						elseif ($objRow->headline != '')
						{
							$trail[] = ' › <span>' . $objRow->headline . '</span>';
						}

					}

					$this->loadDataContainer($ptable);

					// Next parent table
					$pid = $objRow->pid;
					$table = $ptable;
					$ptable = ($GLOBALS['TL_DCA'][$ptable]['config']['dynamicPtable']) ? $objRow->ptable : $GLOBALS['TL_DCA'][$ptable]['config']['ptable'];
				}

				// Add the last parent table
				if (isset($GLOBALS['TL_LANG']['MOD'][$table]))
				{
					$trail[] = ' › <span>'. $GLOBALS['TL_LANG']['MOD'][$table] . '</span>';
				}

				// Add the breadcrumb trail in reverse order
				foreach (array_reverse($trail) as $breadcrumb)
				{
					$this->Template->headline .= $breadcrumb;
				}
			}

			// Add the current action
			if (Input::get('act') == 'editAll')
			{
				if (isset($GLOBALS['TL_LANG']['MSC']['all'][0]))
				{
					$this->Template->headline .= ' › <span>' . $GLOBALS['TL_LANG']['MSC']['all'][0] . '</span>';
				}
			}
			elseif (Input::get('act') == 'overrideAll')
			{
				if (isset($GLOBALS['TL_LANG']['MSC']['all_override'][0]))
				{
					$this->Template->headline .= ' › <span>' . $GLOBALS['TL_LANG']['MSC']['all_override'][0] . '</span>';
				}
			}
			else
			{
				if (Input::get('id'))
				{
					if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
					{
						// Handle new folders (see #7980)
						if (strpos(Input::get('id'), '__new__') !== false)
						{
							$this->Template->headline .= ' › <span>' . \dirname(Input::get('id')) . '</span> › <span>' . $GLOBALS['TL_LANG'][$strTable]['new'][1] . '</span>';
						}
						else
						{
							$this->Template->headline .= ' › <span>' . Input::get('id') . '</span>';
						}
					}
					elseif (isset($GLOBALS['TL_LANG'][$strTable][$act][1]))
					{
						$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('id')) . '</span>';
					}
				}
				elseif (Input::get('pid'))
				{
					if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
					{
						if (Input::get('act') == 'move')
						{
							$this->Template->headline .= ' › <span>' . Input::get('pid') . '</span> › <span>' . $GLOBALS['TL_LANG'][$strTable]['move'][1] . '</span>';
						}
						else
						{
							$this->Template->headline .= ' › <span>' . Input::get('pid') . '</span>';
						}
					}
					elseif (isset($GLOBALS['TL_LANG'][$strTable][$act][1]))
					{
						$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('pid')) . '</span>';
					}
				}
			}

			return $dc->$act();
		}

		return null;
	}
protected function getBackendModule($module, PickerInterface $picker = null)
	{
		$arrModule = array();

		foreach ($GLOBALS['BE_MOD'] as &$arrGroup)
		{
			if (isset($arrGroup[$module]))
			{
				$arrModule = &$arrGroup[$module];
				break;
			}
		}

		unset($arrGroup);

		$this->import(BackendUser::class, 'User');
		$blnAccess = (isset($arrModule['disablePermissionChecks']) && $arrModule['disablePermissionChecks'] === true) || $this->User->hasAccess($module, 'modules');

		// Check whether the current user has access to the current module
		if (!$blnAccess)
		{
			throw new AccessDeniedException('Back end module "' . $module . '" is not allowed for user "' . $this->User->username . '".');
		}

		// The module does not exist
		if (empty($arrModule))
		{
			throw new \InvalidArgumentException('Back end module "' . $module . '" is not defined in the BE_MOD array');
		}

		/** @var Session $objSession */
		$objSession = System::getContainer()->get('session');

		$arrTables = (array) $arrModule['tables'];
		$strTable = Input::get('table') ?: $arrTables[0];
		$id = (!Input::get('act') && Input::get('id')) ? Input::get('id') : $objSession->get('CURRENT_ID');

		// Store the current ID in the current session
		if ($id != $objSession->get('CURRENT_ID'))
		{
			$objSession->set('CURRENT_ID', $id);
		}

		\define('CURRENT_ID', (Input::get('table') ? $id : Input::get('id')));
		$this->Template->headline = $GLOBALS['TL_LANG']['MOD'][$module][0];

		// Add the module style sheet
		if (isset($arrModule['stylesheet']))
		{
			foreach ((array) $arrModule['stylesheet'] as $stylesheet)
			{
				$GLOBALS['TL_CSS'][] = $stylesheet;
			}
		}

		// Add module javascript
		if (isset($arrModule['javascript']))
		{
			foreach ((array) $arrModule['javascript'] as $javascript)
			{
				$GLOBALS['TL_JAVASCRIPT'][] = $javascript;
			}
		}

		$dc = null;

		// Create the data container object
		if ($strTable != '')
		{
			if (!\in_array($strTable, $arrTables))
			{
				throw new AccessDeniedException('Table "' . $strTable . '" is not allowed in module "' . $module . '".');
			}

			// Load the language and DCA file
			System::loadLanguageFile($strTable);
			$this->loadDataContainer($strTable);

			// Include all excluded fields which are allowed for the current user
			if ($GLOBALS['TL_DCA'][$strTable]['fields'])
			{
				foreach ($GLOBALS['TL_DCA'][$strTable]['fields'] as $k=>$v)
				{
					if ($v['exclude'])
					{
						if ($this->User->hasAccess($strTable.'::'.$k, 'alexf'))
						{
							if ($strTable == 'tl_user_group')
							{
								$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['orig_exclude'] = $GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'];
							}

							$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'] = false;
						}
					}
				}
			}

			// Fabricate a new data container object
			if ($GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'] == '')
			{
				$this->log('Missing data container for table "' . $strTable . '"', __METHOD__, TL_ERROR);
				trigger_error('Could not create a data container object', E_USER_ERROR);
			}

			$dataContainer = 'DC_' . $GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'];

			/** @var DataContainer $dc */
			$dc = new $dataContainer($strTable, $arrModule);

			if ($picker !== null && $dc instanceof DataContainer)
			{
				$dc->initPicker($picker);
			}
		}

		// Wrap the existing headline
		$this->Template->headline = '<span>' . $this->Template->headline . '</span>';

		// AJAX request
		if ($_POST && Environment::get('isAjaxRequest'))
		{
			$this->objAjax->executePostActions($dc);
		}

		// Trigger the module callback
		elseif (class_exists($arrModule['callback']))
		{
			/** @var Module $objCallback */
			$objCallback = new $arrModule['callback']($dc);

			$this->Template->main .= $objCallback->generate();
		}

		// Custom action (if key is not defined in config.php the default action will be called)
		elseif (Input::get('key') && isset($arrModule[Input::get('key')]))
		{
			$objCallback = System::importStatic($arrModule[Input::get('key')][0]);
			$response = $objCallback->{$arrModule[Input::get('key')][1]}($dc);

			if ($response instanceof RedirectResponse)
			{
				throw new ResponseException($response);
			}
			elseif ($response instanceof Response)
			{
				$response = $response->getContent();
			}

			$this->Template->main .= $response;

			// Add the name of the parent element
			if (isset($_GET['table']) && !empty($GLOBALS['TL_DCA'][$strTable]['config']['ptable']) && \in_array(Input::get('table'), $arrTables) && Input::get('table') != $arrTables[0])
			{
				$objRow = $this->Database->prepare("SELECT * FROM " . $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] . " WHERE id=(SELECT pid FROM $strTable WHERE id=?)")
										 ->limit(1)
										 ->execute(Input::get('id'));

				if ($objRow->title != '')
				{
					$this->Template->headline .= ' › <span>' . $objRow->title . '</span>';
				}
				elseif ($objRow->name != '')
				{
					$this->Template->headline .= ' › <span>' . $objRow->name . '</span>';
				}
			}

			// Add the name of the submodule
			$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][Input::get('key')][1], Input::get('id')) . '</span>';
		}

		// Default action
		elseif (\is_object($dc))
		{
			$act = Input::get('act');

			if ($act == '' || $act == 'paste' || $act == 'select')
			{
				$act = ($dc instanceof \listable) ? 'showAll' : 'edit';
			}

			switch ($act)
			{
				case 'delete':
				case 'show':
				case 'showAll':
				case 'undo':
					if (!$dc instanceof \listable)
					{
						$this->log('Data container ' . $strTable . ' is not listable', __METHOD__, TL_ERROR);
						trigger_error('The current data container is not listable', E_USER_ERROR);
					}
					break;

				case 'create':
				case 'cut':
				case 'cutAll':
				case 'copy':
				case 'copyAll':
				case 'move':
				case 'edit':
					if (!$dc instanceof \editable)
					{
						$this->log('Data container ' . $strTable . ' is not editable', __METHOD__, TL_ERROR);
						trigger_error('The current data container is not editable', E_USER_ERROR);
					}
					break;
			}

			// Add the name of the parent elements
			if ($strTable && \in_array($strTable, $arrTables) && $strTable != $arrTables[0])
			{
				$trail = array();

				$pid = $dc->id;
				$table = $strTable;
				$ptable = (Input::get('act') != 'edit') ? $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] : $strTable;

				while ($ptable && !\in_array($GLOBALS['TL_DCA'][$table]['list']['sorting']['mode'], array(5, 6)))
				{
					$objRow = $this->Database->prepare("SELECT * FROM " . $ptable . " WHERE id=?")
											 ->limit(1)
											 ->execute($pid);

					// Add only parent tables to the trail
					if ($table != $ptable)
					{
						// Add table name
						if (isset($GLOBALS['TL_LANG']['MOD'][$table]))
						{
							$trail[] = ' › <span>'. $GLOBALS['TL_LANG']['MOD'][$table] . '</span>';
						}

						// Add object title or name
						if ($objRow->title != '')
						{
							$trail[] = ' › <span>' . $objRow->title . '</span>';
						}
						elseif ($objRow->name != '')
						{
							$trail[] = ' › <span>' . $objRow->name . '</span>';
						}
						elseif ($objRow->headline != '')
						{
							$trail[] = ' › <span>' . $objRow->headline . '</span>';
						}

					}

					$this->loadDataContainer($ptable);

					// Next parent table
					$pid = $objRow->pid;
					$table = $ptable;
					$ptable = ($GLOBALS['TL_DCA'][$ptable]['config']['dynamicPtable']) ? $objRow->ptable : $GLOBALS['TL_DCA'][$ptable]['config']['ptable'];
				}

				// Add the last parent table
				if (isset($GLOBALS['TL_LANG']['MOD'][$table]))
				{
					$trail[] = ' › <span>'. $GLOBALS['TL_LANG']['MOD'][$table] . '</span>';
				}

				// Add the breadcrumb trail in reverse order
				foreach (array_reverse($trail) as $breadcrumb)
				{
					$this->Template->headline .= $breadcrumb;
				}
			}

			// Add the current action
			if (Input::get('act') == 'editAll')
			{
				if (isset($GLOBALS['TL_LANG']['MSC']['all'][0]))
				{
					$this->Template->headline .= ' › <span>' . $GLOBALS['TL_LANG']['MSC']['all'][0] . '</span>';
				}
			}
			elseif (Input::get('act') == 'overrideAll')
			{
				if (isset($GLOBALS['TL_LANG']['MSC']['all_override'][0]))
				{
					$this->Template->headline .= ' › <span>' . $GLOBALS['TL_LANG']['MSC']['all_override'][0] . '</span>';
				}
			}
			else
			{
				if (Input::get('id'))
				{
					if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
					{
						// Handle new folders (see #7980)
						if (strpos(Input::get('id'), '__new__') !== false)
						{
							$this->Template->headline .= ' › <span>' . \dirname(Input::get('id')) . '</span> › <span>' . $GLOBALS['TL_LANG'][$strTable]['new'][1] . '</span>';
						}
						else
						{
							$this->Template->headline .= ' › <span>' . Input::get('id') . '</span>';
						}
					}
					elseif (isset($GLOBALS['TL_LANG'][$strTable][$act][1]))
					{
						$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('id')) . '</span>';
					}
				}
				elseif (Input::get('pid'))
				{
					if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
					{
						if (Input::get('act') == 'move')
						{
							$this->Template->headline .= ' › <span>' . Input::get('pid') . '</span> › <span>' . $GLOBALS['TL_LANG'][$strTable]['move'][1] . '</span>';
						}
						else
						{
							$this->Template->headline .= ' › <span>' . Input::get('pid') . '</span>';
						}
					}
					elseif (isset($GLOBALS['TL_LANG'][$strTable][$act][1]))
					{
						$this->Template->headline .= ' › <span>' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('pid')) . '</span>';
					}
				}
			}

			return $dc->$act();
		}

		return null;
	}
Open a back end module and return it as HTML

@param string               $module
@param PickerInterface|null $picker

@return string

@throws AccessDeniedException