API CHANGE: Changes to make Director rules set through the new config system. Includes the addition of a new AdminRootController to take over handling of routing /admin/* routes to the correct LeftAndMain panel.

This commit is contained in:
Hamish Friedlander 2012-05-19 14:36:48 +12:00
parent 8e9ae37719
commit 94f50f554e
6 changed files with 158 additions and 92 deletions

View File

@ -17,22 +17,6 @@
* @subpackage core
*/
// Default director
Director::addRules(10, array(
'Security//$Action/$ID/$OtherID' => 'Security',
//'Security/$Action/$ID' => 'Security',
'$Controller//$Action/$ID/$OtherID' => '*',
'api/v1/live' => 'VersionedRestfulServer',
'api/v1' => 'RestfulServer',
'soap/v1' => 'SOAPModelAccess',
'dev' => 'DevelopmentAdmin',
'interactive' => 'SapphireREPL',
));
// Add default routing unless 'cms' module is present (which overrules this with a CMSMain controller)
Director::addRules(20, array(
'admin//$action/$ID/$OtherID' => '->admin/security'
));
/**
* PHP 5.2 introduced a conflict with the Datetime field type, which was renamed to SSDatetime. This was later renamed
* to SS_Datetime to be consistent with other namespaced classes.

23
_config/routes.yml Normal file
View File

@ -0,0 +1,23 @@
---
Name: coreroutes
After: cms/routes#modelascontrollerroutes
Before: '*'
---
Director:
rules:
'Security//$Action/$ID/$OtherID': 'Security'
'$Controller//$Action/$ID/$OtherID': '*'
'api/v1/live': 'VersionedRestfulServer'
'api/v1': 'RestfulServer'
'soap/v1': 'SOAPModelAccess'
'dev': 'DevelopmentAdmin'
'interactive': 'SapphireREPL'
---
Name: adminroutes
After: framework/routes#coreroutes
---
Director:
rules:
'admin': 'AdminRootController'
'': 'RootURLController'
'dev/buildcache/$Action': 'RebuildStaticCacheTask'

View File

@ -1,14 +1,4 @@
<?php
Director::addRules(50, array(
'' => 'RootURLController',
'processes//$Action/$ID/$Batch' => 'BatchProcess_Controller',
'admin/help//$Action/$ID' => 'CMSHelp',
'admin/bulkload//$Action/$ID/$OtherID' => 'BulkLoaderAdmin',
'dev/buildcache/$Action' => 'RebuildStaticCacheTask',
));
CMSMenu::add_director_rules();
// Default CMS HTMLEditorConfig
HtmlEditorConfig::get('cms')->setOptions(array(
'friendly_name' => 'Default CMS',

View File

@ -0,0 +1,94 @@
<?php
class AdminRootController extends Controller {
/**
* @var string
* @config
* The url base that all LeftAndMain derived panels will live under
* Won't automatically update the base route if you change this - that has to be done seperately
*/
static $url_base = 'admin';
/**
* @var string
* @config
* The LeftAndMain child that will be used as the initial panel to display if none is selected (i.e. if you visit /admin)
*/
static $default_panel = 'SecurityAdmin';
/**
* @var array
* Holds an array of url_pattern => controller k/v pairs, the same as Director::rules. However this is built
* dynamically from introspecting on all the classes that derive from LeftAndMain.
*
* Don't access this directly - always access via the rules() accessor below, which will build this array
* the first time it's accessed
*/
private static $_rules = null;
/**
* Gets a list of url_pattern => controller k/v pairs for each LeftAndMain derived controller
*/
public static function rules() {
if (self::$_rules === null) {
self::$_rules = array();
// Build an array of class => url_priority k/v pairs
$classes = array();
foreach (CMSMenu::get_cms_classes() as $class) {
$classes[$class] = Config::inst()->get($class, 'url_priority', Config::FIRST_SET);
}
// Sort them so highest priority item is first
arsort($classes, SORT_NUMERIC);
// Map over the array calling add_rule_for_controller on each
array_map(array(__CLASS__, 'add_rule_for_controller'), array_keys($classes));
}
return self::$_rules;
}
/**
* Add the appropriate k/v pair to self::$rules for the given controller.
*/
protected static function add_rule_for_controller($controllerClass) {
$urlSegment = Config::inst()->get($controllerClass, 'url_segment', Config::FIRST_SET);
$urlRule = Config::inst()->get($controllerClass, 'url_rule', Config::FIRST_SET);
if($urlSegment || $controllerClass == 'CMSMain') {
// Make director rule
if($urlRule[0] == '/') $urlRule = substr($urlRule,1);
$rule = $urlSegment . '//' . $urlRule;
self::$_rules[$rule] = $controllerClass;
}
}
function handleRequest(SS_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()) {
$base = $this->config()->url_base;
$segment = Config::inst()->get($this->config()->default_panel, 'url_segment');
$this->response = new SS_HTTPResponse();
$this->redirect(Controller::join_links($base, $segment));
return $this->response;
}
// Otherwise
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);
}
}
}
}
}

View File

@ -34,13 +34,6 @@ class CMSMenu extends Object implements IteratorAggregate, i18nEntityProvider
self::$menu_is_cleared = false;
}
/**
* Add Director rules for all of the CMS controllers.
*/
public static function add_director_rules() {
array_map(array('self','add_director_rule_for_controller'), self::get_cms_classes());
}
/**
* Add a LeftAndMain controller to the CMS menu.
*
@ -76,27 +69,7 @@ class CMSMenu extends Object implements IteratorAggregate, i18nEntityProvider
return new CMSMenuItem($menuTitle, $link, $controllerClass, $menuPriority);
}
/**
* Add the appropriate Director rules for the given controller.
*/
protected static function add_director_rule_for_controller($controllerClass) {
$urlBase = Config::inst()->get($controllerClass, 'url_base', Config::FIRST_SET);
$urlSegment = Config::inst()->get($controllerClass, 'url_segment', Config::FIRST_SET);
$urlRule = Config::inst()->get($controllerClass, 'url_rule', Config::FIRST_SET);
$urlPriority = Config::inst()->get($controllerClass, 'url_priority', Config::FIRST_SET);
if($urlSegment || $controllerClass == 'CMSMain') {
$link = Controller::join_links($urlBase, $urlSegment) . '/';
// Make director rule
if($urlRule[0] == '/') $urlRule = substr($urlRule,1);
$rule = $link . '/' . $urlRule; // the / will combine with the / on the end of $link to make a //
Director::addRules($urlPriority, array(
$rule => $controllerClass
));
}
}
/**
* Add an arbitrary URL to the CMS menu.

View File

@ -41,7 +41,11 @@ class Director implements TemplateGlobalProvider {
* We recommend priority 100 for your site's rules. The built-in rules are priority 10, standard modules are priority 50.
*/
static function addRules($priority, $rules) {
Director::$rules[$priority] = isset(Director::$rules[$priority]) ? array_merge($rules, (array)Director::$rules[$priority]) : $rules;
if ($priority != 100) {
Deprecation::notice('3.0', 'Priority argument is now ignored - use the default of 100. You should really be setting routes via _config yaml fragments though.');
}
Config::inst()->update('Director', 'rules', $rules);
}
/**
@ -242,48 +246,46 @@ class Director implements TemplateGlobalProvider {
* @return SS_HTTPResponse|string
*/
protected static function handleRequest(SS_HTTPRequest $request, Session $session, DataModel $model) {
krsort(Director::$rules);
$rules = Config::inst()->get('Director', 'rules');
if(isset($_REQUEST['debug'])) Debug::show(Director::$rules);
foreach(Director::$rules as $priority => $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(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) {
// 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']);
}
if(($arguments = $request->match($pattern, true)) !== false) {
// 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;
// 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);
}
user_error("Bad result from url " . $request->getURL() . " handled by " .
get_class($controllerObj)." controller: ".get_class($result), E_USER_WARNING);
}
}
}