public function testMatch() { $request = new SS_HTTPRequest("GET", "admin/crm/add"); /* When a rule matches, but has no variables, array("_matched" => true) is returned. */ $this->assertEquals(array("_matched" => true), $request->match('admin/crm', true)); /* Becasue we shifted admin/crm off the stack, just "add" should be remaining */ $this->assertEquals("add", $request->remaining()); $this->assertEquals(array("_matched" => true), $request->match('add', true)); }
/** * @param SS_HTTPRequest $request */ public function run($request) { $email = $request->remaining(); $params = $request->allParams(); $url = Director::absoluteURL("dev/{$params['Action']}/{$params['TaskName']}", true); echo '<h2>Choose Email</h2>'; echo '<ul>'; foreach ($this->previewableEmails as $key => $method) { echo '<li><a href="' . $url . '/' . $method . '">' . $method . '</a></li>'; } echo '</ul><hr>'; if ($email && in_array($email, $this->previewableEmails)) { $order = Order::get()->first(); $notifier = OrderEmailNotifier::create($order)->setDebugMode(true); $method = "send{$email}"; echo $notifier->{$method}(); } else { } //this is a little hardcore way of ending the party, //but as it's only used for styling, it works for now die; }
/** * @param SS_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 != '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); } }
/** * Handles URL requests. * * - ViewableData::handleRequest() iterates through each rule in {@link self::$url_handlers}. * - If the rule matches, the named method will be called. * - If there is still more URL to be processed, then handleRequest() * is called on the object that that method returns. * * Once all of the URL has been processed, the final result is returned. * However, if the final result is an array, this * array is interpreted as being additional template data to customise the * 2nd to last result with, rather than an object * in its own right. This is most frequently used when a Controller's * action will return an array of data with which to * customise the controller. * * @param $request The {@link SS_HTTPRequest} object that is reponsible for distributing URL parsing * @uses SS_HTTPRequest * @uses SS_HTTPRequest->match() * @return SS_HTTPResponse|RequestHandler|string|array */ function handleRequest(SS_HTTPRequest $request, DataModel $model) { // $handlerClass is used to step up the class hierarchy to implement url_handlers inheritance $handlerClass = ($this->class) ? $this->class : get_class($this); if($this->brokenOnConstruct) { user_error("parent::__construct() needs to be called on {$handlerClass}::__construct()", E_USER_WARNING); } $this->request = $request; $this->setModel($model); // We stop after RequestHandler; in other words, at ViewableData while($handlerClass && $handlerClass != 'ViewableData') { $urlHandlers = Config::inst()->get($handlerClass, 'url_handlers', Config::FIRST_SET); if($urlHandlers) foreach($urlHandlers as $rule => $action) { if(isset($_REQUEST['debug_request'])) Debug::message("Testing '$rule' with '" . $request->remaining() . "' on $this->class"); if($params = $request->match($rule, true)) { // Backwards compatible setting of url parameters, please use SS_HTTPRequest->latestParam() instead //Director::setUrlParams($request->latestParams()); if(isset($_REQUEST['debug_request'])) { Debug::message("Rule '$rule' matched to action '$action' on $this->class. Latest request params: " . var_export($request->latestParams(), true)); } // Actions can reference URL parameters, eg, '$Action/$ID/$OtherID' => '$Action', if($action[0] == '$') $action = $params[substr($action,1)]; if($this->checkAccessAction($action)) { if(!$action) { if(isset($_REQUEST['debug_request'])) Debug::message("Action not set; using default action method name 'index'"); $action = "index"; } else if(!is_string($action)) { user_error("Non-string method name: " . var_export($action, true), E_USER_ERROR); } try { if(!$this->hasMethod($action)) { return $this->httpError(404, "Action '$action' isn't available on class " . get_class($this) . "."); } $result = $this->$action($request); } catch(SS_HTTPResponse_Exception $responseException) { $result = $responseException->getResponse(); } } else { return $this->httpError(403, "Action '$action' isn't allowed on class " . get_class($this) . "."); } if($result instanceof SS_HTTPResponse && $result->isError()) { if(isset($_REQUEST['debug_request'])) Debug::message("Rule resulted in HTTP error; breaking"); return $result; } // If we return a RequestHandler, call handleRequest() on that, even if there is no more URL to parse. // It might have its own handler. However, we only do this if we haven't just parsed an empty rule ourselves, // to prevent infinite loops. Also prevent further handling of controller actions which return themselves // to avoid infinite loops. if($this !== $result && !$request->isEmptyPattern($rule) && is_object($result) && $result instanceof RequestHandler) { $returnValue = $result->handleRequest($request, $model); // Array results can be used to handle if(is_array($returnValue)) $returnValue = $this->customise($returnValue); return $returnValue; // If we return some other data, and all the URL is parsed, then return that } else if($request->allParsed()) { return $result; // But if we have more content on the URL and we don't know what to do with it, return an error. } else { return $this->httpError(404, "I can't handle sub-URLs of a $this->class object."); } return $this; } } $handlerClass = get_parent_class($handlerClass); } // If nothing matches, return this object return $this; }
/** * */ 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')); }