Beispiel #1
0
    /**
     * 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($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]);
                }
            }
            $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 .= "\n\n" . '<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($vv, 1, -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'] == 4 || 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($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);
                $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', 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 .= '&amp;table=' . \Input::get('table');
                }
                // Tree view
                if ($this->treeView) {
                    $strUrl .= '&amp;act=create&amp;mode=1&amp;pid=' . $this->intId;
                } 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;
                } 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;
    }
Beispiel #2
0
 /**
  * Compare two versions of a Model object. Returns an array of properties
  * that have changed between the two versions, but does no comparison
  * of the changes themselves. Note that this looks at the data array
  * of the Model objects, not object properties, so it will not work
  * on ordinary objects, only Model-based objects and objects returned
  * by the `recent()` and `history()` methods.
  */
 public static function diff($obj1, $obj2)
 {
     if (get_class($obj1) === 'stdClass') {
         $v = new Versions();
         $obj1 = $v->restore($obj1);
     }
     if (get_class($obj2) === 'stdClass') {
         $v = new Versions();
         $obj2 = $v->restore($obj2);
     }
     // are there extended fields?
     $ext = is_subclass_of($obj2, 'ExtendedModel') ? $obj2->_extended_field : false;
     $changed = array();
     $obj1_orig = (array) $obj1->orig();
     $obj2_orig = (array) $obj2->orig();
     foreach ($obj1_orig as $key => $value) {
         if ($ext === $key) {
             // skip extended field
             continue;
         }
         if ($value !== $obj2_orig[$key]) {
             $changed[] = $key;
         }
     }
     return $changed;
 }
Beispiel #3
0
    /**
     * Load the source editor
     *
     * @return string
     */
    public function source()
    {
        $this->isValid($this->intId);
        if (is_dir(TL_ROOT . '/' . $this->intId)) {
            $this->log('Folder "' . $this->intId . '" cannot be edited', __METHOD__, TL_ERROR);
            $this->redirect('contao/main.php?act=error');
        } elseif (!file_exists(TL_ROOT . '/' . $this->intId)) {
            $this->log('File "' . $this->intId . '" does not exist', __METHOD__, TL_ERROR);
            $this->redirect('contao/main.php?act=error');
        }
        $this->import('BackendUser', 'User');
        // Check user permission
        if (!$this->User->hasAccess('f5', 'fop')) {
            $this->log('Not enough permissions to edit the file source of file "' . $this->intId . '"', __METHOD__, TL_ERROR);
            $this->redirect('contao/main.php?act=error');
        }
        $objFile = new \File($this->intId, true);
        // Check whether file type is editable
        if (!in_array($objFile->extension, trimsplit(',', strtolower(\Config::get('editableFiles'))))) {
            $this->log('File type "' . $objFile->extension . '" (' . $this->intId . ') is not allowed to be edited', __METHOD__, TL_ERROR);
            $this->redirect('contao/main.php?act=error');
        }
        $objMeta = null;
        $objVersions = null;
        // Add the versioning routines
        if ($this->blnIsDbAssisted && \Dbafs::shouldBeSynchronized($this->intId)) {
            $objMeta = \FilesModel::findByPath($objFile->value);
            if ($objMeta === null) {
                $objMeta = \Dbafs::addResource($objFile->value);
            }
            $objVersions = new \Versions($this->strTable, $objMeta->id);
            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'));
                    // Purge the script cache (see #7005)
                    if ($objFile->extension == 'css' || $objFile->extension == 'scss' || $objFile->extension == 'less') {
                        $this->import('Automator');
                        $this->Automator->purgeScriptCache();
                    }
                    $this->reload();
                }
            }
            $objVersions->initialize();
        }
        $strContent = $objFile->getContent();
        if ($objFile->extension == 'svgz') {
            $strContent = gzdecode($strContent);
        }
        // Process the request
        if (\Input::post('FORM_SUBMIT') == 'tl_files') {
            // Restore the basic entities (see #7170)
            $strSource = \StringUtil::restoreBasicEntities(\Input::postRaw('source'));
            // Save the file
            if (md5($strContent) != md5($strSource)) {
                if ($objFile->extension == 'svgz') {
                    $strSource = gzencode($strSource);
                }
                // Write the file
                $objFile->write($strSource);
                $objFile->close();
                // Update the database
                if ($this->blnIsDbAssisted && $objMeta !== null) {
                    /** @var \FilesModel $objMeta */
                    $objMeta->hash = $objFile->hash;
                    $objMeta->save();
                    $objVersions->create();
                }
                // Purge the script cache (see #7005)
                if ($objFile->extension == 'css' || $objFile->extension == 'scss' || $objFile->extension == 'less') {
                    $this->import('Automator');
                    $this->Automator->purgeScriptCache();
                }
            }
            if (\Input::post('saveNclose')) {
                \System::setCookie('BE_PAGE_OFFSET', 0, 0);
                $this->redirect($this->getReferer());
            }
            $this->reload();
        }
        $codeEditor = '';
        // Prepare the code editor
        if (\Config::get('useCE')) {
            $selector = 'ctrl_source';
            $type = $objFile->extension;
            // Load the code editor configuration
            ob_start();
            include TL_ROOT . '/system/config/ace.php';
            $codeEditor = ob_get_contents();
            ob_end_clean();
            unset($selector, $type);
        }
        // Versions overview
        if ($GLOBALS['TL_DCA'][$this->strTable]['config']['enableVersioning'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['hideVersionMenu'] && $this->blnIsDbAssisted && $objVersions !== null) {
            $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']) . '">';
        $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 $version . '
<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>
' . \Message::generate() . '
<form action="' . ampersand(\Environment::get('request'), true) . '" id="tl_files" class="tl_form" method="post">
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="tl_files">
<input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">
<div class="tl_tbox">
  <h3><label for="ctrl_source">' . $GLOBALS['TL_LANG']['tl_files']['editor'][0] . '</label></h3>
  <textarea name="source" id="ctrl_source" class="tl_textarea monospace" rows="12" cols="80" style="height:400px" onfocus="Backend.getScrollOffset()">' . "\n" . htmlspecialchars($strContent) . '</textarea>' . (\Config::get('showHelp') && strlen($GLOBALS['TL_LANG']['tl_files']['editor'][1]) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_files']['editor'][1] . '</p>' : '') . '
</div>
</div>

<div class="tl_formbody_submit">

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

</div>
</form>' . "\n\n" . $codeEditor;
    }
Beispiel #4
0
 * Restores a previous version of a Model object, replacing the
 * current version, and adding a new version to the history
 * as well.
 */
$page->layout = 'admin';
if (!User::require_admin()) {
    $this->redirect('/admin');
}
$ver = new Versions($_GET['id']);
$lock = new Lock($ver->class, $ver->pkey);
if ($lock->exists()) {
    $page->title = __('Editing Locked');
    echo $tpl->render('admin/locked', $lock->info());
    return;
} else {
    $lock->add();
}
$obj = $ver->restore();
$obj->put();
if ($obj->error) {
    $page->title = __('An Error Occurred');
    echo __('Error Message') . ': ' . $obj->error;
    return;
}
Versions::add($obj);
$this->add_notification(__('Item restored.'));
if ($ver->class == 'Webpage') {
    $cache->delete('_admin_page_' . $obj->id);
    $this->redirect('/' . $obj->id);
}
$this->redirect('/');
Beispiel #5
0
 /**
  * Compare two versions of a Model object. Returns an array of properties
  * that have changed between the two versions, but does no comparison
  * of the changes themselves. Note that this looks at the data array
  * of the Model objects, not object properties, so it will not work
  * on ordinary objects, only Model-based objects and objects returned
  * by the `recent()` and `history()` methods.
  */
 public static function diff($obj1, $obj2)
 {
     if (get_class($obj1) === 'stdClass') {
         $v = new Versions();
         $obj1 = $v->restore($obj1);
     }
     if (get_class($obj2) === 'stdClass') {
         $v = new Versions();
         $obj2 = $v->restore($obj2);
     }
     $changed = array();
     foreach ($obj1->data as $key => $value) {
         if ($value !== $obj2->data[$key]) {
             $changed[] = $key;
         }
     }
     return $changed;
 }
Beispiel #6
0
    Logger::error(i18n::s('You are not allowed to perform this operation.'));
    // not found
} elseif (!isset($item['id'])) {
    include '../error.php';
    // an anchor is mandatory
} elseif (!is_object($anchor)) {
    Safe::header('Status: 404 Not Found', TRUE, 404);
    Logger::error(i18n::s('No anchor has been found.'));
    // permission denied
} elseif (!$permitted) {
    // surfer has to be authenticated
    if (!Surfer::is_logged()) {
        Safe::redirect($context['url_to_home'] . $context['url_to_root'] . 'users/login.php?url=' . urlencode(Versions::get_url($item['id'], 'restore')));
    }
    // permission denied to authenticated user
    Safe::header('Status: 401 Unauthorized', TRUE, 401);
    Logger::error(i18n::s('You are not allowed to perform this operation.'));
    // restoration
} else {
    // update the database
    if (Versions::restore($item['id'])) {
        // provide some feed-back
        $context['text'] .= '<p>' . i18n::s('The page has been successfully restored.') . '</p>';
        // follow-up commands
        $context['text'] .= Skin::build_link($anchor->get_url(), i18n::s('Done'), 'button');
        // clear the cache; the article may be listed at many places
        Cache::clear();
    }
}
// render the skin
render_skin();
    /**
     * Auto-generate a form to edit the current database record
     * @param integer
     * @param integer
     * @return string
     */
    public function edit($intID = false, $ajaxId = false)
    {
        if ($GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable']) {
            \System::log('Table ' . $this->strTable . ' is not editable', __METHOD__, TL_ERROR);
            \Controller::redirect('contao/main.php?act=error');
        }
        if ($intID) {
            $this->intId = $intID;
        }
        // Get the current record
        $objRow = \Database::getInstance()->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) {
            \System::log('Could not load record "' . $this->strTable . '.id=' . $this->intId . '"', __METHOD__, TL_ERROR);
            \Controller::redirect('contao/main.php?act=error');
        } elseif ($objRow->language != '') {
            \System::log('Cannot edit language record "' . $this->strTable . '.id=' . $this->intId . '"', __METHOD__, TL_ERROR);
            \Controller::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);
        // 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();
        // Load and/or change language
        $this->blnEditLanguage = false;
        if (!empty($this->arrTranslations)) {
            $blnLanguageUpdated = false;
            $session = $this->Session->getData();
            if (\Input::post('FORM_SUBMIT') == 'tl_language') {
                if (in_array(\Input::post('language'), $this->arrTranslations)) {
                    $session['language'][$this->strTable][$this->intId] = \Input::post('language');
                } else {
                    unset($session['language'][$this->strTable][$this->intId]);
                }
                $blnLanguageUpdated = true;
            } elseif (\Input::post('FORM_SUBMIT') == $this->strTable && isset($_POST['deleteLanguage'])) {
                $this->Database->prepare("DELETE FROM {$this->strTable} WHERE pid=? AND language=?")->execute($this->intId, $session['language'][$this->strTable][$this->intId]);
                unset($session['language'][$this->strTable][$this->intId]);
                $blnLanguageUpdated = true;
            }
            if ($blnLanguageUpdated) {
                $this->Session->setData($session);
                $_SESSION['TL_INFO'] = '';
                \Controller::reload();
            }
            if ($_SESSION['BE_DATA']['language'][$this->strTable][$this->intId] != '' && in_array($_SESSION['BE_DATA']['language'][$this->strTable][$this->intId], $this->arrTranslations)) {
                $objRow = $this->Database->prepare("SELECT * FROM {$this->strTable} WHERE pid=? AND language=?")->execute($this->intId, $_SESSION['BE_DATA']['language'][$this->strTable][$this->intId]);
                if (!$objRow->numRows) {
                    $intId = $this->Database->prepare("INSERT INTO {$this->strTable} (pid,tstamp,language) VALUES (?,?,?)")->execute($this->intId, time(), $_SESSION['BE_DATA']['language'][$this->strTable][$this->intId])->insertId;
                    $objRow = $this->Database->prepare("SELECT * FROM {$this->strTable} WHERE id=?")->execute($intId);
                }
                $this->objActiveRecord = $objRow;
                $this->values = array($this->intId, $_SESSION['BE_DATA']['language'][$this->strTable][$this->intId]);
                $this->procedure = array('pid=?', 'language=?');
                $this->blnEditLanguage = true;
            }
        }
        // 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('/^\\[.*\\]$/i', $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]);
                    } elseif ($this->blnEditLanguage && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$vv]['attributes']['multilingual']) {
                        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 .= "\n\n" . '<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($vv, 1, -1);
                        $blnAjax = $ajaxId == $thisId && \Environment::get('isAjaxRequest') ? true : false;
                        $return .= "\n" . '<div id="' . $thisId . '">';
                        continue;
                    }
                    $this->strField = $vv;
                    $this->strInputName = $vv;
                    $this->varValue = $this->objActiveRecord->{$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 = call_user_func($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>';
            }
        }
        $version = '';
        // Versions overview
        if ($GLOBALS['TL_DCA'][$this->strTable]['config']['enableVersioning']) {
            $version = $objVersions->renderDropdown();
        }
        if ('' === $version) {
            $version = '<div class="tl_version_panel"></div>';
        }
        // Check languages
        if (!empty($this->arrTranslations)) {
            $arrAvailableLanguages = $this->Database->prepare("SELECT language FROM {$this->strTable} WHERE pid=?")->execute($this->intId)->fetchEach('language');
            $available = '';
            $undefined = '';
            foreach ($this->arrTranslations as $language) {
                if (in_array($language, $arrAvailableLanguages)) {
                    if ($_SESSION['BE_DATA']['language'][$this->strTable][$this->intId] == $language) {
                        $available .= '<option value="' . $language . '" selected="selected">' . $this->arrTranslationLabels[$language] . '</option>';
                        $_SESSION['TL_INFO'] = array($GLOBALS['TL_LANG']['MSC']['editingLanguage']);
                    } else {
                        $available .= '<option value="' . $language . '">' . $this->arrTranslationLabels[$language] . '</option>';
                    }
                } else {
                    $undefined .= '<option value="' . $language . '">' . $this->arrTranslationLabels[$language] . ' (' . $GLOBALS['TL_LANG']['MSC']['undefinedLanguage'] . ')' . '</option>';
                }
            }
            $version = str_replace('<div class="tl_version_panel">', '<div class="tl_version_panel tl_iso_products_panel">
<form action="' . ampersand(\Environment::get('request'), true) . '" id="tl_language" class="tl_form" method="post">
<div class="tl_formbody">
<input type="hidden" name="FORM_SUBMIT" value="tl_language">
<input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">
<select name="language" class="tl_select' . (strlen($_SESSION['BE_DATA']['language'][$this->strTable][$this->intId]) ? ' active' : '') . '" onchange="document.id(this).getParent(\'form\').submit()">
    <option value="">' . $GLOBALS['TL_LANG']['MSC']['defaultLanguage'] . '</option>' . $available . $undefined . '
</select>
<noscript>
<input type="submit" name="editLanguage" class="tl_submit" value="' . specialchars($GLOBALS['TL_LANG']['MSC']['editLanguage']) . '">
</noscript>
</div>
</form>', $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'] == 4 || 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']) . '">';
        }
        if ($this->blnEditLanguage) {
            $arrButtons['deleteLanguage'] = '<input type="submit" name="deleteLanguage" class="tl_submit" style="float:right" value="' . specialchars($GLOBALS['TL_LANG']['MSC']['deleteLanguage']) . '" onclick="return confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteLanguageConfirm'] . '\')">';
        }
        // 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>';
        $copyFallback = $this->blnEditLanguage ? '&nbsp;&nbsp;::&nbsp;&nbsp;<a href="' . \Backend::addToUrl('act=copyFallback') . '" class="header_iso_copy" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['copyFallback']) . '" accesskey="d" onclick="Backend.getScrollOffset();">' . ($GLOBALS['TL_LANG']['MSC']['copyFallback'] ? $GLOBALS['TL_LANG']['MSC']['copyFallback'] : 'copyFallback') . '</a>' : '';
        // 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="' . \System::getReferer(true) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a>') . $copyFallback . '
</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($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)) {
                        call_user_func($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'])) {
                    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->objActiveRecord->id, $this);
                        } elseif (is_callable($callback)) {
                            call_user_func($callback, $this->strTable, $this->objActiveRecord->id, $this);
                        }
                    }
                }
                \System::log('A new version of record "' . $this->strTable . '.id=' . $this->intId . '" has been created' . $this->getParentEntries($this->strTable, $this->intId), __METHOD__, TL_GENERAL);
            }
            // 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);
                \Controller::redirect(\System::getReferer());
            } elseif (isset($_POST['saveNedit'])) {
                \Message::reset();
                \System::setCookie('BE_PAGE_OFFSET', 0, 0);
                $strUrl = \Backend::addToUrl($GLOBALS['TL_DCA'][$this->strTable]['list']['operations']['edit']['href'], false);
                $strUrl = preg_replace('/(&amp;)?(s2e|act)=[^&]*/i', '', $strUrl);
                \Controller::redirect($strUrl);
            } elseif (isset($_POST['saveNback'])) {
                \Message::reset();
                \System::setCookie('BE_PAGE_OFFSET', 0, 0);
                if ($this->ptable == '') {
                    \Controller::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') {
                    \Controller::redirect(\System::getReferer(false, $this->strTable));
                } else {
                    \Controller::redirect(\System::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 .= '&amp;table=' . \Input::get('table');
                }
                // Tree view
                if ($this->treeView) {
                    $strUrl .= '&amp;act=create&amp;mode=1&amp;pid=' . $this->intId;
                } elseif ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4 || $this->activeRecord->pid > 0) {
                    $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;
                } else {
                    $strUrl .= $this->ptable != '' ? '&amp;act=create&amp;mode=2&amp;pid=' . CURRENT_ID : '&amp;act=create';
                }
                \Controller::redirect($strUrl . '&amp;rt=' . REQUEST_TOKEN);
            }
            \Controller::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;
    }
Beispiel #8
0
<?php

/**
 * Compares a previous version of a Model object to the
 * current version, allowing you to restore the previous
 * version if desired.
 */
$page->layout = 'admin';
if (!User::require_admin()) {
    $this->redirect('/admin');
}
$ver = new Versions($_GET['id']);
$old = $ver->restore();
$class = $ver->class;
$cur = new $class($ver->pkey);
if ($cur->error) {
    // deleted item
    foreach (json_decode($ver->serialized) as $key => $value) {
        $cur->{$key} = $value;
    }
}
$diff = Versions::diff($old, $cur);
$data = array();
foreach ((array) $cur->orig() as $key => $value) {
    $data[$key] = array('cur' => $value, 'old' => $old->{$key}, 'diff' => in_array($key, $diff) ? true : false);
}
$page->title = i18n_get('Comparing') . ' ' . $ver->class . ' / ' . $ver->pkey;
echo $tpl->render('admin/compare', array('fields' => $data, 'class' => $ver->class, 'pkey' => $ver->pkey, 'ts' => $ver->ts));