/** * Handle the url parsing for the documentation. In order to make this * user friendly this does some tricky things.. * * The urls which should work * / - index page * /en/sapphire - the index page of sapphire (shows versions) * /2.4/en/sapphire - the docs for 2.4 sapphire. * /2.4/en/sapphire/installation/ * * @return SS_HTTPResponse */ public function handleRequest(SS_HTTPRequest $request) { // Workaround for root routing, e.g. Director::addRules(10, array('$Action' => 'DocumentationViewer')) $this->Version = $request->param('Action') ? $request->param('Action') : $request->shift(); $this->Lang = $request->shift(); $this->ModuleName = $request->shift(); $this->Remaining = $request->shift(10); DocumentationService::load_automatic_registration(); if (isset($this->Version)) { // check to see if its a valid version. If its not a float then its not actually a version // its actually a language and it needs to change. So this means we support 2 structures // /2.4/en/sapphire/page and // /en/sapphire/page which is a link to the latest one if (!is_numeric($this->Version) && $this->Version != 'current') { array_unshift($this->Remaining, $this->ModuleName); // not numeric so /en/sapphire/folder/page if (isset($this->Lang) && $this->Lang) { $this->ModuleName = $this->Lang; } $this->Lang = $this->Version; $this->Version = null; } else { // if(!DocumentationService::is_registered_version($this->Version)) { // $this->httpError(404, 'The requested version could not be found.'); // } } } if (isset($this->Lang)) { // check to see if its a valid language // if(!DocumentationService::is_registered_language($this->Lang)) { // $this->httpError(404, 'The requested language could not be found.'); // } } else { $this->Lang = 'en'; } // 'current' version mapping $module = DocumentationService::is_registered_module($this->ModuleName, null, $this->Lang); if ($this->Version && $module) { $current = $module->getCurrentVersion(); if ($this->Version == 'current') { $this->Version = $current; } else { if ($current == $this->Version) { $this->Version = 'current'; $link = $this->Link($this->Remaining); $this->response = new SS_HTTPResponse(); $this->redirect($link, 301); // permanent redirect return $this->response; } } } return parent::handleRequest($request); }
/** * @uses ModelAsController::getNestedController() * @param SS_HTTPRequest $request * @param DataModel $model * @return SS_HTTPResponse */ public function handleRequest(SS_HTTPRequest $request, DataModel $model) { // Check Translatable dependency if (!class_exists('Translatable') || !SiteTree::has_extension('Translatable') && !SiteTree::has_extension('LanguagePrefixTranslatable')) { throw new Exception('Dependency error: the LanguagePrefix module expects the Translatable module.'); } $disablePrefixForDefaultLang = Config::inst()->get('prefixconfig', 'disable_prefix_for_default_lang'); $firstSegment = $request->param('URLSegment'); if ($firstSegment) { $prefixUsed = $this->setLocale($firstSegment); $defaultLocale = Translatable::default_locale(); $isDefaultLocale = $this->locale == $defaultLocale; if ($prefixUsed) { if ($isDefaultLocale && $disablePrefixForDefaultLang) { $url = substr($request->getURL(true), strlen($firstSegment)); return $this->redirect($url, 301); } else { $request->shiftAllParams(); $request->shift(1); } } else { /* * if no prefix is used but $disablePrefixForDefaultLang * is set, we go on like nothing happened. Otherwise a * 404 is generated. @todo: maybe we should redirect * pages that do actually exist, because this is a bit * harsh? */ //if (!$isDefaultLocale || !$disablePrefixForDefaultLang) { // return $this->showPageNotFound(); //} } } return parent::handleRequest($request, $model); }
/** * Get the file component from the request * * @param \SS_HTTPRequest $request * @return string */ protected function parseFilename(\SS_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 static function module_controller_for_request(ContentController $contentController, SS_HTTPRequest $request, $relationship = 'ContentModules') { $moduleURLSegment = $request->shift(); if ($module = $contentController->data()->{$relationship}()->filter('URLSegment', $moduleURLSegment)->first()) { $controller = self::controller_for($module, $contentController); //backwards compatibility support for modules handling actions directly //should move to using controllers to handle actions if ($controller instanceof ModuleController) { return $controller->handleRequest($request, new DataModel()); } else { $action = $request->shift(); if ($controller->hasMethod($action)) { return $controller->{$action}($request); } } } }
/** Preview an advertisement. */ public function preview(SS_HTTPRequest $request) { $request->shift(); $adID = (int) $request->param('ID'); $ad = UniadsObject::get()->byID($adID); if (!$ad) { Controller::curr()->httpError(404); return; } // No impression and click tracking for previews $conf = UniadsObject::config(); $conf->use_js_tracking = false; $conf->record_impressions = false; $conf->record_impressions_stats = false; // Block stylesheets and JS that are not required (using our own template) Requirements::clear(); $template = new SSViewer('UniadsPreview'); return $template->Process($ad); }
/** * Handle an HTTP request, defined with a SS_HTTPRequest object. * * @param SS_HTTPRequest $request * @param Session $session * @param DataModel $model * * @return SS_HTTPResponse|string */ protected static function handleRequest(SS_HTTPRequest $request, Session $session, DataModel $model) { $rules = Config::inst()->get('Director', '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); // Find the controller name if (isset($arguments['Controller'])) { $controller = $arguments['Controller']; } // 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 { Director::$urlParams = $arguments; $controllerObj = Injector::inst()->create($controller); $controllerObj->setSession($session); try { $result = $controllerObj->handleRequest($request, $model); } catch (SS_HTTPResponse_Exception $responseException) { $result = $responseException->getResponse(); } if (!is_object($result) || $result instanceof SS_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 SS_HTTPResponse('No URL rule was matched', 404); }
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 SS_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()); } }
/** * Mock a request against a given controller * * @param ContentController $controller * @param string $url */ protected function requestURL(ContentController $controller, $url) { $request = new SS_HTTPRequest('get', $url); $request->match('$URLSegment//$Action/$ID/$OtherID'); $request->shift(); $controller->init(); $controller->handleRequest($request, new DataModel()); }
/** * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * fall over to a child controller in order to provide functionality for nested URLs. * * @return SS_HTTPResponse */ public function handleRequest(SS_HTTPRequest $request) { $child = null; $action = $request->param('Action'); // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass // control to a child controller. This allows for the creation of chains of controllers which correspond to a // nested URL. if ($action && SiteTree::nested_urls() && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic Translatable::disable_locale_filter(); // look for a page with this URLSegment $child = DataObject::get_one('SiteTree', sprintf("\"ParentID\" = %s AND \"URLSegment\" = '%s'", $this->ID, Convert::raw2sql($action))); Translatable::enable_locale_filter(); // if we can't find a page with this URLSegment try to find one that used to have // that URLSegment but changed. See ModelAsController->getNestedController() for similiar logic. if (!$child) { $child = ModelAsController::find_old_page($action, $this->ID); if ($child) { $response = new SS_HTTPResponse(); $params = $request->getVars(); if (isset($params['url'])) { unset($params['url']); } $response->redirect(Controller::join_links($child->Link(Controller::join_links($request->param('ID'), $request->param('OtherID'))), $params ? '?' . http_build_query($params) : null), 301); return $response; } } } // we found a page with this URLSegment. if ($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request); } else { // If a specific locale is requested, and it doesn't match the page found by URLSegment, // look for a translation and redirect (see #5001). Only happens on the last child in // a potentially nested URL chain. if ($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) { $translation = $this->dataRecord->getTranslation($request->getVar('locale')); if ($translation) { $response = new SS_HTTPResponse(); $response->redirect($translation->Link(), 301); throw new SS_HTTPResponse_Exception($response); } } Director::set_current_page($this->data()); $response = parent::handleRequest($request); Director::set_current_page(null); } return $response; }
/** * Handle the current URL, parsing a year/month/day/media format, and directing towards any valid controller actions that may be defined. * * @URLparameter <{YEAR}> integer * @URLparameter <{MONTH}> integer * @URLparameter <{DAY}> integer * @URLparameter <{MEDIA_URL_SEGMENT}> string * @return ss http response */ public function handleURL() { // Retrieve the formatted URL. $request = $this->getRequest(); $URL = $request->param('URL'); // Determine whether a controller action resolves. if ($this->hasAction($URL) && $this->checkAccessAction($URL)) { $output = $this->{$URL}($request); // The current request URL has been successfully parsed. while (!$request->allParsed()) { $request->shift(); } return $output; } else { if (!is_numeric($URL)) { // Determine whether a media page child once existed, and redirect appropriately. $response = $this->resolveURL(); if ($response) { // The current request URL has been successfully parsed. while (!$request->allParsed()) { $request->shift(); } return $response; } else { // The URL doesn't resolve. return $this->httpError(404); } } } // Determine the formatted URL segments. $segments = array($URL); $remaining = $request->remaining(); if ($remaining) { $remaining = explode('/', $remaining); // Determine the media page child to display. $child = null; $action = null; // Iterate the formatted URL segments. $iteration = 1; foreach ($remaining as $segment) { if (is_null($action)) { // Update the current request. $request->shift(); if ($child) { // Determine whether a controller action has been defined. $action = $segment; break; } else { if (!is_numeric($segment)) { if ($iteration === 4) { // The remaining URL doesn't match the month/day/media format. return $this->httpError(404); } // Determine the media page child to display, using the URL segment and date. $children = MediaPage::get()->filter(array('ParentID' => $this->data()->ID, 'URLSegment' => $segment)); if (!empty($segments)) { // Apply a partial match against the date, since the previous URL segments may only contain the year/month. $date = array(); foreach ($segments as $previous) { $date[] = str_pad($previous, 2, '0', STR_PAD_LEFT); } $children = $children->filter(array('Date:StartsWith' => implode('-', $date))); } $child = $children->first(); // Determine whether a media page child once existed, and redirect appropriately. if (is_null($child)) { $response = $this->resolveURL(); if ($response) { // The current request URL has been successfully parsed. while (!$request->allParsed()) { $request->shift(); } return $response; } else { // The URL doesn't match the month/day/media format. return $this->httpError(404); } } } } } $segments[] = $segment; $iteration++; } // Retrieve the media page child controller, and determine whether an action resolves. if ($child) { $controller = ModelAsController::controller_for($child); // Determine whether a controller action resolves. if (is_null($action)) { return $controller; } else { if ($controller->hasAction($action) && $controller->checkAccessAction($action)) { $output = $controller->{$action}($request); // The current request URL has been successfully parsed. while (!$request->allParsed()) { $request->shift(); } return $output; } else { // The controller action doesn't resolve. return $this->httpError(404); } } } } // Retrieve the paginated children using the date filter segments. $request = new SS_HTTPRequest('GET', $this->Link(), array_merge($request->getVars(), array('from' => implode('-', $segments)))); // The new request URL doesn't require parsing. while (!$request->allParsed()) { $request->shift(); } // Handle the new request URL. return $this->handleRequest($request); }
/** * Handle an HTTP request, defined with a SS_HTTPRequest object. * * @return SS_HTTPResponse|string */ protected static function handleRequest(SS_HTTPRequest $request, Session $session, DataModel $model) { $rules = Config::inst()->get('Director', '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); // Find the controller name if (isset($arguments['Controller'])) { $controller = $arguments['Controller']; } // Pop additional tokens from the tokeniser if necessary if (isset($controllerOptions['_PopTokeniser'])) { $request->shift($controllerOptions['_PopTokeniser']); } // Handle redirections if (isset($arguments['Redirect'])) { return "redirect:" . Director::absoluteURL($arguments['Redirect'], true); } else { Director::$urlParams = $arguments; $controllerObj = Injector::inst()->create($controller); $controllerObj->setSession($session); try { $result = $controllerObj->handleRequest($request, $model); } catch (SS_HTTPResponse_Exception $responseException) { $result = $responseException->getResponse(); } if (!is_object($result) || $result instanceof SS_HTTPResponse) { return $result; } user_error("Bad result from url " . $request->getURL() . " handled by " . get_class($controllerObj) . " controller: " . get_class($result), E_USER_WARNING); } } } /** * @andrelohmann * * This code allows to return custom Error Pages without using the CMS Module * */ $template = array('ErrorPage', 'Page'); $result = new ArrayData(array('Title' => 404, 'Content' => DBField::create_field('HTMLText', 'No URL rule was matched'))); // No URL rules matched, so return a 404 error. return new SS_HTTPResponse($result->renderWith($template), 404); /** * Original Code * * // No URL rules matched, so return a 404 error. * return new SS_HTTPResponse('No URL rule was matched', 404); * */ }
/** * Allows a user to view the details of their registration. * * @param SS_HTTPRequest $request * @return EventRegistrationDetailsController */ public function registration($request) { $id = $request->param('ID'); if (!ctype_digit($id)) { $this->httpError(404); } $rego = EventRegistration::get()->byID($id); if (!$rego || $rego->Time()->EventID != $this->ID) { $this->httpError(404); } $request->shift(); $request->shiftAllParams(); return new EventRegistrationDetailsController($this, $rego); }
/** * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * fall over to a child controller in order to provide functionality for nested URLs. * * @param SS_HTTPRequest $request * @param DataModel $model * @return SS_HTTPResponse * @throws SS_HTTPResponse_Exception */ public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { $child = null; $action = $request->param('Action'); $this->setDataModel($model); // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass // control to a child controller. This allows for the creation of chains of controllers which correspond to a // nested URL. if ($action && SiteTree::config()->nested_urls && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } // look for a page with this URLSegment $child = $this->model->SiteTree->filter(array('ParentID' => $this->ID, 'URLSegment' => rawurlencode($action)))->first(); if (class_exists('Translatable')) { Translatable::enable_locale_filter(); } } // we found a page with this URLSegment. if ($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request, $model); } else { // If a specific locale is requested, and it doesn't match the page found by URLSegment, // look for a translation and redirect (see #5001). Only happens on the last child in // a potentially nested URL chain. if (class_exists('Translatable')) { if ($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) { $translation = $this->dataRecord->getTranslation($request->getVar('locale')); if ($translation) { $response = new SS_HTTPResponse(); $response->redirect($translation->Link(), 301); throw new SS_HTTPResponse_Exception($response); } } } Director::set_current_page($this->data()); try { $response = parent::handleRequest($request, $model); Director::set_current_page(null); } catch (SS_HTTPResponse_Exception $e) { $this->popCurrent(); Director::set_current_page(null); throw $e; } } return $response; }
/** * Allows a user to view the details of their registration. * * @param SS_HTTPRequest $request * @return EventRegistrationDetailsController */ public function registration($request) { $id = $request->param('ID'); $rego = DataObject::get_by_id('EventRegistration', (int) $id); if (!$rego || $rego->Time()->EventID != $this->ID) { $this->httpError(404); } $request->shift(); $request->shiftAllParams(); return new EventRegistrationDetailsController($this, $rego); }
/** * Action to handle sorting of a single file * * @param SS_HTTPRequest $request */ public function sort(SS_HTTPRequest $request) { $controller = Controller::curr(); //die(json_encode($request->allParams())); // Check if a new position is given $newPosition = $request->getVar('newPosition'); $oldPosition = $request->getVar('oldPosition'); $fileID = $request->shift(); if ($newPosition === "") { $controller->httpError(403); } // Check form field state if ($this->owner->isDisabled() || $this->owner->isReadonly()) { $controller->httpError(403); } // Check item permissions $itemMoved = DataObject::get_by_id('File', $fileID); if (!$itemMoved) { $controller->httpError(404); } if (!$itemMoved->canEdit()) { $controller->httpError(403); } // Only allow actions on files in the managed relation (if one exists) $sortColumn = $this->getSortableColumn(); $relationName = $this->owner->getName(); $record = $this->owner->getRecord(); if ($record && $record->hasMethod($relationName)) { /** @var HasManyList|ManyManyList $list */ $list = $record->{$relationName}(); $list = $list->sort($sortColumn, 'ASC'); $listForeignKey = $list->getForeignKey(); $is_many_many = $record->manyMany($relationName) !== null; $i = 0; $newPosition = intval($newPosition); $oldPosition = intval($oldPosition); $arrayList = $list->toArray(); $itemIsInList = false; foreach ($arrayList as $item) { /** @var File $item */ if ($item->ID == $itemMoved->ID) { $sort = $newPosition; // flag that we found our item in the list $itemIsInList = true; } else { if ($i >= $newPosition && $i < $oldPosition) { $sort = $i + 1; } else { if ($i <= $newPosition && $i > $oldPosition) { $sort = max(0, $i - 1); } else { $sort = $i; } } } if ($is_many_many) { $list->remove($item); $list->add($item, array($sortColumn => $sort + 1)); } else { if (!$item->exists()) { $item->write(); } $item->{$sortColumn} = $sort + 1; $item->write(); } $i++; } // if the item wasn't in our list, add it now with the new sort position if (!$itemIsInList) { if ($is_many_many) { $list->add($itemMoved, array($sortColumn => $newPosition + 1)); } else { $itemMoved->{$listForeignKey} = $record->ID; $itemMoved->{$sortColumn} = intval($newPosition + 1); $itemMoved->write(); } } Requirements::clear(); return "1"; } $controller->httpError(403); }
/** * */ public function handleAddInline(SS_HTTPRequest $request) { // Force reset $this->children = FieldList::create(); // Get passed arguments // todo(Jake): Change '->remaining' to '->shift(4)' and test. // remove other ->shift things. $dirParts = explode('/', $request->remaining()); $class = isset($dirParts[0]) ? $dirParts[0] : ''; if (!$class) { return $this->httpError(400, 'No ClassName was supplied.'); } $modelClassNames = $this->getModelClasses(); if (!isset($modelClassNames[$class])) { return $this->httpError(400, 'Invalid ClassName "' . $class . '" was supplied.'); } // Determine sub field action (if executing one) $isSubFieldAction = isset($dirParts[1]); $recordIDOrNew = isset($dirParts[1]) && $dirParts[1] ? $dirParts[1] : null; if ($recordIDOrNew === null || $recordIDOrNew === 'new') { $record = $class::create(); if (!$record->canCreate(Member::currentUser())) { return $this->httpError(400, 'Invalid permissions. Current user (#' . Member::currentUserID() . ') cannot create "' . $class . '" class type.'); } } else { $recordIDOrNew = (int) $recordIDOrNew; if (!$recordIDOrNew) { return $this->httpError(400, 'Malformed record ID in sub-field action was supplied (' . $class . ' #' . $recordIDOrNew . ').'); } $record = $class::get()->byID($recordIDOrNew); if (!$record->canEdit(Member::currentUser())) { return $this->httpError(400, 'Invalid permissions. Current user (#' . Member::currentUserID() . ') cannot edit "' . $class . '" #' . $recordIDOrNew . ' class type.'); } } // Check if sub-field exists on requested record (can request new record with 'new') $fields = $this->getRecordDataFields($record); $dataFields = $fields->dataFields(); // $isValidSubFieldAction = isset($dirParts[2]) && $dirParts[2] === 'field' ? true : false; $subField = null; if ($isSubFieldAction) { $subFieldName = isset($dirParts[3]) && $dirParts[3] ? $dirParts[3] : ''; if (!$subFieldName || !isset($dataFields[$subFieldName])) { return $this->httpError(400, 'Invalid sub-field was supplied (' . $class . '::' . $subFieldName . ').'); } $subField = $dataFields[$subFieldName]; } $this->applyUniqueFieldNames($fields, $record); // If set a sub-field, execute its action instead. if ($isSubFieldAction) { if ($isValidSubFieldAction && $subField) { // Consume so Silverstripe handles the actions naturally. $request->shift(); // $ClassName $request->shift(); // $ID ('new' or '1') $request->shift(); // field $request->shift(); // $SubFieldName return $subField; } return $this->httpError(400, 'Invalid sub-field action on ' . __CLASS__ . '::' . __FUNCTION__); } // Allow fields to render, $this->children = $fields; // Remove all actions $actions = $this->Actions(); foreach ($actions as $action) { $actions->remove($action); } return $this->renderWith(array($this->class . '_addinline', __CLASS__ . '_addinline')); }