silverstripe-framework/admin/code/CMSBatchActionHandler.php
Damian Mooyman d8e9af8af8 API New Database abstraction layer. Ticket #7429
Database abstraction broken up into controller, connector, query builder, and schema manager, each independently configurable via YAML / Injector
Creation of new DBQueryGenerator for database specific generation of SQL
Support for parameterised queries, move of code base to use these over escaped conditions
Refactor of SQLQuery into separate query classes for each of INSERT UPDATE DELETE and SELECT
Support for PDO
Installation process upgraded to use new ORM
SS_DatabaseException created to handle database errors, maintaining details of raw sql and parameter details for user code designed interested in that data.
Renamed DB static methods to conform correctly to naming conventions (e.g. DB::getConn -> DB::get_conn)
3.2 upgrade docs
Performance Optimisation and simplification of code to use more concise API
API Ability for database adapters to register extensions to ConfigureFromEnv.php
2014-07-09 18:04:05 +12:00

215 lines
6.6 KiB
PHP

<?php
/**
* Special request handler for admin/batchaction
*
* @package framework
* @subpackage admin
*/
class CMSBatchActionHandler extends RequestHandler {
/** @config */
private static $batch_actions = array();
private static $url_handlers = array(
'$BatchAction/applicablepages' => 'handleApplicablePages',
'$BatchAction/confirmation' => 'handleConfirmation',
'$BatchAction' => 'handleBatchAction',
);
private static $allowed_actions = array(
'handleBatchAction',
'handleApplicablePages',
'handleConfirmation',
);
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
*/
public static function register($urlSegment, $batchActionClass, $recordClass = 'SiteTree') {
if(is_subclass_of($batchActionClass, 'CMSBatchAction')) {
Config::inst()->update('CMSBatchActionHandler', 'batch_actions',
array($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
*/
public function __construct($parentController, $urlSegment, $recordClass = null) {
$this->parentController = $parentController;
$this->urlSegment = $urlSegment;
if($recordClass) $this->recordClass = $recordClass;
parent::__construct();
}
public function Link() {
return Controller::join_links($this->parentController->Link(), $this->urlSegment);
}
public function handleBatchAction($request) {
// This method can't be called without ajax.
if(!$request->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 = preg_split('/ *, */', trim($request->requestVar('csvIDs')));
foreach($ids as $k => $v) if(!is_numeric($v)) unset($ids[$k]);
if($ids) {
if(class_exists('Translatable') && SiteTree::has_extension('Translatable')) {
Translatable::disable_locale_filter();
}
$recordClass = $this->recordClass;
$pages = DataObject::get($recordClass)->byIDs($ids);
if(class_exists('Translatable') && SiteTree::has_extension('Translatable')) {
Translatable::enable_locale_filter();
}
$record_class = $this->recordClass;
if($record_class::has_extension('Versioned')) {
// If we didn't query all the pages, then find the rest on the live site
if(!$pages || $pages->Count() < sizeof($ids)) {
$idsFromLive = array();
foreach($ids as $id) $idsFromLive[$id] = true;
if($pages) foreach($pages as $page) unset($idsFromLive[$page->ID]);
$idsFromLive = array_keys($idsFromLive);
$livePages = Versioned::get_by_stage($this->recordClass, 'Live')->byIDs($idsFromLive);
if($pages) {
// Can't merge into a DataList, need to condense into an actual list first
// (which will retrieve all records as objects, so its an expensive operation)
$pages = new ArrayList($pages->toArray());
$pages->merge($livePages);
} else {
$pages = $livePages;
}
}
}
} else {
$pages = new ArrayList();
}
return $actionHandler->run($pages);
}
public function handleApplicablePages($request) {
// Find the action handler
$actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
$actionClass = $actions[$request->param('BatchAction')];
$actionHandler = new $actionClass['class']();
// Sanitise ID list and query the database for apges
$ids = preg_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(json_encode($applicableIDs));
$response->addHeader("Content-type", "application/json");
return $response;
}
public function handleConfirmation($request) {
// Find the action handler
$actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
$actionClass = $actions[$request->param('BatchAction')];
$actionHandler = new $actionClass();
// Sanitise ID list and query the database for apges
$ids = preg_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 SS_List of ArrayData objects containing the following pieces of info
* about each batch action:
* - Link
* - Title
*/
public function batchActionList() {
$actions = $this->batchActions();
$actionList = new ArrayList();
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.
*/
public function batchActions() {
$actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
if($actions) foreach($actions as $action) {
if($action['recordClass'] != $this->recordClass) unset($action);
}
return $actions;
}
}