silverstripe-cms/code/Controllers/CMSPageHistoryController.php

472 lines
14 KiB
PHP
Raw Normal View History

<?php
2016-07-22 01:32:32 +02:00
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Admin\LeftAndMainFormRequestHandler;
2016-08-10 06:08:39 +02:00
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller;
2016-09-09 01:26:24 +02:00
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\HTMLReadonlyField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\Tab;
2016-08-10 06:08:39 +02:00
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Security\Security;
2016-10-12 04:09:59 +02:00
use SilverStripe\View\ArrayData;
use SilverStripe\View\ViewableData;
/**
* Legacy CMS History controller. This functionality has been moved to the `silverstripe/versioned-admin` module and
* this class will be removed completly in SilverStripe 5.0.0.
* @deprecated 4.3.0:5.0.0
*/
2017-01-25 21:59:25 +01:00
class CMSPageHistoryController extends CMSMain
{
private static $url_segment = 'pages/history';
private static $url_rule = '/$Action/$ID/$VersionID/$OtherVersionID';
private static $url_priority = 42;
private static $menu_title = 'History';
private static $required_permission_codes = 'CMS_ACCESS_CMSMain';
private static $allowed_actions = array(
'EditForm',
2017-01-25 21:59:25 +01:00
'VersionsForm',
'CompareVersionsForm',
'show',
'compare'
);
private static $url_handlers = array(
'$Action/$ID/$VersionID/$OtherVersionID' => 'handleAction',
'EditForm/$ID/$VersionID' => 'EditForm',
2017-01-25 21:59:25 +01:00
);
/**
* Current version ID for this request. Can be 0 for latest version
*
* @var int
*/
protected $versionID = null;
2017-01-25 21:59:25 +01:00
public function getResponseNegotiator()
{
$negotiator = parent::getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () {
$form = $this->getEditForm();
2017-01-25 21:59:25 +01:00
if ($form) {
return $form->forTemplate();
}
return $this->renderWith($this->getTemplatesWithSuffix('_Content'));
2017-01-25 21:59:25 +01:00
});
$negotiator->setCallback('default', function () {
return $this->renderWith($this->getViewer('show'));
2017-01-25 21:59:25 +01:00
});
2017-01-25 21:59:25 +01:00
return $negotiator;
}
/**
* @param HTTPRequest $request
* @return HTTPResponse
2017-01-25 21:59:25 +01:00
*/
public function show($request)
{
// Record id and version for this request
$id = $request->param('ID');
$this->setCurrentPageID($id);
$versionID = $request->param('VersionID');
$this->setVersionID($versionID);
// Show id
$form = $this->getEditForm();
2017-01-25 21:59:25 +01:00
$negotiator = $this->getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () use ($form) {
return $form
? $form->forTemplate()
: $this->renderWith($this->getTemplatesWithSuffix('_Content'));
2017-01-25 21:59:25 +01:00
});
$negotiator->setCallback('default', function () use ($form) {
return $this
->customise(array('EditForm' => $form))
->renderWith($this->getViewer('show'));
2017-01-25 21:59:25 +01:00
});
return $negotiator->respond($request);
}
/**
* @param HTTPRequest $request
* @return HTTPResponse
2017-01-25 21:59:25 +01:00
*/
public function compare($request)
{
$form = $this->CompareVersionsForm(
$request->param('VersionID'),
$request->param('OtherVersionID')
);
$negotiator = $this->getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () use ($form) {
return $form ? $form->forTemplate() : $this->renderWith($this->getTemplatesWithSuffix('_Content'));
2017-01-25 21:59:25 +01:00
});
$negotiator->setCallback('default', function () use ($form) {
return $this->customise(array('EditForm' => $form))->renderWith($this->getViewer('show'));
2017-01-25 21:59:25 +01:00
});
return $negotiator->respond($request);
}
public function getSilverStripeNavigator()
{
$record = $this->getRecord($this->currentPageID(), $this->getRequest()->param('VersionID'));
if ($record) {
$navigator = new SilverStripeNavigator($record);
return $navigator->renderWith($this->getTemplatesWithSuffix('_SilverStripeNavigator'));
} else {
return false;
}
}
/**
* @param HTTPRequest $request
* @return Form
*/
public function EditForm($request = null)
{
if ($request) {
// Validate VersionID is present
$versionID = $request->param('VersionID');
if (!isset($versionID)) {
$this->httpError(400);
return null;
}
$this->setVersionID($versionID);
}
return parent::EditForm($request);
}
2017-01-25 21:59:25 +01:00
/**
* Returns the read only version of the edit form. Detaches all {@link FormAction}
* 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
* @param int $compareID Compare mode
*
* @return Form
*/
public function getEditForm($id = null, $fields = null, $versionID = null, $compareID = null)
{
if (!$id) {
$id = $this->currentPageID();
}
if (!$versionID) {
$versionID = $this->getVersionID();
}
2017-01-25 21:59:25 +01:00
$record = $this->getRecord($id, $versionID);
if (!$record) {
return $this->EmptyForm();
}
// Refresh version ID
$versionID = $record->Version;
$this->setVersionID($versionID);
2017-01-25 21:59:25 +01:00
// Get edit form
$form = parent::getEditForm($record, $record->getCMSFields());
2017-01-25 21:59:25 +01:00
// Respect permission failures from parent implementation
if (!($form instanceof Form)) {
return $form;
}
// TODO: move to the SilverStripeNavigator structure so the new preview can pick it up.
//$nav = new SilverStripeNavigatorItem_ArchiveLink($record);
$actions = new FieldList(
$revert = FormAction::create(
'doRollback',
2017-04-20 03:15:29 +02:00
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')
2017-09-11 06:26:16 +02:00
)
->setUseButtonTag(true)
->addExtraClass('btn-warning font-icon-back-in-time')
);
$actions->setForm($form);
$form->setActions($actions);
2017-01-25 21:59:25 +01:00
$fields = $form->Fields();
$fields->removeByName("Status");
$fields->push(new HiddenField("ID"));
$fields->push(new HiddenField("Version"));
$fields = $fields->makeReadonly();
if ($compareID) {
$link = Controller::join_links(
$this->Link('show'),
$id
);
$view = _t(__CLASS__ . '.VIEW', "view");
2017-01-25 21:59:25 +01:00
$message = _t(
__CLASS__ . '.COMPARINGVERSION',
2017-01-25 21:59:25 +01:00
"Comparing versions {version1} and {version2}.",
array(
'version1' => sprintf('%s (<a href="%s">%s</a>)', $versionID, Controller::join_links($link, $versionID), $view),
'version2' => sprintf('%s (<a href="%s">%s</a>)', $compareID, Controller::join_links($link, $compareID), $view)
)
);
$revert->setReadonly(true);
} else {
if ($record->isLatestVersion()) {
$message = _t(__CLASS__ . '.VIEWINGLATEST', 'Currently viewing the latest version.');
2017-01-25 21:59:25 +01:00
} else {
$message = _t(
__CLASS__ . '.VIEWINGVERSION',
2017-01-25 21:59:25 +01:00
"Currently viewing version {version}.",
array('version' => $versionID)
);
}
}
2016-03-08 21:50:55 +01:00
/** @var Tab $mainTab */
$mainTab = $fields->fieldByName('Root.Main');
$mainTab->unshift(
LiteralField::create('CurrentlyViewingMessage', ArrayData::create(array(
'Content' => DBField::create_field('HTMLFragment', $message),
'Classes' => 'alert alert-info'
))->renderWith($this->getTemplatesWithSuffix('_notice')))
);
2017-01-25 21:59:25 +01:00
$form->setFields($fields->makeReadonly());
$form->loadDataFrom(array(
"ID" => $id,
"Version" => $versionID,
));
if ($record->isLatestVersion()) {
2017-01-25 21:59:25 +01:00
$revert->setReadonly(true);
}
$form->removeExtraClass('cms-content');
// History form has both ID and VersionID as suffixes
$form->setRequestHandler(
LeftAndMainFormRequestHandler::create($form, [$id, $versionID])
);
2017-01-25 21:59:25 +01:00
return $form;
}
/**
* 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.
*
* @return Form
*/
public function VersionsForm()
{
$id = $this->currentPageID();
$page = $this->getRecord($id);
$versionsHtml = '';
$action = $this->getRequest()->param('Action');
$versionID = $this->getRequest()->param('VersionID');
$otherVersionID = $this->getRequest()->param('OtherVersionID');
$showUnpublishedChecked = 0;
$compareModeChecked = ($action == "compare");
if ($page) {
$versions = $page->allVersions();
$versionID = (!$versionID) ? $page->Version : $versionID;
if ($versions) {
foreach ($versions as $k => $version) {
$active = false;
if ($version->Version == $versionID || $version->Version == $otherVersionID) {
$active = true;
if (!$version->WasPublished) {
$showUnpublishedChecked = 1;
}
}
$version->Active = ($active);
}
}
$vd = new ViewableData();
$versionsHtml = $vd->customise(array(
'Versions' => $versions
))->renderWith($this->getTemplatesWithSuffix('_versions'));
}
$fields = new FieldList(
new CheckboxField(
'ShowUnpublished',
2017-04-20 03:15:29 +02:00
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.SHOWUNPUBLISHED', 'Show unpublished versions'),
2017-01-25 21:59:25 +01:00
$showUnpublishedChecked
),
new CheckboxField(
'CompareMode',
2017-04-20 03:15:29 +02:00
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.COMPAREMODE', 'Compare mode (select two)'),
2017-01-25 21:59:25 +01:00
$compareModeChecked
),
new LiteralField('VersionsHtml', $versionsHtml),
$hiddenID = new HiddenField('ID', false, "")
);
$form = Form::create(
$this,
'VersionsForm',
$fields,
new FieldList()
2017-01-25 21:59:25 +01:00
)->setHTMLID('Form_VersionsForm');
$form->loadDataFrom($this->getRequest()->requestVars());
$hiddenID->setValue($id);
$form->unsetValidator();
$form
->addExtraClass('cms-versions-form') // placeholder, necessary for $.metadata() to work
->setAttribute('data-link-tmpl-compare', Controller::join_links($this->Link('compare'), '%s', '%s', '%s'))
->setAttribute('data-link-tmpl-show', Controller::join_links($this->Link('show'), '%s', '%s'));
return $form;
}
/**
* @param int $versionID
* @param int $otherVersionID
* @return mixed
*/
public function CompareVersionsForm($versionID, $otherVersionID)
{
if ($versionID > $otherVersionID) {
$toVersion = $versionID;
$fromVersion = $otherVersionID;
} else {
$toVersion = $otherVersionID;
$fromVersion = $versionID;
}
if (!$toVersion || !$fromVersion) {
return null;
}
$id = $this->currentPageID();
/** @var SiteTree $page */
$page = SiteTree::get()->byID($id);
$record = null;
if ($page && $page->exists()) {
if (!$page->canView()) {
return Security::permissionFailure($this);
}
$record = $page->compareVersions($fromVersion, $toVersion);
}
$fromVersionRecord = Versioned::get_version(SiteTree::class, $id, $fromVersion);
$toVersionRecord = Versioned::get_version(SiteTree::class, $id, $toVersion);
2017-01-25 21:59:25 +01:00
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) {
return null;
}
$form = $this->getEditForm($id, null, $fromVersion, $toVersion);
$form->setActions(new FieldList());
$form->addExtraClass('compare');
$form->loadDataFrom($record);
$form->loadDataFrom(array(
"ID" => $id,
"Version" => $fromVersion,
));
2017-02-28 04:34:46 +01:00
// Comparison views shouldn't be editable.
// As the comparison output is HTML and not valid values for the various field types
$readonlyFields = $this->transformReadonly($form->Fields());
$form->setFields($readonlyFields);
2017-02-28 04:34:46 +01:00
2017-01-25 21:59:25 +01:00
return $form;
}
2017-02-28 04:34:46 +01:00
/**
* Replace all data fields with HTML readonly fields to display diff
*
* @param FieldList $fields
* @return FieldList
*/
public function transformReadonly(FieldList $fields)
{
2017-02-28 04:34:46 +01:00
foreach ($fields->dataFields() as $field) {
if ($field instanceof HiddenField) {
continue;
}
2017-02-28 04:34:46 +01:00
$newField = $field->castedCopy(HTMLReadonlyField::class);
$fields->replaceField($field->getName(), $newField);
}
return $fields;
}
/**
* Set current version ID
*
* @param int $versionID
* @return $this
*/
public function setVersionID($versionID)
{
$this->versionID = $versionID;
return $this;
}
/**
* Get current version ID
*
* @return int
*/
public function getVersionID()
{
return $this->versionID;
}
public function getTabIdentifier()
{
return 'history';
}
}