NEW Admin url can now be customized

The default 'admin/' base URL can now be changed with Director rules
This commit is contained in:
Thierry François 2014-07-05 14:13:01 +03:00 committed by Thierry Francois
parent 392536cb17
commit 533d5dbd4b
13 changed files with 123 additions and 45 deletions

View File

@ -4,15 +4,47 @@
* @package framework
* @subpackage admin
*/
class AdminRootController extends Controller {
class AdminRootController extends Controller implements TemplateGlobalProvider {
/**
* @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
* Convenience function to return the admin route config.
* Looks for the {@link Director::$rules} for the current admin Controller.
*/
private static $url_base = 'admin';
public static function get_admin_route() {
if (Controller::has_curr()) {
$routeParams = Controller::curr()->getRequest()->routeParams();
$adminControllerClass = isset($routeParams['Controller']) ? $routeParams['Controller'] : get_called_class();
}
else {
$adminControllerClass = get_called_class();
}
$rules = Config::inst()->get('Director', 'rules');
$adminRoute = array_search($adminControllerClass, $rules);
return $adminRoute ? $adminRoute : '';
}
/**
* Returns the root admin URL for the site with trailing slash
*
* @return string
* @uses get_admin_route()
*/
public static function admin_url() {
return self::get_admin_route() . '/';
}
/**
* Includes the adminURL JavaScript config in the ss namespace
*/
public static function include_js() {
$js = "(function(root) {
root.ss = root.ss || {};
root.ss.config = root.ss.config || {};
root.ss.config.adminURL = '".self::admin_url()."'
}(window));";
Requirements::customScript($js, 'adminURLConfig');
}
/**
* @var string
@ -74,11 +106,10 @@ class AdminRootController extends Controller {
public 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));
$this->redirect(Controller::join_links(self::admin_url(), $segment));
return $this->response;
}
@ -97,4 +128,14 @@ class AdminRootController extends Controller {
return $this->httpError(404, 'Not found');
}
/**
* @return array Returns an array of strings of the method names of methods on the call that should be exposed
* as global variables in the templates.
*/
public static function get_template_global_variables() {
return array(
'adminURL' => 'admin_url'
);
}
}

View File

@ -57,7 +57,7 @@ class CMSMenu extends Object implements IteratorAggregate, i18nEntityProvider {
* Return a CMSMenuItem to add the given controller to the CMSMenu
*/
protected static function menuitem_for_controller($controllerClass) {
$urlBase = Config::inst()->get($controllerClass, 'url_base', Config::FIRST_SET);
$urlBase = AdminRootController::admin_url();
$urlSegment = Config::inst()->get($controllerClass, 'url_segment', Config::FIRST_SET);
$menuPriority = Config::inst()->get($controllerClass, 'menu_priority', Config::FIRST_SET);

View File

@ -11,16 +11,6 @@
*/
class LeftAndMain extends Controller implements PermissionProvider {
/**
* The 'base' url for CMS administration areas.
* Note that if this is changed, many javascript
* behaviours need to be updated with the correct url
*
* @config
* @var string $url_base
*/
private static $url_base = "admin";
/**
* The current url segment attached to the LeftAndMain instance
*
@ -340,6 +330,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
if (Director::isDev()) Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/leaktools.js');
HTMLEditorField::include_js();
AdminRootController::include_js();
$leftAndMainIncludes = array_unique(array_merge(
array(
@ -527,7 +518,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
};
$link = Controller::join_links(
$this->stat('url_base', true),
AdminRootController::admin_url(),
$segment,
'/', // trailing slash needed if $action is null!
"$action"
@ -642,7 +633,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
// default menu is the one with a blank {@link url_segment}
} else if(singleton($menuItem->controller)->stat('url_segment') == '') {
if($this->Link() == $this->stat('url_base').'/') {
if($this->Link() == AdminRootController::admin_url()) {
$linkingmode = "current";
}

View File

@ -333,7 +333,7 @@
/**
* Publish selected pages action
*/
$('#Form_BatchActionsForm').register('admin/batchactions/publish', function(ids) {
$('#Form_BatchActionsForm').register(ss.config.adminURL+'batchactions/publish', function(ids) {
var confirmed = confirm(
"You have " + ids.length + " pages selected.\n\n"
+ "Do your really want to publish?"
@ -344,7 +344,7 @@
/**
* Unpublish selected pages action
*/
$('#Form_BatchActionsForm').register('admin/batchactions/unpublish', function(ids) {
$('#Form_BatchActionsForm').register(ss.config.adminURL+'batchactions/unpublish', function(ids) {
var confirmed = confirm(
"You have " + ids.length + " pages selected.\n\n"
+ "Do your really want to unpublish?"
@ -355,7 +355,7 @@
/**
* Delete selected pages action
*/
$('#Form_BatchActionsForm').register('admin/batchactions/delete', function(ids) {
$('#Form_BatchActionsForm').register(ss.config.adminURL+'batchactions/delete', function(ids) {
var confirmed = confirm(
"You have " + ids.length + " pages selected.\n\n"
+ "Do your really want to delete?"
@ -366,7 +366,7 @@
/**
* Delete selected pages from live action
*/
$('#Form_BatchActionsForm').register('admin/batchactions/deletefromlive', function(ids) {
$('#Form_BatchActionsForm').register(ss.config.adminURL+'batchactions/deletefromlive', function(ids) {
var confirmed = confirm(
"You have " + ids.length + " pages selected.\n\n"
+ "Do your really want to delete these pages from live?"

View File

@ -12,7 +12,7 @@
<% with $CurrentMember %>
<span>
<% _t('LeftAndMain_Menu_ss.Hello','Hi') %>
<a href="{$AbsoluteBaseURL}admin/myprofile" class="profile-link">
<a href="{$AbsoluteBaseURL}{$AdminURL}myprofile" class="profile-link">
<% if $FirstName && $Surname %>$FirstName $Surname<% else_if $FirstName %>$FirstName<% else %>$Email<% end_if %>
</a>
</span>

View File

@ -351,12 +351,14 @@ class Director implements TemplateGlobalProvider {
if(isset($_REQUEST['debug'])) Debug::show($rules);
foreach($rules as $pattern => $controllerOptions) {
if(is_string($controllerOptions)) {
if(is_string($controllerOptions) && $controllerOptions) {
if(substr($controllerOptions,0,2) == '->') {
$controllerOptions = array('Redirect' => substr($controllerOptions,2));
} else {
$controllerOptions = array('Controller' => $controllerOptions);
}
} else {
continue;
}
if(($arguments = $request->match($pattern, true)) !== false) {

View File

@ -135,7 +135,6 @@ if(Director::isLive()) {
*/
Debug::loadErrorHandlers();
///////////////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS

View File

@ -15,6 +15,42 @@ with some special conventions.
For a more practical-oriented approach to CMS customizations, refer to the
[Howto: Extend the CMS Interface](../how_tos/extend_cms_interface) which builds
## The Admin URL
The CMS interface can be accessed by default through the `admin/` URL. You can change this by setting your own [Director routing rule](director#routing-rules) to the `[api:AdminRootController]` and clear the old rule like in the example below.
:::yml
---
Name: myadmin
After:
- '#adminroutes'
---
Director:
rule:
'admin': ''
'newAdmin': 'AdminRootController'
---
When extending the CMS or creating modules, you can take advantage of various functions that will return the configured admin URL (by default 'admin/' is returned):
In PHP you should use:
:::php
AdminRootController::admin_url()
When writing templates use:
:::ss
$AdminURL
And in JavaScript, this is avaible through the `ss` namespace
:::js
ss.config.adminURL
### Multiple Admin URL and overrides
You can also create your own classes that extend the `[api:AdminRootController]` to create multiple or custom admin areas, with a `Director.rules` for each one.
## Markup and Style Conventions
@ -257,7 +293,7 @@ in a single Ajax request.
<% include CMSBreadcrumbs %>
<div>Static content (not affected by update)</div>
<% include MyRecordInfo %>
<a href="admin/myadmin" class="cms-panel-link" data-pjax-target="MyRecordInfo,Breadcrumbs">
<a href="{$AdminURL}myadmin" class="cms-panel-link" data-pjax-target="MyRecordInfo,Breadcrumbs">
Update record info
</a>
@ -285,7 +321,7 @@ On the client, you can set your preference through the `data-pjax-target` attrib
on links or through the `X-Pjax` header. For firing off an Ajax request that is
tracked in the browser history, use the `pjax` attribute on the state data.
$('.cms-container').loadPanel('admin/pages', null, {pjax: 'Content'});
$('.cms-container').loadPanel(ss.config.adminURL+'pages', null, {pjax: 'Content'});
## Loading lightweight PJAX fragments
@ -301,16 +337,16 @@ unrelated to the main flow.
In this case you can use the `loadFragment` call supplied by `LeftAndMain.js`. You can trigger as many of these in
parallel as you want. This will not disturb the main navigation.
$('.cms-container').loadFragment('admin/foobar/', 'Fragment1');
$('.cms-container').loadFragment('admin/foobar/', 'Fragment2');
$('.cms-container').loadFragment('admin/foobar/', 'Fragment3');
$('.cms-container').loadFragment(ss.config.adminURL+'foobar/', 'Fragment1');
$('.cms-container').loadFragment(ss.config.adminURL+'foobar/', 'Fragment2');
$('.cms-container').loadFragment(ss.config.adminURL+'foobar/', 'Fragment3');
The ongoing requests are tracked by the PJAX fragment name (Fragment1, 2, and 3 above) - resubmission will
result in the prior request for this fragment to be aborted. Other parallel requests will continue undisturbed.
You can also load multiple fragments in one request, as long as they are to the same controller (i.e. URL):
$('.cms-container').loadFragment('admin/foobar/', 'Fragment2,Fragment3');
$('.cms-container').loadFragment(ss.config.adminURL+'foobar/', 'Fragment2,Fragment3');
This counts as a separate request type from the perspective of the request tracking, so will not abort the singular
`Fragment2` nor `Fragment3`.
@ -331,7 +367,7 @@ You can hook up a response handler that obtains all the details of the XHR reque
Alternatively you can use the jQuery deferred API:
$('.cms-container')
.loadFragment('admin/foobar/', 'Fragment1')
.loadFragment(ss.config.adminURL+'foobar/', 'Fragment1')
.success(function(data, status, xhr) {
// Say 'success'!
alert(status);
@ -519,19 +555,19 @@ and load the HTML content into the main view. Example:
<div id="my-tab-id" class="cms-tabset" data-ignore-tab-state="true">
<ul>
<li class="<% if MyActiveCondition %> ui-tabs-active<% end_if %>">
<a href="admin/mytabs/tab1" class="cms-panel-link">
<a href="{$AdminURL}mytabs/tab1" class="cms-panel-link">
Tab1
</a>
</li>
<li class="<% if MyActiveCondition %> ui-tabs-active<% end_if %>">
<a href="admin/mytabs/tab2" class="cms-panel-link">
<a href="{$AdminURL}mytabs/tab2" class="cms-panel-link">
Tab2
</a>
</li>
</ul>
</div>
The URL endpoints `admin/mytabs/tab1` and `admin/mytabs/tab2`
The URL endpoints `{$AdminURL}mytabs/tab1` and `{$AdminURL}mytabs/tab2`
should return HTML fragments suitable for inserting into the content area,
through the `PjaxResponseNegotiator` class (see above).

View File

@ -26,7 +26,7 @@ code like this:
...
<li id="record-15" class="class-Page closed jstree-leaf jstree-unchecked" data-id="15">
<ins class="jstree-icon">&nbsp;</ins>
<a class="" title="Page type: Page" href="admin/page/edit/show/15">
<a class="" title="Page type: Page" href="{$AdminURL}page/edit/show/15">
<ins class="jstree-checkbox">&nbsp;</ins>
<ins class="jstree-icon">&nbsp;</ins>
<span class="text">

View File

@ -33,10 +33,10 @@ the CMS logic. Add a new section into the `<ul class="cms-menu-list">`
<ul class="cms-menu-list">
<!-- ... -->
<li class="bookmarked-link first">
<a href="admin/pages/edit/show/1">Edit "My popular page"</a>
<a href="{$AdminURL}pages/edit/show/1">Edit "My popular page"</a>
</li>
<li class="bookmarked-link last">
<a href="admin/pages/edit/show/99">Edit "My other page"</a>
<a href="{$AdminURL}pages/edit/show/99">Edit "My other page"</a>
</li>
</ul>
...
@ -130,7 +130,7 @@ and replace it with the following:
<!-- ... -->
<% loop $BookmarkedPages %>
<li class="bookmarked-link $FirstLast">
<li><a href="admin/pages/edit/show/$ID">Edit "$Title"</a></li>
<li><a href="{$AdminURL}pages/edit/show/$ID">Edit "$Title"</a></li>
</li>
<% end_loop %>
</ul>

View File

@ -17,6 +17,7 @@
* `Mailer` no longer calls `xml2raw` on all email subject line, and now must be passed in via plain text.
* `ErrorControlChain` now supports reload on exceptions
* `FormField::validate` now requires an instance of `Validator`
* Admin URL can now be configured via custom Director routing rule
#### Deprecated classes/methods removed
@ -124,6 +125,14 @@ languages like JavaScript won't be able to read them.
To set it back to be non-HTTP only, you need to set the `$httpOnly` argument to false when calling
`Cookie::set()`.
### Admin URL can now be configured via custom Director routing rule
The default `admin/` URL to access the CMS interface can now be changed
via a custom Director routing rule for `AdminRootController`. If your website or module
has hard coded `admin` URLs in PHP, templates or JavaScript, make sure to update those
with the appropriate function or config call.
See [CMS architecture](/developer_guides/customising_the_admin_interface/cms-architecture#the-admin-url) for language specific functions.
### Bugfixes
* Migration of code to use new parameterised framework

View File

@ -748,7 +748,7 @@ class File extends DataObject {
* @todo Coupling with cms module, remove this method.
*/
public function DeleteLink() {
return Director::absoluteBaseURL()."admin/assets/removefile/".$this->ID;
return Director::absoluteBaseURL().AdminRootController::admin_url()."assets/removefile/".$this->ID;
}
public function getFilename() {