2011-08-19 02:32:31 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @package cms
|
|
|
|
* @subpackage controllers
|
|
|
|
*/
|
|
|
|
class CMSPageHistoryController extends CMSMain {
|
|
|
|
|
|
|
|
static $url_segment = 'page/history';
|
|
|
|
static $url_rule = '/$Action/$ID/$VersionID/$OtherVersionID';
|
|
|
|
static $url_priority = 42;
|
|
|
|
static $menu_title = 'History';
|
|
|
|
|
|
|
|
static $allowed_actions = array(
|
|
|
|
'VersionsForm',
|
|
|
|
'compare'
|
|
|
|
);
|
|
|
|
|
|
|
|
public static $url_handlers = array(
|
|
|
|
'$Action/$ID/$VersionID/$OtherVersionID' => 'handleAction'
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
2011-08-26 04:03:21 +02:00
|
|
|
* @return array
|
2011-08-19 02:32:31 +02:00
|
|
|
*/
|
2011-09-19 21:06:39 +02:00
|
|
|
function show($request) {
|
|
|
|
$form = $this->ShowVersionForm(
|
|
|
|
$request->param('VersionID')
|
2011-08-19 02:32:31 +02:00
|
|
|
);
|
2011-09-19 21:06:39 +02:00
|
|
|
if($this->isAjax()) {
|
|
|
|
$content = $form->forTemplate();
|
|
|
|
} else {
|
|
|
|
$content = $this->customise(array('EditForm' => $form))->renderWith($this->getViewer('show'));
|
|
|
|
}
|
|
|
|
return $content;
|
2011-08-19 02:32:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-08-26 04:03:21 +02:00
|
|
|
* @return array
|
2011-08-19 02:32:31 +02:00
|
|
|
*/
|
2011-09-19 21:06:39 +02:00
|
|
|
function compare($request) {
|
|
|
|
$form = $this->CompareVersionsForm(
|
|
|
|
$request->param('VersionID'),
|
|
|
|
$request->param('OtherVersionID')
|
2011-08-19 02:32:31 +02:00
|
|
|
);
|
2011-09-19 21:06:39 +02:00
|
|
|
if($this->isAjax()) {
|
|
|
|
$content = $form->forTemplate();
|
|
|
|
} else {
|
|
|
|
$content = $this->customise(array('EditForm' => $form))->renderWith($this->getViewer('show'));
|
|
|
|
}
|
|
|
|
return $content;
|
2011-08-19 02:32:31 +02:00
|
|
|
}
|
2011-08-30 00:26:40 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
function rollback() {
|
|
|
|
return $this->doRollback(array(
|
|
|
|
'ID' => $this->currentPageID(),
|
|
|
|
'Version' => $this->request->param('VersionID')
|
|
|
|
), null);
|
|
|
|
}
|
2011-08-26 04:03:21 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
/**
|
2011-08-26 04:03:21 +02:00
|
|
|
* Returns the read only version of the edit form. Detaches all {@link FormAction}
|
2011-08-19 02:32:31 +02:00
|
|
|
* instances attached since only action relates to revert.
|
|
|
|
*
|
|
|
|
* Permission checking is done at the {@link CMSMain::getEditForm()} level.
|
|
|
|
*
|
|
|
|
* @param int $id ID of the record to show
|
|
|
|
* @param array $fields optional
|
|
|
|
* @param int $versionID
|
2011-08-26 04:03:21 +02:00
|
|
|
* @param int $compare Compare mode
|
|
|
|
*
|
|
|
|
* @return Form
|
2011-08-19 02:32:31 +02:00
|
|
|
*/
|
2011-08-26 04:03:21 +02:00
|
|
|
function getEditForm($id = null, $fields = null, $versionID = null, $compareID = null) {
|
|
|
|
if(!$id) $id = $this->currentPageID();
|
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
$record = $this->getRecord($id, $versionID);
|
2011-08-26 04:03:21 +02:00
|
|
|
$versionID = ($record) ? $record->Version : $versionID;
|
2011-08-19 02:32:31 +02:00
|
|
|
|
|
|
|
$form = parent::getEditForm($record, ($record) ? $record->getCMSFields() : null);
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
$form->setActions(new FieldSet(
|
2011-08-30 02:36:02 +02:00
|
|
|
$revert = new FormAction('doRollback', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version'))
|
2011-08-26 04:03:21 +02:00
|
|
|
));
|
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
$fields = $form->Fields();
|
|
|
|
$fields->removeByName("Status");
|
|
|
|
$fields->push(new HiddenField("ID"));
|
|
|
|
$fields->push(new HiddenField("Version"));
|
|
|
|
|
|
|
|
$fields = $fields->makeReadonly();
|
2011-08-26 04:03:21 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
foreach($fields->dataFields() as $field) {
|
|
|
|
$field->dontEscape = true;
|
2011-08-26 04:03:21 +02:00
|
|
|
$field->reserveNL = true;
|
2011-08-19 02:32:31 +02:00
|
|
|
}
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
if($compareID) {
|
2011-08-30 00:26:40 +02:00
|
|
|
$link = Controller::join_links(
|
2011-09-19 21:06:39 +02:00
|
|
|
$this->Link('show'),
|
2011-08-30 00:26:40 +02:00
|
|
|
$id
|
|
|
|
);
|
|
|
|
|
|
|
|
$view = _t('CMSPageHistoryController.VIEW',"view");
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
$message = sprintf(
|
|
|
|
_t('CMSPageHistoryController.COMPARINGVERSION',"Comparing versions %s and %s."),
|
|
|
|
sprintf('%s (<a href="%s">%s</a>)', $versionID, Controller::join_links($link, $versionID), $view),
|
|
|
|
sprintf('%s (<a href="%s">%s</a>)', $compareID, Controller::join_links($link, $compareID), $view)
|
|
|
|
);
|
|
|
|
|
|
|
|
$revert->setReadonly(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$message = sprintf(
|
2011-08-30 00:26:40 +02:00
|
|
|
_t('CMSPageHistoryController.VIEWINGVERSION',"Currently viewing version %s."), $versionID
|
2011-08-26 04:03:21 +02:00
|
|
|
);
|
|
|
|
}
|
2011-08-19 02:32:31 +02:00
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
$fields->addFieldToTab('Root.Main',
|
|
|
|
new LiteralField('CurrentlyViewingMessage', $this->customise(array(
|
|
|
|
'Content' => $message,
|
|
|
|
'Classes' => 'notice'
|
|
|
|
))->renderWith(array('CMSMain_notice'))),
|
|
|
|
"Title"
|
|
|
|
);
|
|
|
|
|
|
|
|
$form->setFields($fields->makeReadonly());
|
2011-08-19 02:32:31 +02:00
|
|
|
$form->loadDataFrom(array(
|
|
|
|
"ID" => $id,
|
|
|
|
"Version" => $versionID,
|
|
|
|
));
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
if(($record && $record->isLatestVersion())) {
|
|
|
|
$revert->setReadonly(true);
|
|
|
|
}
|
2011-08-19 02:32:31 +02:00
|
|
|
|
|
|
|
$form->removeExtraClass('cms-content');
|
|
|
|
|
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
/**
|
2011-08-26 04:03:21 +02:00
|
|
|
* Version select form. Main interface between selecting versions to view
|
|
|
|
* and comparing multiple versions.
|
|
|
|
*
|
|
|
|
* Because we can reload the page directly to a compare view (history/compare/1/2/3)
|
|
|
|
* this form has to adapt to those parameters as well.
|
|
|
|
*
|
2011-08-19 02:32:31 +02:00
|
|
|
* @return Form
|
|
|
|
*/
|
|
|
|
function VersionsForm() {
|
|
|
|
$id = $this->currentPageID();
|
|
|
|
$page = $this->getRecord($id);
|
|
|
|
$versionsHtml = '';
|
|
|
|
|
2011-08-26 04:03:21 +02:00
|
|
|
$action = $this->request->param('Action');
|
|
|
|
$versionID = $this->request->param('VersionID');
|
|
|
|
$otherVersionID = $this->request->param('OtherVersionID');
|
|
|
|
|
|
|
|
$showUnpublishedChecked = 0;
|
|
|
|
$compareModeChecked = ($action == "compare");
|
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
if($page) {
|
|
|
|
$versions = $page->allVersions();
|
2011-08-30 02:36:02 +02:00
|
|
|
$versionID = (!$versionID) ? $page->Version : $versionID;
|
2011-08-30 04:33:03 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
if($versions) {
|
|
|
|
foreach($versions as $k => $version) {
|
2011-08-26 04:03:21 +02:00
|
|
|
$active = false;
|
|
|
|
|
|
|
|
if($version->Version == $versionID || $version->Version == $otherVersionID) {
|
|
|
|
$active = true;
|
|
|
|
|
2011-08-30 04:33:03 +02:00
|
|
|
if(!$version->WasPublished) $showUnpublishedChecked = 1;
|
2011-08-26 04:03:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$version->Active = ($active);
|
2011-08-19 02:32:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$vd = new ViewableData();
|
|
|
|
|
|
|
|
$versionsHtml = $vd->customise(array(
|
|
|
|
'Versions' => $versions
|
|
|
|
))->renderWith('CMSPageHistoryController_versions');
|
|
|
|
}
|
2011-08-26 04:03:21 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
$form = new Form(
|
|
|
|
$this,
|
|
|
|
'VersionsForm',
|
|
|
|
new FieldSet(
|
|
|
|
new CheckboxField(
|
|
|
|
'ShowUnpublished',
|
2011-08-26 04:03:21 +02:00
|
|
|
_t('CMSPageHistoryController.SHOWUNPUBLISHED','Show unpublished versions'),
|
|
|
|
$showUnpublishedChecked
|
2011-08-19 02:32:31 +02:00
|
|
|
),
|
|
|
|
new CheckboxField(
|
|
|
|
'CompareMode',
|
2011-09-02 01:18:43 +02:00
|
|
|
_t('CMSPageHistoryController.COMPAREMODE', 'Compare mode (select two)'),
|
2011-08-26 04:03:21 +02:00
|
|
|
$compareModeChecked
|
2011-08-19 02:32:31 +02:00
|
|
|
),
|
|
|
|
new LiteralField('VersionsHtml', $versionsHtml),
|
2011-08-30 00:26:40 +02:00
|
|
|
$hiddenID = new HiddenField('ID', false, "")
|
2011-08-19 02:32:31 +02:00
|
|
|
),
|
|
|
|
new FieldSet(
|
|
|
|
new FormAction(
|
|
|
|
'doCompare', _t('CMSPageHistoryController.COMPAREVERSIONS','Compare Versions')
|
|
|
|
),
|
|
|
|
new FormAction(
|
|
|
|
'doShowVersion', _t('CMSPageHistoryController.SHOWVERSION','Show Version')
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$form->loadDataFrom($this->request->requestVars());
|
2011-08-30 00:26:40 +02:00
|
|
|
$hiddenID->setValue($id);
|
2011-08-19 02:32:31 +02:00
|
|
|
$form->unsetValidator();
|
|
|
|
|
2011-09-19 21:34:46 +02:00
|
|
|
$form->addExtraClass('cms-versions-form'); // placeholder, necessary for $.metadata() to work
|
|
|
|
$form->addExtraClass(Convert::raw2json(array(
|
|
|
|
'link-tmpl-compare' => Controller::join_links($this->Link('compare'), '%s', '%s', '%s'),
|
|
|
|
'link-tmpl-show' => Controller::join_links($this->Link('show'), '%s', '%s'),
|
|
|
|
)));
|
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the {@link VersionsForm} compare function between two pages.
|
|
|
|
*
|
|
|
|
* @param array
|
|
|
|
* @param Form
|
|
|
|
*
|
|
|
|
* @return html
|
|
|
|
*/
|
|
|
|
function doCompare($data, $form) {
|
|
|
|
$versions = $data['Versions'];
|
|
|
|
if(count($versions) < 2) return null;
|
|
|
|
|
|
|
|
$id = $this->currentPageID();
|
|
|
|
$version1 = array_shift($versions);
|
|
|
|
$version2 = array_shift($versions);
|
|
|
|
|
|
|
|
$form = $this->CompareVersionsForm($version1, $version2);
|
|
|
|
|
|
|
|
// javascript solution, render into template
|
|
|
|
if($this->isAjax()) {
|
|
|
|
return $this->customise(array(
|
|
|
|
"EditForm" => $form
|
|
|
|
))->renderWith(array(
|
|
|
|
$this->class . '_EditForm',
|
|
|
|
'LeftAndMain_Content'
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
// non javascript, redirect the user to the page
|
|
|
|
$this->redirect(Controller::join_links(
|
|
|
|
$this->Link('compare'),
|
|
|
|
$version1,
|
|
|
|
$version2
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the {@link VersionsForm} show version function. Only requires
|
|
|
|
* one page to be selected.
|
|
|
|
*
|
|
|
|
* @param array
|
|
|
|
* @param Form
|
|
|
|
*
|
|
|
|
* @return html
|
|
|
|
*/
|
|
|
|
function doShowVersion($data, $form) {
|
|
|
|
$versionID = null;
|
|
|
|
|
|
|
|
if(isset($data['Versions']) && is_array($data['Versions'])) {
|
|
|
|
$versionID = array_shift($data['Versions']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$versionID) return;
|
|
|
|
|
|
|
|
if($this->isAjax()) {
|
|
|
|
return $this->customise(array(
|
|
|
|
"EditForm" => $this->ShowVersionForm($versionID)
|
|
|
|
))->renderWith(array(
|
|
|
|
$this->class . '_EditForm',
|
|
|
|
'LeftAndMain_Content'
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
// non javascript, redirect the user to the page
|
|
|
|
$this->redirect(Controller::join_links(
|
|
|
|
$this->Link('version'),
|
|
|
|
$versionID
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rolls a site back to a given version ID
|
|
|
|
*
|
|
|
|
* @param array
|
|
|
|
* @param Form
|
|
|
|
*
|
|
|
|
* @return html
|
|
|
|
*/
|
|
|
|
function doRollback($data, $form) {
|
2011-08-30 00:26:40 +02:00
|
|
|
$this->extend('onBeforeRollback', $data['ID']);
|
2011-08-30 02:36:02 +02:00
|
|
|
|
2011-08-30 00:26:40 +02:00
|
|
|
$id = (isset($data['ID'])) ? (int) $data['ID'] : null;
|
|
|
|
$version = (isset($data['Version'])) ? (int) $data['Version'] : null;
|
|
|
|
|
|
|
|
if(isset($data['Version']) && (bool)$data['Version']) {
|
|
|
|
$record = $this->performRollback($data['ID'], $data['Version']);
|
|
|
|
$message = sprintf(
|
|
|
|
_t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"),
|
|
|
|
$data['Version'],
|
|
|
|
$record->Version
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$record = $this->performRollback($data['ID'], "Live");
|
|
|
|
$message = sprintf(
|
|
|
|
_t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"),
|
|
|
|
$record->Version
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->isAjax()) {
|
|
|
|
$this->response->addHeader('X-Status', $message);
|
|
|
|
$form = $this->getEditForm($record->ID);
|
|
|
|
|
|
|
|
return $form->forTemplate();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array(
|
|
|
|
'EditForm' => $this->customise(array(
|
|
|
|
'Message' => $message,
|
|
|
|
'Status' => 'success'
|
|
|
|
))->renderWith('CMSMain_notice')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs a rollback of the a given
|
|
|
|
*
|
|
|
|
* @param int $id record ID
|
|
|
|
* @param int $version version ID to rollback to
|
|
|
|
*/
|
|
|
|
function performRollback($id, $version) {
|
|
|
|
$record = DataObject::get_by_id($this->stat('tree_class'), $id);
|
|
|
|
|
|
|
|
if($record && !$record->canEdit()) return Security::permissionFailure($this);
|
|
|
|
|
|
|
|
$record->doRollbackTo($version);
|
|
|
|
|
|
|
|
return $record;
|
2011-08-19 02:32:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Form
|
|
|
|
*/
|
|
|
|
function ShowVersionForm($versionID = null) {
|
|
|
|
if(!$versionID) return null;
|
2011-08-26 04:03:21 +02:00
|
|
|
|
2011-08-19 02:32:31 +02:00
|
|
|
$id = $this->currentPageID();
|
|
|
|
$form = $this->getEditForm($id, null, $versionID);
|
|
|
|
|
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Form
|
|
|
|
*/
|
|
|
|
function CompareVersionsForm($versionID, $otherVersionID) {
|
|
|
|
if($versionID > $otherVersionID) {
|
|
|
|
$toVersion = $versionID;
|
|
|
|
$fromVersion = $otherVersionID;
|
|
|
|
} else {
|
|
|
|
$toVersion = $otherVersionID;
|
|
|
|
$fromVersion = $versionID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$toVersion || !$toVersion) return false;
|
|
|
|
|
|
|
|
$id = $this->currentPageID();
|
|
|
|
$page = DataObject::get_by_id("SiteTree", $id);
|
|
|
|
|
|
|
|
if($page && !$page->canView()) {
|
|
|
|
return Security::permissionFailure($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
$record = $page->compareVersions($fromVersion, $toVersion);
|
|
|
|
|
|
|
|
$fromVersionRecord = Versioned::get_version('SiteTree', $id, $fromVersion);
|
|
|
|
$toVersionRecord = Versioned::get_version('SiteTree', $id, $toVersion);
|
|
|
|
|
|
|
|
if(!$fromVersionRecord) {
|
|
|
|
user_error("Can't find version $fromVersion of page $id", E_USER_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$toVersionRecord) {
|
|
|
|
user_error("Can't find version $toVersion of page $id", E_USER_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($record) {
|
2011-08-26 04:03:21 +02:00
|
|
|
$form = $this->getEditForm($id, null, null, true);
|
2011-08-19 02:32:31 +02:00
|
|
|
$form->setActions(new FieldSet());
|
2011-10-07 12:07:46 +02:00
|
|
|
$form->addExtraClass('compare');
|
|
|
|
|
|
|
|
// Comparison views shouldn't be editable.
|
|
|
|
// Its important to convert fields *before* loading data,
|
|
|
|
// as the comparison output is HTML and not valid values for the various field types
|
|
|
|
$readonlyFields = $form->Fields()->makeReadonly();
|
|
|
|
$form->setFields($readonlyFields);
|
2011-08-19 02:32:31 +02:00
|
|
|
|
2011-10-07 12:07:46 +02:00
|
|
|
$form->loadDataFrom($record);
|
2011-08-19 02:32:31 +02:00
|
|
|
$form->loadDataFrom(array(
|
|
|
|
"ID" => $id,
|
|
|
|
"Version" => $fromVersion,
|
|
|
|
));
|
|
|
|
|
2011-10-07 12:07:46 +02:00
|
|
|
foreach($form->Fields()->dataFields() as $field) {
|
|
|
|
$field->dontEscape = true;
|
|
|
|
}
|
2011-08-19 02:32:31 +02:00
|
|
|
|
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|