/**
  * Out of the box, the handler "CurrentForm" value, which will return the rendered form.
  * Non-Ajax calls will redirect back.
  *
  * @param HTTPRequest $request
  * @param array $extraCallbacks List of anonymous functions or callables returning either a string
  * or HTTPResponse, keyed by their fragment identifier. The 'default' key can
  * be used as a fallback for non-ajax responses.
  * @return HTTPResponse
  * @throws HTTPResponse_Exception
  */
 public function respond(HTTPRequest $request, $extraCallbacks = array())
 {
     // Prepare the default options and combine with the others
     $callbacks = array_merge($this->callbacks, $extraCallbacks);
     $response = $this->getResponse();
     $responseParts = array();
     if (isset($this->fragmentOverride)) {
         $fragments = $this->fragmentOverride;
     } elseif ($fragmentStr = $request->getHeader('X-Pjax')) {
         $fragments = explode(',', $fragmentStr);
     } else {
         if ($request->isAjax()) {
             throw new HTTPResponse_Exception("Ajax requests to this URL require an X-Pjax header.", 400);
         } elseif (empty($callbacks['default'])) {
             throw new HTTPResponse_Exception("Missing default response handler for this URL", 400);
         }
         $response->setBody(call_user_func($callbacks['default']));
         return $response;
     }
     // Execute the fragment callbacks and build the response.
     foreach ($fragments as $fragment) {
         if (isset($callbacks[$fragment])) {
             $res = call_user_func($callbacks[$fragment]);
             $responseParts[$fragment] = $res ? (string) $res : $res;
         } else {
             throw new HTTPResponse_Exception("X-Pjax = '{$fragment}' not supported for this URL.", 400);
         }
     }
     $response->setBody(Convert::raw2json($responseParts));
     $response->addHeader('Content-Type', 'text/json');
     return $response;
 }
 /**
  * @inheritdoc
  *
  * @param HTTPRequest $request
  * @param Session $session
  * @param DataModel $model
  *
  * @return bool
  */
 public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
 {
     if (array_key_exists('flush', $request->getVars())) {
         foreach (ClassInfo::implementorsOf('SilverStripe\\Core\\Flushable') as $class) {
             $class::flush();
         }
     }
     return true;
 }
 public function testGetURL()
 {
     $req = new HTTPRequest('GET', '/');
     $this->assertEquals('', $req->getURL());
     $req = new HTTPRequest('GET', '/assets/somefile.gif');
     $this->assertEquals('assets/somefile.gif', $req->getURL());
     $req = new HTTPRequest('GET', '/home?test=1');
     $this->assertEquals('home?test=1', $req->getURL(true));
     $this->assertEquals('home', $req->getURL());
 }
 /**
  * Check if we should merge
  *
  * @param HTTPRequest $request
  * @return bool
  */
 protected function getIsMerge($request)
 {
     $merge = $request->getVar('merge');
     // Default to true if not given
     if (!isset($merge)) {
         return true;
     }
     // merge=0 or merge=false will disable merge
     return !in_array($merge, array('0', 'false'));
 }
 /**
  * Get the file component from the request
  *
  * @param HTTPRequest $request
  * @return string
  */
 protected function parseFilename(HTTPRequest $request)
 {
     $filename = '';
     $next = $request->param('Filename');
     while ($next) {
         $filename = $filename ? File::join_paths($filename, $next) : $next;
         $next = $request->shift();
     }
     if ($extension = $request->getExtension()) {
         $filename = $filename . "." . $extension;
     }
     return $filename;
 }
 public function testFragmentsOverride()
 {
     $negotiator = new PjaxResponseNegotiator(array('alpha' => function () {
         return 'alpha response';
     }, 'beta' => function () {
         return 'beta response';
     }));
     $request = new HTTPRequest('GET', '/');
     $request->addHeader('X-Pjax', 'alpha');
     $request->addHeader('Accept', 'text/json');
     $response = $negotiator->setFragmentOverride(array('beta'))->respond($request);
     $json = json_decode($response->getBody());
     $this->assertFalse(isset($json->alpha));
     $this->assertObjectHasAttribute('beta', $json);
 }
 /**
  * @param HTTPRequest $request
  */
 public function runTask($request)
 {
     $name = $request->param('TaskName');
     $tasks = $this->getTasks();
     $title = function ($content) {
         printf(Director::is_cli() ? "%s\n\n" : '<h1>%s</h1>', $content);
     };
     $message = function ($content) {
         printf(Director::is_cli() ? "%s\n" : '<p>%s</p>', $content);
     };
     foreach ($tasks as $task) {
         if ($task['segment'] == $name) {
             $inst = Injector::inst()->create($task['class']);
             $title(sprintf('Running Task %s', $inst->getTitle()));
             if (!$inst->isEnabled()) {
                 $message('The task is disabled');
                 return;
             }
             $inst->run($request);
             return;
         }
     }
     $message(sprintf('The build task "%s" could not be found', Convert::raw2xml($name)));
 }
 /**
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return GridFieldDetailForm_ItemRequest
  */
 public function handleItem($gridField, $request)
 {
     // Our getController could either give us a true Controller, if this is the top-level GridField.
     // It could also give us a RequestHandler in the form of GridFieldDetailForm_ItemRequest if this is a
     // nested GridField.
     $requestHandler = $gridField->getForm()->getController();
     /** @var DataObject $record */
     if (is_numeric($request->param('ID'))) {
         $record = $gridField->getList()->byID($request->param("ID"));
     } else {
         $record = Object::create($gridField->getModelClass());
     }
     $handler = $this->getItemRequestHandler($gridField, $record, $requestHandler);
     // if no validator has been set on the GridField and the record has a
     // CMS validator, use that.
     if (!$this->getValidator() && (method_exists($record, 'getCMSValidator') || $record instanceof Object && $record->hasMethod('getCMSValidator'))) {
         $this->setValidator($record->getCMSValidator());
     }
     return $handler->handleRequest($request, DataModel::inst());
 }
 /**
  * Show the "password sent" page, after a user has requested
  * to reset their password.
  *
  * @param HTTPRequest $request The HTTPRequest for this action.
  * @return string Returns the "password sent" page as HTML code.
  */
 public function passwordsent($request)
 {
     $controller = $this->getResponseController(_t('Security.LOSTPASSWORDHEADER', 'Lost Password'));
     // if the controller calls Director::redirect(), this will break early
     if (($response = $controller->getResponse()) && $response->isFinished()) {
         return $response;
     }
     $email = Convert::raw2xml(rawurldecode($request->param('ID')) . '.' . $request->getExtension());
     $customisedController = $controller->customise(array('Title' => _t('Security.PASSWORDSENTHEADER', "Password reset link sent to '{email}'", array('email' => $email)), 'Content' => "<p>" . _t('Security.PASSWORDSENTTEXT', "Thank you! A reset link has been sent to '{email}', provided an account exists for this email" . " address.", array('email' => $email)) . "</p>", 'Email' => $email));
     //Controller::$currentController = $controller;
     return $customisedController->renderWith($this->getTemplatesFor('passwordsent'));
 }
 /**
  * View of a single file, either on the filesystem or on the web.
  *
  * @throws HTTPResponse_Exception
  * @param HTTPRequest $request
  * @return string
  */
 public function viewfile($request)
 {
     $file = null;
     $url = null;
     // Get file and url by request method
     if ($fileUrl = $request->getVar('FileURL')) {
         // Get remote url
         list($file, $url) = $this->viewfile_getRemoteFileByURL($fileUrl);
     } elseif ($id = $request->getVar('ID')) {
         // Or we could have been passed an ID directly
         list($file, $url) = $this->viewfile_getLocalFileByID($id);
     } else {
         // Or we could have been passed nothing, in which case panic
         throw $this->getErrorFor(_t("HTMLEditorField_Toolbar.ERROR_ID", 'Need either "ID" or "FileURL" parameter to identify the file'));
     }
     // Validate file exists
     if (!$url) {
         throw $this->getErrorFor(_t("HTMLEditorField_Toolbar.ERROR_NOTFOUND", 'Unable to find file to view'));
     }
     // Instantiate file wrapper and get fields based on its type
     // Check if appCategory is an image and exists on the local system, otherwise use Embed to reference a
     // remote image
     $fileCategory = $this->getFileCategory($url, $file);
     switch ($fileCategory) {
         case 'image':
         case 'image/supported':
             $fileWrapper = new HTMLEditorField_Image($url, $file);
             break;
         case 'flash':
             $fileWrapper = new HTMLEditorField_Flash($url, $file);
             break;
         default:
             // Only remote files can be linked via o-embed
             // {@see HTMLEditorField_Toolbar::getAllowedExtensions())
             if ($file) {
                 throw $this->getErrorFor(_t("HTMLEditorField_Toolbar.ERROR_OEMBED_REMOTE", "Embed is only compatible with remote files"));
             }
             // Other files should fallback to embed
             $fileWrapper = new HTMLEditorField_Embed($url, $file);
             break;
     }
     // Render fields and return
     $fields = $this->getFieldsForFile($url, $fileWrapper);
     return $fileWrapper->customise(array('Fields' => $fields))->renderWith($this->getTemplateViewFile());
 }
 /**
  * Handle an HTTP request, defined with a HTTPRequest object.
  *
  * @skipUpgrade
  * @param HTTPRequest $request
  * @param Session $session
  * @param DataModel $model
  * @return HTTPResponse|string
  */
 protected static function handleRequest(HTTPRequest $request, Session $session, DataModel $model)
 {
     $rules = Director::config()->get('rules');
     if (isset($_REQUEST['debug'])) {
         Debug::show($rules);
     }
     foreach ($rules as $pattern => $controllerOptions) {
         if (is_string($controllerOptions)) {
             if (substr($controllerOptions, 0, 2) == '->') {
                 $controllerOptions = array('Redirect' => substr($controllerOptions, 2));
             } else {
                 $controllerOptions = array('Controller' => $controllerOptions);
             }
         }
         if (($arguments = $request->match($pattern, true)) !== false) {
             $request->setRouteParams($controllerOptions);
             // controllerOptions provide some default arguments
             $arguments = array_merge($controllerOptions, $arguments);
             // Pop additional tokens from the tokenizer if necessary
             if (isset($controllerOptions['_PopTokeniser'])) {
                 $request->shift($controllerOptions['_PopTokeniser']);
             }
             // Handle redirection
             if (isset($arguments['Redirect'])) {
                 return "redirect:" . Director::absoluteURL($arguments['Redirect'], true);
             } else {
                 // Find the controller name
                 $controller = $arguments['Controller'];
                 Director::$urlParams = $arguments;
                 $controllerObj = Injector::inst()->create($controller);
                 $controllerObj->setSession($session);
                 try {
                     $result = $controllerObj->handleRequest($request, $model);
                 } catch (HTTPResponse_Exception $responseException) {
                     $result = $responseException->getResponse();
                 }
                 if (!is_object($result) || $result instanceof HTTPResponse) {
                     return $result;
                 }
                 user_error("Bad result from url " . $request->getURL() . " handled by " . get_class($controllerObj) . " controller: " . get_class($result), E_USER_WARNING);
             }
         }
     }
     // No URL rules matched, so return a 404 error.
     return new HTTPResponse('No URL rule was matched', 404);
 }
 /**
  * Url handler for edit form
  *
  * @param HTTPRequest $request
  * @return Form
  */
 public function DetailEditForm($request)
 {
     // Get ID either from posted back value, or url parameter
     $id = $request->param('ID') ?: $request->postVar('ID');
     return $this->getDetailEditForm($id);
 }
 /**
  * Url handler for add to campaign form
  *
  * @param HTTPRequest $request
  * @return Form
  */
 public function addToCampaignForm($request)
 {
     // Get ID either from posted back value, or url parameter
     $id = $request->param('ID') ?: $request->postVar('ID');
     return $this->getAddToCampaignForm($id);
 }
 /**
  * Handle a field request.
  * Uses {@link Form->dataFieldByName()} to find a matching field,
  * and falls back to {@link FieldList->fieldByName()} to look
  * for tabs instead. This means that if you have a tab and a
  * formfield with the same name, this method gives priority
  * to the formfield.
  *
  * @param HTTPRequest $request
  * @return FormField
  */
 public function handleField($request)
 {
     $field = $this->Fields()->dataFieldByName($request->param('FieldName'));
     if ($field) {
         return $field;
     } else {
         // falling back to fieldByName, e.g. for getting tabs
         return $this->Fields()->fieldByName($request->param('FieldName'));
     }
 }
 /**
  * @param HTTPRequest $request
  * @return mixed
  */
 public function edit($request)
 {
     $controller = $this->getToplevelController();
     $form = $this->ItemEditForm();
     $return = $this->customise(array('Backlink' => $controller->hasMethod('Backlink') ? $controller->Backlink() : $controller->Link(), 'ItemEditForm' => $form))->renderWith($this->getTemplates());
     if ($request->isAjax()) {
         return $return;
     } else {
         // If not requested by ajax, we need to render it within the controller context+template
         return $controller->customise(array('Content' => $return));
     }
 }
 /**
  * Controller's default action handler.  It will call the method named in "$Action", if that method
  * exists. If "$Action" isn't given, it will use "index" as a default.
  *
  * @param HTTPRequest $request
  * @param string $action
  *
  * @return DBHTMLText|HTTPResponse
  */
 protected function handleAction($request, $action)
 {
     foreach ($request->latestParams() as $k => $v) {
         if ($v || !isset($this->urlParams[$k])) {
             $this->urlParams[$k] = $v;
         }
     }
     $this->action = $action;
     $this->requestParams = $request->requestVars();
     if ($this->hasMethod($action)) {
         $result = parent::handleAction($request, $action);
         // If the action returns an array, customise with it before rendering the template.
         if (is_array($result)) {
             return $this->getViewer($action)->process($this->customise($result));
         } else {
             return $result;
         }
     }
     // Fall back to index action with before/after handlers
     $beforeResult = $this->extend('beforeCallActionHandler', $request, $action);
     if ($beforeResult) {
         return reset($beforeResult);
     }
     $result = $this->getViewer($action)->process($this);
     $afterResult = $this->extend('afterCallActionHandler', $request, $action, $result);
     if ($afterResult) {
         return reset($afterResult);
     }
     return $result;
 }
 /**
  * This is the action that gets executed when a GridField_AlterAction gets clicked.
  *
  * @param array $data
  * @param Form $form
  * @param HTTPRequest $request
  *
  * @return string
  */
 public function gridFieldAlterAction($data, $form, HTTPRequest $request)
 {
     $data = $request->requestVars();
     // Protection against CSRF attacks
     $token = $this->getForm()->getSecurityToken();
     if (!$token->checkRequest($request)) {
         $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again."));
     }
     $name = $this->getName();
     $fieldData = null;
     if (isset($data[$name])) {
         $fieldData = $data[$name];
     }
     $state = $this->getState(false);
     /** @skipUpgrade */
     if (isset($fieldData['GridState'])) {
         $state->setValue($fieldData['GridState']);
     }
     foreach ($data as $dataKey => $dataValue) {
         if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) {
             $stateChange = Session::get($matches[1]);
             $actionName = $stateChange['actionName'];
             $arguments = array();
             if (isset($stateChange['args'])) {
                 $arguments = $stateChange['args'];
             }
             $html = $this->handleAlterAction($actionName, $arguments, $data);
             if ($html) {
                 return $html;
             }
         }
     }
     if ($request->getHeader('X-Pjax') === 'CurrentField') {
         return $this->FieldHolder();
     }
     return $form->forTemplate();
 }
 /**
  * Determine if the current user is able to set the given site stage / archive
  *
  * @param HTTPRequest $request
  * @return bool
  */
 public static function can_choose_site_stage($request)
 {
     // Request is allowed if stage isn't being modified
     if ((!$request->getVar('stage') || $request->getVar('stage') === static::LIVE) && !$request->getVar('archiveDate')) {
         return true;
     }
     // Check permissions with member ID in session.
     $member = Member::currentUser();
     $permissions = Config::inst()->get(get_called_class(), 'non_live_permissions');
     return $member && Permission::checkMember($member, $permissions);
 }
 /**
  * Determines if a specified file exists
  *
  * @param HTTPRequest $request
  * @return HTTPResponse
  */
 public function fileexists(HTTPRequest $request)
 {
     // Assert that requested filename doesn't attempt to escape the directory
     $originalFile = $request->requestVar('filename');
     if ($originalFile !== basename($originalFile)) {
         $return = array('error' => _t('File.NOVALIDUPLOAD', 'File is not a valid upload'));
     } else {
         $return = array('exists' => $this->checkFileExists($originalFile));
     }
     // Encode and present response
     $response = new HTTPResponse(Convert::raw2json($return));
     $response->addHeader('Content-Type', 'application/json');
     if (!empty($return['error'])) {
         $response->setStatusCode(400);
     }
     return $response;
 }
 public function handleRequest(HTTPRequest $request, DataModel $model)
 {
     // If this is the final portion of the request (i.e. the URL is just /admin), direct to the default panel
     if ($request->allParsed()) {
         $segment = Config::inst()->get($this->config()->default_panel, 'url_segment');
         $this->redirect(Controller::join_links(self::admin_url(), $segment, '/'));
         return $this->getResponse();
     } else {
         $rules = self::rules();
         foreach ($rules as $pattern => $controller) {
             if (($arguments = $request->match($pattern, true)) !== false) {
                 $controllerObj = Injector::inst()->create($controller);
                 $controllerObj->setSession($this->session);
                 return $controllerObj->handleRequest($request, $model);
             }
         }
     }
     return $this->httpError(404, 'Not found');
 }
 /**
  * Returns a json array of a search results that can be used by for example Jquery.ui.autosuggestion
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return string
  */
 public function doSearch($gridField, $request)
 {
     $dataClass = $gridField->getModelClass();
     $allList = $this->searchList ? $this->searchList : DataList::create($dataClass);
     $searchFields = $this->getSearchFields() ? $this->getSearchFields() : $this->scaffoldSearchFields($dataClass);
     if (!$searchFields) {
         throw new LogicException(sprintf('GridFieldAddExistingAutocompleter: No searchable fields could be found for class "%s"', $dataClass));
     }
     $params = array();
     foreach ($searchFields as $searchField) {
         $name = strpos($searchField, ':') !== FALSE ? $searchField : "{$searchField}:StartsWith";
         $params[$name] = $request->getVar('gridfield_relationsearch');
     }
     $results = $allList->subtract($gridField->getList())->filterAny($params)->sort(strtok($searchFields[0], ':'), 'ASC')->limit($this->getResultsLimit());
     $json = array();
     Config::nest();
     SSViewer::config()->update('source_file_comments', false);
     $viewer = SSViewer::fromString($this->resultsFormat);
     foreach ($results as $result) {
         $title = html_entity_decode($viewer->process($result));
         $json[] = array('label' => $title, 'value' => $title, 'id' => $result->ID);
     }
     Config::unnest();
     return Convert::array2json($json);
 }
 public function testSubActions()
 {
     /* If a controller action returns another controller, ensure that the $action variable is correctly forwarded */
     $response = $this->get("ControllerTest_ContainerController/subcontroller/subaction");
     $this->assertEquals('subaction', $response->getBody());
     $request = new HTTPRequest('GET', 'ControllerTest_ContainerController/subcontroller/substring/subvieweraction');
     /* Shift to emulate the director selecting the controller */
     $request->shift();
     /* Handle the request to create conditions where improperly passing the action to the viewer might fail */
     $controller = new ControllerTest_ContainerController();
     try {
         $controller->handleRequest($request, DataModel::inst());
     } catch (ControllerTest_SubController_Exception $e) {
         $this->fail($e->getMessage());
     }
 }
 /**
  * Allows requesting a view update on specific tree nodes.
  * Similar to {@link getsubtree()}, but doesn't enforce loading
  * all children with the node. Useful to refresh views after
  * state modifications, e.g. saving a form.
  *
  * @param HTTPRequest $request
  * @return string JSON
  */
 public function updatetreenodes($request)
 {
     $data = array();
     $ids = explode(',', $request->getVar('ids'));
     foreach ($ids as $id) {
         if ($id === "") {
             continue;
         }
         // $id may be a blank string, which is invalid and should be skipped over
         $record = $this->getRecord($id);
         if (!$record) {
             continue;
         }
         // In case a page is no longer available
         $recordController = $this->stat('tree_class') == 'SilverStripe\\CMS\\Model\\SiteTree' ? CMSPageEditController::singleton() : $this;
         // Find the next & previous nodes, for proper positioning (Sort isn't good enough - it's not a raw offset)
         // TODO: These methods should really be in hierarchy - for a start it assumes Sort exists
         $next = $prev = null;
         $className = $this->stat('tree_class');
         $next = DataObject::get($className)->filter('ParentID', $record->ParentID)->filter('Sort:GreaterThan', $record->Sort)->first();
         if (!$next) {
             $prev = DataObject::get($className)->filter('ParentID', $record->ParentID)->filter('Sort:LessThan', $record->Sort)->reverse()->first();
         }
         $link = Controller::join_links($recordController->Link("show"), $record->ID);
         $html = LeftAndMain_TreeNode::create($record, $link, $this->isCurrentPage($record))->forTemplate() . '</li>';
         $data[$id] = array('html' => $html, 'ParentID' => $record->ParentID, 'NextID' => $next ? $next->ID : null, 'PrevID' => $prev ? $prev->ID : null);
     }
     $this->getResponse()->addHeader('Content-Type', 'text/json');
     return Convert::raw2json($data);
 }
 /**
  * Get security token from request
  *
  * @param HTTPRequest $request
  * @return string
  */
 protected function getRequestToken($request)
 {
     $name = $this->getName();
     $header = 'X-' . ucwords(strtolower($name));
     if ($token = $request->getHeader($header)) {
         return $token;
     }
     // Get from request var
     return $request->requestVar($name);
 }
 public function runRegisteredController(HTTPRequest $request)
 {
     $controllerClass = null;
     $baseUrlPart = $request->param('Action');
     $reg = Config::inst()->get(__CLASS__, 'registered_controllers');
     if (isset($reg[$baseUrlPart])) {
         $controllerClass = $reg[$baseUrlPart]['controller'];
     }
     if ($controllerClass && class_exists($controllerClass)) {
         return $controllerClass::create();
     }
     $msg = 'Error: no controller registered in ' . __CLASS__ . ' for: ' . $request->param('Action');
     if (Director::is_cli()) {
         // in CLI we cant use httpError because of a bug with stuff being in the output already, see DevAdminControllerTest
         throw new Exception($msg);
     } else {
         $this->httpError(500, $msg);
     }
 }
 public function testCheckRequest()
 {
     $t = new SecurityToken();
     $n = $t->getName();
     $t->setValue(null);
     $r = new HTTPRequest('GET', 'dummy', array($n => 'invalidtoken'));
     $this->assertFalse($t->checkRequest($r), 'Any token is invalid if no token is stored');
     $t->setValue(null);
     $r = new HTTPRequest('GET', 'dummy', array($n => null));
     $this->assertFalse($t->checkRequest($r), 'NULL token is invalid if no token is stored');
     $t->setValue('mytoken');
     $r = new HTTPRequest('GET', 'dummy', array($n => 'invalidtoken'));
     $this->assertFalse($t->checkRequest($r), 'Invalid token returns false');
     $t->setValue('mytoken');
     $r = new HTTPRequest('GET', 'dummy', array($n => 'mytoken'));
     $this->assertTrue($t->checkRequest($r), 'Valid token returns true');
     $t->setValue('mytoken');
     $r = new HTTPRequest('GET', 'dummy');
     $r->addHeader('X-Securityid', 'mytoken');
     $this->assertTrue($t->checkRequest($r), 'Valid token returns true');
     $t->setValue('mytoken');
     $r = new HTTPRequest('GET', 'dummy');
     $r->addHeader('X-Securityid', 'wrongtoken');
     $this->assertFalse($t->checkRequest($r), 'Valid token returns true');
 }
 /**
  * Get the whole tree of a part of the tree via an AJAX request.
  *
  * @param HTTPRequest $request
  * @return string
  * @throws Exception
  */
 public function tree(HTTPRequest $request)
 {
     // Array sourceObject is an explicit list of values - construct a "flat tree"
     if (is_array($this->sourceObject)) {
         $output = "<ul class=\"tree\">\n";
         foreach ($this->sourceObject as $k => $v) {
             $output .= '<li id="selector-' . $this->name . '-' . $k . '"><a>' . $v . '</a>';
         }
         $output .= "</ul>";
         return $output;
     }
     // Regular source specification
     $isSubTree = false;
     $this->search = $request->requestVar('search');
     $id = is_numeric($request->latestParam('ID')) ? (int) $request->latestParam('ID') : (int) $request->requestVar('ID');
     /** @var DataObject|Hierarchy $obj */
     $obj = null;
     if ($id && !$request->requestVar('forceFullTree')) {
         $obj = DataObject::get_by_id($this->sourceObject, $id);
         $isSubTree = true;
         if (!$obj) {
             throw new Exception("TreeDropdownField->tree(): the object #{$id} of type {$this->sourceObject} could not be found");
         }
     } else {
         if ($this->baseID) {
             $obj = DataObject::get_by_id($this->sourceObject, $this->baseID);
         }
         if (!$this->baseID || !$obj) {
             $obj = DataObject::singleton($this->sourceObject);
         }
     }
     // pre-process the tree - search needs to operate globally, not locally as marking filter does
     if ($this->search) {
         $this->populateIDs();
     }
     if ($this->filterCallback || $this->search) {
         $obj->setMarkingFilterFunction(array($this, "filterMarking"));
     }
     $obj->markPartialTree($nodeCountThreshold = 30, $context = null, $this->childrenMethod, $this->numChildrenMethod);
     // allow to pass values to be selected within the ajax request
     if (isset($_REQUEST['forceValue']) || $this->value) {
         $forceValue = isset($_REQUEST['forceValue']) ? $_REQUEST['forceValue'] : $this->value;
         $values = preg_split('/,\\s*/', $forceValue);
         if ($values) {
             foreach ($values as $value) {
                 if (!$value || $value == 'unchanged') {
                     continue;
                 }
                 $obj->markToExpose($this->objectForKey($value));
             }
         }
     }
     $self = $this;
     $titleFn = function (&$child) use(&$self) {
         /** @var DataObject|Hierarchy $child */
         $keyField = $self->keyField;
         $labelField = $self->labelField;
         return sprintf('<li id="selector-%s-%s" data-id="%s" class="class-%s %s %s"><a rel="%d">%s</a>', Convert::raw2xml($self->getName()), Convert::raw2xml($child->{$keyField}), Convert::raw2xml($child->{$keyField}), Convert::raw2xml($child->class), Convert::raw2xml($child->markingClasses($self->numChildrenMethod)), $self->nodeIsDisabled($child) ? 'disabled' : '', (int) $child->ID, $child->obj($labelField)->forTemplate());
     };
     // Limit the amount of nodes shown for performance reasons.
     // Skip the check if we're filtering the tree, since its not clear how many children will
     // match the filter criteria until they're queried (and matched up with previously marked nodes).
     $nodeThresholdLeaf = Config::inst()->get('SilverStripe\\ORM\\Hierarchy\\Hierarchy', 'node_threshold_leaf');
     if ($nodeThresholdLeaf && !$this->filterCallback && !$this->search) {
         $className = $this->sourceObject;
         $nodeCountCallback = function ($parent, $numChildren) use($className, $nodeThresholdLeaf) {
             if ($className === 'SilverStripe\\CMS\\Model\\SiteTree' && $parent->ID && $numChildren > $nodeThresholdLeaf) {
                 return sprintf('<ul><li><span class="item">%s</span></li></ul>', _t('LeftAndMain.TooManyPages', 'Too many pages'));
             }
             return null;
         };
     } else {
         $nodeCountCallback = null;
     }
     if ($isSubTree) {
         $html = $obj->getChildrenAsUL("", $titleFn, null, true, $this->childrenMethod, $this->numChildrenMethod, true, null, $nodeCountCallback);
         return substr(trim($html), 4, -5);
     } else {
         $html = $obj->getChildrenAsUL('class="tree"', $titleFn, null, true, $this->childrenMethod, $this->numChildrenMethod, true, null, $nodeCountCallback);
         return $html;
     }
 }
 /**
  * Check if this action has a confirmation step
  *
  * @param HTTPRequest $request
  * @return HTTPResponse
  */
 public function handleConfirmation($request)
 {
     // Find the action handler
     $action = $request->param('BatchAction');
     $actionHandler = $this->actionByName($action);
     // Sanitise ID list and query the database for apges
     $csvIDs = $request->requestVar('csvIDs');
     $ids = $this->cleanIDs($csvIDs);
     // Check dialog
     if ($actionHandler->hasMethod('confirmationDialog')) {
         $response = new HTTPResponse(json_encode($actionHandler->confirmationDialog($ids)));
     } else {
         $response = new HTTPResponse(json_encode(array('alert' => false)));
     }
     $response->addHeader("Content-type", "application/json");
     return $response;
 }
 /**
  * Handle the export, for both the action button and the URL
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return HTTPResponse
  */
 public function handleExport($gridField, $request = null)
 {
     $now = date("d-m-Y-H-i");
     $fileName = "export-{$now}.csv";
     if ($fileData = $this->generateExportFileData($gridField)) {
         return HTTPRequest::send_file($fileData, $fileName, 'text/csv');
     }
     return null;
 }
 /**
  * @param HTTPRequest $request
  * @return array
  */
 protected function findAction($request)
 {
     $handlerClass = $this->class ? $this->class : get_class($this);
     // We stop after RequestHandler; in other words, at ViewableData
     while ($handlerClass && $handlerClass != 'SilverStripe\\View\\ViewableData') {
         $urlHandlers = Config::inst()->get($handlerClass, 'url_handlers', Config::UNINHERITED);
         if ($urlHandlers) {
             foreach ($urlHandlers as $rule => $action) {
                 if (isset($_REQUEST['debug_request'])) {
                     Debug::message("Testing '{$rule}' with '" . $request->remaining() . "' on {$this->class}");
                 }
                 if ($request->match($rule, true)) {
                     if (isset($_REQUEST['debug_request'])) {
                         Debug::message("Rule '{$rule}' matched to action '{$action}' on {$this->class}. " . "Latest request params: " . var_export($request->latestParams(), true));
                     }
                     return array('rule' => $rule, 'action' => $action);
                 }
             }
         }
         $handlerClass = get_parent_class($handlerClass);
     }
     return null;
 }