From 919c85d4134929726011f2fa20b5653f2b0a6c66 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 24 Mar 2011 21:18:01 +1300 Subject: [PATCH] MINOR Moved CMSBatchAction class to sapphire module, but keeping SiteTree specific subclasses in cms --- code/CMSBatchAction.php | 261 --------------------------------- code/CMSBatchActionHandler.php | 208 -------------------------- code/CMSBatchActions.php | 143 ++++++++++++++++++ 3 files changed, 143 insertions(+), 469 deletions(-) delete mode 100644 code/CMSBatchAction.php delete mode 100644 code/CMSBatchActionHandler.php create mode 100644 code/CMSBatchActions.php diff --git a/code/CMSBatchAction.php b/code/CMSBatchAction.php deleted file mode 100644 index 27e0454f..00000000 --- a/code/CMSBatchAction.php +++ /dev/null @@ -1,261 +0,0 @@ - - * CMSMain::register_batch_action('publishitems', new CMSBatchAction('doPublish', - * _t('CMSBatchActions.PUBLISHED_PAGES', 'published %d pages'))); - * - * - * @package cms - * @subpackage batchaction - */ -abstract class CMSBatchAction extends Object { - /** - * The the text to show in the dropdown for this action - */ - abstract function getActionTitle(); - - /** - * Run this action for the given set of pages. - * Return a set of status-updated JavaScript to return to the CMS. - */ - abstract function run(DataObjectSet $pages); - - /** - * Helper method for processing batch actions. - * Returns a set of status-updating JavaScript to return to the CMS. - * - * @param $pages The DataObjectSet of SiteTree objects to perform this batch action - * on. - * @param $helperMethod The method to call on each of those objects. - * @return JSON encoded map in the following format: - * { - * 'modified': { - * 3: {'TreeTitle': 'Page3'}, - * 5: {'TreeTitle': 'Page5'} - * }, - * 'deleted': { - * // all deleted pages - * } - * } - */ - public function batchaction(DataObjectSet $pages, $helperMethod, $successMessage, $arguments = array()) { - $status = array('modified' => array(), 'error' => array()); - - foreach($pages as $page) { - - // Perform the action - if (!call_user_func_array(array($page, $helperMethod), $arguments)) { - $status['error'][$page->ID] = ''; - } - - // Now make sure the tree title is appropriately updated - $publishedRecord = DataObject::get_by_id('SiteTree', $page->ID); - if ($publishedRecord) { - $status['modified'][$publishedRecord->ID] = array( - 'TreeTitle' => $publishedRecord->TreeTitle, - ); - } - $page->destroy(); - unset($page); - } - - $response = Controller::curr()->getResponse(); - if($response) { - $response->setStatusCode( - 200, - sprintf($successMessage, $pages->Count(), count($status['error'])) - ); - } - - return Convert::raw2json($status); - } - - - - /** - * Helper method for applicablePages() methods. Acts as a skeleton implementation. - * - * @param $ids The IDs passed to applicablePages - * @param $methodName The canXXX() method to call on each page to check if the action is applicable - * @param $checkStagePages Set to true if you want to check stage pages - * @param $checkLivePages Set to true if you want to check live pages (e.g, for deleted-from-draft) - */ - function applicablePagesHelper($ids, $methodName, $checkStagePages = true, $checkLivePages = true) { - if(!is_array($ids)) user_error("Bad \$ids passed to applicablePagesHelper()", E_USER_WARNING); - if(!is_string($methodName)) user_error("Bad \$methodName passed to applicablePagesHelper()", E_USER_WARNING); - - $applicableIDs = array(); - - $SQL_ids = implode(', ', array_filter($ids, 'is_numeric')); - $draftPages = DataObject::get("SiteTree", "\"SiteTree\".\"ID\" IN ($SQL_ids)"); - - $onlyOnLive = array_fill_keys($ids, true); - if($checkStagePages) { - foreach($draftPages as $page) { - unset($onlyOnLive[$page->ID]); - if($page->$methodName()) $applicableIDs[] = $page->ID; - } - } - - // Get the pages that only exist on live (deleted from stage) - if($checkLivePages && $onlyOnLive) { - $SQL_ids = implode(', ', array_keys($onlyOnLive)); - $livePages = Versioned::get_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" IN ($SQL_ids)"); - - if($livePages) foreach($livePages as $page) { - if($page->$methodName()) $applicableIDs[] = $page->ID; - } - } - - return $applicableIDs; - } - - - // if your batchaction has parameters, return a fieldset here - function getParameterFields() { - return false; - } - - /** - * If you wish to restrict the batch action to some users, overload this function. - */ - function canView() { - return true; - } -} - -/** - * Publish items batch action. - * - * @package cms - * @subpackage batchaction - */ -class CMSBatchAction_Publish extends CMSBatchAction { - function getActionTitle() { - return _t('CMSBatchActions.PUBLISH_PAGES', 'Publish'); - } - - function run(DataObjectSet $pages) { - return $this->batchaction($pages, 'doPublish', - _t('CMSBatchActions.PUBLISHED_PAGES', 'Published %d pages, %d failures') - ); - } - - function applicablePages($ids) { - return $this->applicablePagesHelper($ids, 'canPublish', true, false); - } -} - -/** - * Un-publish items batch action. - * - * @package cms - * @subpackage batchaction - */ -class CMSBatchAction_Unpublish extends CMSBatchAction { - function getActionTitle() { - return _t('CMSBatchActions.UNPUBLISH_PAGES', 'Un-publish'); - } - - function run(DataObjectSet $pages) { - return $this->batchaction($pages, 'doUnpublish', - _t('CMSBatchActions.UNPUBLISHED_PAGES', 'Un-published %d pages') - ); - } -} - -/** - * Delete items batch action. - * - * @package cms - * @subpackage batchaction - */ -class CMSBatchAction_Delete extends CMSBatchAction { - function getActionTitle() { - return _t('CMSBatchActions.DELETE_DRAFT_PAGES', 'Delete from draft site'); - } - - function run(DataObjectSet $pages) { - $status = array( - 'modified'=>array(), - 'deleted'=>array(), - 'error'=>array() - ); - - foreach($pages as $page) { - $id = $page->ID; - - // Perform the action - if($page->canDelete()) $page->delete(); - else $status['error'][$page->ID] = true; - - // check to see if the record exists on the live site, - // if it doesn't remove the tree node - $liveRecord = Versioned::get_one_by_stage( 'SiteTree', 'Live', "\"SiteTree\".\"ID\"=$id"); - if($liveRecord) { - $liveRecord->IsDeletedFromStage = true; - $status['modified'][$liveRecord->ID] = array( - 'TreeTitle' => $liveRecord->TreeTitle, - ); - } else { - $status['deleted'][$id] = array(); - } - - } - - return Convert::raw2json($status); - } - - function applicablePages($ids) { - return $this->applicablePagesHelper($ids, 'canDelete', true, false); - } -} - -/** - * Unpublish (delete from live site) items batch action. - * - * @package cms - * @subpackage batchaction - */ -class CMSBatchAction_DeleteFromLive extends CMSBatchAction { - function getActionTitle() { - return _t('CMSBatchActions.DELETE_PAGES', 'Delete from published site'); - } - - function run(DataObjectSet $pages) { - $status = array( - 'modified'=>array(), - 'deleted'=>array() - ); - - foreach($pages as $page) { - $id = $page->ID; - - // Perform the action - if($page->canDelete()) $page->doDeleteFromLive(); - - // check to see if the record exists on the stage site, if it doesn't remove the tree node - $stageRecord = Versioned::get_one_by_stage( 'SiteTree', 'Stage', "\"SiteTree\".\"ID\"=$id"); - if($stageRecord) { - $stageRecord->IsAddedToStage = true; - $status['modified'][$stageRecord->ID] = array( - 'TreeTitle' => $stageRecord->TreeTitle, - ); - } else { - $status['deleted'][$id] = array(); - } - - } - - return Convert::raw2json($status); - } - - function applicablePages($ids) { - return $this->applicablePagesHelper($ids, 'canDelete', false, true); - } -} \ No newline at end of file diff --git a/code/CMSBatchActionHandler.php b/code/CMSBatchActionHandler.php deleted file mode 100644 index 0cfb63dd..00000000 --- a/code/CMSBatchActionHandler.php +++ /dev/null @@ -1,208 +0,0 @@ - 'handleApplicablePages', - '$BatchAction/confirmation' => 'handleConfirmation', - '$BatchAction' => 'handleAction', - ); - - protected $parentController; - - /** - * @var String - */ - protected $urlSegment; - - /** - * @var String $recordClass The classname that should be affected - * by any batch changes. Needs to be set in the actual {@link CMSBatchAction} - * implementations as well. - */ - protected $recordClass = 'SiteTree'; - - /** - * Register a new batch action. Each batch action needs to be represented by a subclass - * of {@link CMSBatchAction}. - * - * @param $urlSegment The URL Segment of the batch action - the URL used to process this - * action will be admin/batchactions/(urlSegment) - * @param $batchActionClass The name of the CMSBatchAction subclass to register - */ - static function register($urlSegment, $batchActionClass, $recordClass = 'SiteTree') { - if(is_subclass_of($batchActionClass, 'CMSBatchAction')) { - self::$batch_actions[$urlSegment] = array( - 'class' => $batchActionClass, - 'recordClass' => $recordClass - ); - } else { - user_error("CMSBatchActionHandler::register() - Bad class '$batchActionClass'", E_USER_ERROR); - } - } - - /** - * @param string $parentController - * @param string $urlSegment - * @param string $recordClass - */ - function __construct($parentController, $urlSegment, $recordClass = null) { - $this->parentController = $parentController; - $this->urlSegment = $urlSegment; - if($recordClass) $this->recordClass = $recordClass; - - parent::__construct(); - } - - function Link() { - return Controller::join_links($this->parentController->Link(), $this->urlSegment); - } - - function handleAction($request) { - // This method can't be called without ajax. - if(!$this->parentController->isAjax()) { - $this->parentController->redirectBack(); - return; - } - - // Protect against CSRF on destructive action - if(!SecurityToken::inst()->checkRequest($request)) return $this->httpError(400); - - $actions = $this->batchActions(); - $actionClass = $actions[$request->param('BatchAction')]['class']; - $actionHandler = new $actionClass(); - - // Sanitise ID list and query the database for apges - $ids = split(' *, *', trim($request->requestVar('csvIDs'))); - foreach($ids as $k => $v) if(!is_numeric($v)) unset($ids[$k]); - - if($ids) { - if(class_exists('Translatable') && Object::has_extension('SiteTree','Translatable')) Translatable::disable_locale_filter(); - - $pages = DataObject::get( - $this->recordClass, - sprintf( - '"%s"."ID" IN (%s)', - ClassInfo::baseDataClass($this->recordClass), - implode(", ", $ids) - ) - ); - - if(class_exists('Translatable') && Object::has_extension('SiteTree','Translatable')) Translatable::enable_locale_filter(); - - if(Object::has_extension($this->recordClass, 'Versioned')) { - // If we didn't query all the pages, then find the rest on the live site - if(!$pages || $pages->Count() < sizeof($ids)) { - foreach($ids as $id) $idsFromLive[$id] = true; - if($pages) foreach($pages as $page) unset($idsFromLive[$page->ID]); - $idsFromLive = array_keys($idsFromLive); - - $sql = sprintf( - '"%s"."ID" IN (%s)', - $this->recordClass, - implode(", ", $idsFromLive) - ); - $livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql); - if($pages) $pages->merge($livePages); - else $pages = $livePages; - } - } - } else { - $pages = new DataObjectSet(); - } - - return $actionHandler->run($pages); - } - - function handleApplicablePages($request) { - // Find the action handler - $actions = Object::get_static($this->class, 'batch_actions'); - $actionClass = $actions[$request->param('BatchAction')]; - $actionHandler = new $actionClass['class'](); - - // Sanitise ID list and query the database for apges - $ids = split(' *, *', trim($request->requestVar('csvIDs'))); - foreach($ids as $k => $id) $ids[$k] = (int)$id; - $ids = array_filter($ids); - - if($actionHandler->hasMethod('applicablePages')) { - $applicableIDs = $actionHandler->applicablePages($ids); - } else { - $applicableIDs = $ids; - } - - $response = new SS_HTTPResponse(Convert::raw2json(array_values($applicableIDs))); - $response->addHeader("Content-type", "application/json"); - return $response; - } - - function handleConfirmation($request) { - // Find the action handler - $actions = Object::get_static($this->class, 'batch_actions'); - $actionClass = $actions[$request->param('BatchAction')]; - $actionHandler = new $actionClass(); - - // Sanitise ID list and query the database for apges - $ids = split(' *, *', trim($request->requestVar('csvIDs'))); - foreach($ids as $k => $id) $ids[$k] = (int)$id; - $ids = array_filter($ids); - - if($actionHandler->hasMethod('confirmationDialog')) { - $response = new SS_HTTPResponse(json_encode($actionHandler->confirmationDialog($ids))); - } else { - $response = new SS_HTTPResponse(json_encode(array('alert' => false))); - } - - $response->addHeader("Content-type", "application/json"); - return $response; - } - - /** - * Return a DataObjectSet of ArrayData objects containing the following pieces of info - * about each batch action: - * - Link - * - Title - */ - function batchActionList() { - $actions = $this->batchActions(); - $actionList = new DataObjectSet(); - - foreach($actions as $urlSegment => $action) { - $actionClass = $action['class']; - $actionObj = new $actionClass(); - if($actionObj->canView()) { - $actionDef = new ArrayData(array( - "Link" => Controller::join_links($this->Link(), $urlSegment), - "Title" => $actionObj->getActionTitle(), - )); - $actionList->push($actionDef); - } - } - - return $actionList; - } - - /** - * Get all registered actions through the static defaults set by {@link register()}. - * Filters for the currently set {@link recordClass}. - * - * @return array See {@link register()} for the returned format. - */ - function batchActions() { - $actions = Object::get_static($this->class, 'batch_actions'); - if($actions) foreach($actions as $action) { - if($action['recordClass'] != $this->recordClass) unset($action); - } - - return $actions; - } - -} \ No newline at end of file diff --git a/code/CMSBatchActions.php b/code/CMSBatchActions.php new file mode 100644 index 00000000..15549fe7 --- /dev/null +++ b/code/CMSBatchActions.php @@ -0,0 +1,143 @@ +batchaction($pages, 'doPublish', + _t('CMSBatchActions.PUBLISHED_PAGES', 'Published %d pages, %d failures') + ); + } + + function applicablePages($ids) { + return $this->applicablePagesHelper($ids, 'canPublish', true, false); + } +} + +/** + * Un-publish items batch action. + * + * @package cms + * @subpackage batchaction + */ +class CMSBatchAction_Unpublish extends CMSBatchAction { + function getActionTitle() { + return _t('CMSBatchActions.UNPUBLISH_PAGES', 'Un-publish'); + } + function getDoingText() { + return _t('CMSBatchActions.UNPUBLISHING_PAGES', 'Un-publishing selected pages'); + } + + function run(DataObjectSet $pages) { + return $this->batchaction($pages, 'doUnpublish', + _t('CMSBatchActions.UNPUBLISHED_PAGES', 'Un-published %d pages') + ); + } +} + +/** + * Delete items batch action. + * + * @package cms + * @subpackage batchaction + */ +class CMSBatchAction_Delete extends CMSBatchAction { + function getActionTitle() { + return _t('CMSBatchActions.DELETE_DRAFT_PAGES', 'Delete from draft site'); + } + function getDoingText() { + return _t('CMSBatchActions.DELETING_DRAFT_PAGES', 'Deleting selected pages from the draft site'); + } + + function run(DataObjectSet $pages) { + $status = array( + 'modified'=>array(), + 'deleted'=>array(), + 'error'=>array() + ); + + foreach($pages as $page) { + $id = $page->ID; + + // Perform the action + if($page->canDelete()) $page->delete(); + else $status['error'][$page->ID] = true; + + // check to see if the record exists on the live site, + // if it doesn't remove the tree node + $liveRecord = Versioned::get_one_by_stage( 'SiteTree', 'Live', "\"SiteTree\".\"ID\"=$id"); + if($liveRecord) { + $liveRecord->IsDeletedFromStage = true; + $status['modified'][$liveRecord->ID] = array( + 'TreeTitle' => $liveRecord->TreeTitle, + ); + } else { + $status['deleted'][$id] = array(); + } + + } + + return Convert::raw2json($status); + } + + function applicablePages($ids) { + return $this->applicablePagesHelper($ids, 'canDelete', true, false); + } +} + +/** + * Unpublish (delete from live site) items batch action. + * + * @package cms + * @subpackage batchaction + */ +class CMSBatchAction_DeleteFromLive extends CMSBatchAction { + function getActionTitle() { + return _t('CMSBatchActions.DELETE_PAGES', 'Delete from published site'); + } + function getDoingText() { + return _t('CMSBatchActions.DELETING_PAGES', 'Deleting selected pages from the published site'); + } + + function run(DataObjectSet $pages) { + $status = array( + 'modified'=>array(), + 'deleted'=>array() + ); + + foreach($pages as $page) { + $id = $page->ID; + + // Perform the action + if($page->canDelete()) $page->doDeleteFromLive(); + + // check to see if the record exists on the stage site, if it doesn't remove the tree node + $stageRecord = Versioned::get_one_by_stage( 'SiteTree', 'Stage', "\"SiteTree\".\"ID\"=$id"); + if($stageRecord) { + $stageRecord->IsAddedToStage = true; + $status['modified'][$stageRecord->ID] = array( + 'TreeTitle' => $stageRecord->TreeTitle, + ); + } else { + $status['deleted'][$id] = array(); + } + + } + + return Convert::raw2json($status); + } + + function applicablePages($ids) { + return $this->applicablePagesHelper($ids, 'canDelete', false, true); + } +} \ No newline at end of file