public function edit($intId = null, $ajaxId = null)
{
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable']) {
throw new InternalServerErrorException('Table "' . $this->strTable . '" is not editable.');
}
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) {
throw new AccessDeniedException('Cannot load record "' . $this->strTable . '.id=' . $this->intId . '".');
}
$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 = \StringUtil::trimsplit(';', $this->strPalette);
$legends = array();
if (!empty($boxes)) {
foreach ($boxes as $k => $v) {
$eCount = 1;
$boxes[$k] = \StringUtil::trimsplit(',', $v);
foreach ($boxes[$k] as $kk => $vv) {
if (preg_match('/^\\[.*\\]$/', $vv)) {
++$eCount;
continue;
}
if (preg_match('/^\\{.*\\}$/', $vv)) {
$legends[$k] = substr($vv, 1, -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]);
}
}
/** @var SessionInterface $objSessionBag */
$objSessionBag = \System::getContainer()->get('session')->getBag('contao_backend');
$class = 'tl_tbox';
$fs = $objSessionBag->get('fieldset_states');
// Render boxes
foreach ($boxes as $k => $v) {
$arrAjax = array();
$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 .= "\n\n" . '<fieldset' . ($key ? ' id="pal_' . $key . '"' : '') . ' class="' . $class . ($legend ? '' : ' nolegend') . '">' . $legend;
$thisId = '';
// Build rows of the current box
foreach ($v as $vv) {
if ($vv == '[EOF]') {
if ($blnAjax && \Environment::get('isAjaxRequest')) {
if ($ajaxId == $thisId) {
return $arrAjax[$thisId] . '<input type="hidden" name="FORM_FIELDS[]" value="' . \StringUtil::specialchars($this->strPalette) . '">';
}
if (count($arrAjax) > 1) {
$current = "\n" . '<div id="' . $thisId . '">' . $arrAjax[$thisId] . '</div>';
unset($arrAjax[$thisId]);
end($arrAjax);
$thisId = key($arrAjax);
$arrAjax[$thisId] .= $current;
}
}
$return .= "\n" . '</div>';
continue;
}
if (preg_match('/^\\[.*\\]$/', $vv)) {
$thisId = 'sub_' . substr($vv, 1, -1);
$arrAjax[$thisId] = '';
$blnAjax = $ajaxId == $thisId && \Environment::get('isAjaxRequest') ? true : $blnAjax;
$return .= "\n" . '<div id="' . $thisId . '">';
continue;
}
$this->strField = $vv;
$this->strInputName = $vv;
$this->varValue = $objRow->{$vv};
// 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 = \StringUtil::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 ? $arrAjax[$thisId] .= $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'] = '<button type="submit" name="save" id="save" class="tl_submit" accesskey="s">' . $GLOBALS['TL_LANG']['MSC']['save'] . '</button>';
if (!\Input::get('nb')) {
$arrButtons['saveNclose'] = '<button type="submit" name="saveNclose" id="saveNclose" class="tl_submit" accesskey="c">' . $GLOBALS['TL_LANG']['MSC']['saveNclose'] . '</button>';
if (!\Input::get('nc')) {
if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) {
$arrButtons['saveNcreate'] = '<button type="submit" name="saveNcreate" id="saveNcreate" class="tl_submit" accesskey="n">' . $GLOBALS['TL_LANG']['MSC']['saveNcreate'] . '</button>';
$arrButtons['saveNduplicate'] = '<button type="submit" name="saveNduplicate" id="saveNduplicate" class="tl_submit" accesskey="d">' . $GLOBALS['TL_LANG']['MSC']['saveNduplicate'] . '</button>';
}
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['switchToEdit']) {
$arrButtons['saveNedit'] = '<button type="submit" name="saveNedit" id="saveNedit" class="tl_submit" accesskey="e">' . $GLOBALS['TL_LANG']['MSC']['saveNedit'] . '</button>';
}
if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4 || strlen($this->ptable) || $GLOBALS['TL_DCA'][$this->strTable]['config']['switchToEdit']) {
$arrButtons['saveNback'] = '<button type="submit" name="saveNback" id="saveNback" class="tl_submit" accesskey="g">' . $GLOBALS['TL_LANG']['MSC']['saveNback'] . '</button>';
}
}
}
// 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);
}
}
}
if (count($arrButtons) < 3) {
$strButtons = implode(' ', $arrButtons);
} else {
$strButtons = array_shift($arrButtons) . ' ';
$strButtons .= '<div class="split-button">';
$strButtons .= array_shift($arrButtons) . '<button type="button" id="sbtog">' . \Image::getHtml('navcol.svg') . '</button> <ul class="invisible">';
foreach ($arrButtons as $strButton) {
$strButtons .= '<li>' . $strButton . '</li>';
}
$strButtons .= '</ul></div>';
}
// Add the buttons and end the form
$return .= '
</div>
<div class="tl_formbody_submit">
<div class="tl_submit_container">
' . $strButtons . '
</div>
</div>
</form>';
// 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') ? ' ' : '
<a href="' . $this->getReferer(true) . '" class="header_back" title="' . \StringUtil::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="' . $this->strTable . '">
<input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">
<input type="hidden" name="FORM_FIELDS[]" value="' . \StringUtil::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($arrValues, time());
// 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->ptable, time(), $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', 0, 0);
$this->redirect($this->getReferer());
} elseif (isset($_POST['saveNedit'])) {
\Message::reset();
\System::setCookie('BE_PAGE_OFFSET', 0, 0);
$this->redirect($this->addToUrl($GLOBALS['TL_DCA'][$this->strTable]['list']['operations']['edit']['href'], false, array('s2e', 'act', 'mode', 'pid')));
} elseif (isset($_POST['saveNback'])) {
\Message::reset();
\System::setCookie('BE_PAGE_OFFSET', 0, 0);
if ($this->ptable == '') {
$this->redirect(TL_SCRIPT . '?do=' . \Input::get('do'));
} 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', 0, 0);
$strUrl = TL_SCRIPT . '?do=' . \Input::get('do');
if (isset($_GET['table'])) {
$strUrl .= '&table=' . \Input::get('table');
}
// Tree view
if ($this->treeView) {
$strUrl .= '&act=create&mode=1&pid=' . $this->intId;
} elseif ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) {
$strUrl .= $this->Database->fieldExists('sorting', $this->strTable) ? '&act=create&mode=1&pid=' . $this->intId : '&act=create&mode=2&pid=' . $this->activeRecord->pid;
} else {
$strUrl .= $this->ptable != '' ? '&act=create&mode=2&pid=' . CURRENT_ID : '&act=create';
}
$this->redirect($strUrl . '&rt=' . REQUEST_TOKEN);
} elseif (isset($_POST['saveNduplicate'])) {
\Message::reset();
\System::setCookie('BE_PAGE_OFFSET', 0, 0);
$strUrl = TL_SCRIPT . '?do=' . \Input::get('do');
if (isset($_GET['table'])) {
$strUrl .= '&table=' . \Input::get('table');
}
// Tree view
if ($this->treeView) {
$strUrl .= '&act=copy&mode=1&id=' . $this->intId . '&pid=' . $this->intId;
} elseif ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) {
$strUrl .= $this->Database->fieldExists('sorting', $this->strTable) ? '&act=copy&mode=1&pid=' . $this->intId . '&id=' . $this->intId : '&act=copy&mode=2&pid=' . $this->intId . '&id=' . $this->intId;
} else {
$strUrl .= $this->ptable != '' ? '&act=copy&mode=2&pid=' . CURRENT_ID . '&id=' . CURRENT_ID : '&act=copy&id=' . CURRENT_ID;
}
$this->redirect($strUrl . '&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;
}