mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-09-08 10:41:25 +02:00
Merge remote branch 'origin/master' into translation-staging
This commit is contained in:
commit
fbaf743274
@ -283,7 +283,8 @@ class RequestHandler extends ViewableData {
|
|||||||
return true;
|
return true;
|
||||||
} elseif(substr($test, 0, 2) == '->') {
|
} elseif(substr($test, 0, 2) == '->') {
|
||||||
// Case 2: Determined by custom method with "->" prefix
|
// Case 2: Determined by custom method with "->" prefix
|
||||||
return $this->{substr($test, 2)}();
|
list($method, $arguments) = Object::parse_class_spec(substr($test, 2));
|
||||||
|
return call_user_func_array(array($this, $method), $arguments);
|
||||||
} else {
|
} else {
|
||||||
// Case 3: Value is a permission code to check the current member against
|
// Case 3: Value is a permission code to check the current member against
|
||||||
return Permission::check($test);
|
return Permission::check($test);
|
||||||
|
@ -113,6 +113,48 @@ will are assumed to be relative to the site-root.
|
|||||||
The `redirect()` method takes an optional HTTP status code,
|
The `redirect()` method takes an optional HTTP status code,
|
||||||
either `301` for permanent redirects, or `302` for temporary redirects (default).
|
either `301` for permanent redirects, or `302` for temporary redirects (default).
|
||||||
|
|
||||||
|
## Access control
|
||||||
|
|
||||||
|
You can also limit access to actions on a controller using the static `$allowed_actions` array. This allows you to always allow an action, or restrict it to a specific permission or to call a method that checks if the action is allowed.
|
||||||
|
|
||||||
|
For example, the default `Controller::$allowed_actions` is
|
||||||
|
static $allowed_actions = array(
|
||||||
|
'handleAction',
|
||||||
|
'handleIndex',
|
||||||
|
);
|
||||||
|
which allows the `handleAction` and `handleIndex` methods to be called via a URL.
|
||||||
|
|
||||||
|
To allow any action on your controller to be called you can either leave your `$allowed_actions` array empty or not have one at all. This is the default behaviour, however it is not recommended as it allows anything on your controller to be called via a URL, including view-specific methods.
|
||||||
|
|
||||||
|
The recommended approach is to explicitly state the actions that can be called via a URL. Any action not in the `$allowed_actions` array, excluding the default `index` method, is then unable to be called.
|
||||||
|
|
||||||
|
To always allow an action to be called, you can either add the name of the action to the array or add a value of `true` to the array, using the name of the method as its index. For example
|
||||||
|
static $allowed_actions = array(
|
||||||
|
'MyAwesomeAction',
|
||||||
|
'MyOtherAction' => true
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
To require that the current user has a certain permission before being allowed to call an action you add the action to the array as an index with the value being the permission code that user must have. For example
|
||||||
|
static $allowed_actions = array(
|
||||||
|
'MyAwesomeAction',
|
||||||
|
'MyOtherAction' => true,
|
||||||
|
'MyLimitedAction' => 'CMS_ACCESS_CMSMain',
|
||||||
|
'MyAdminAction' => 'ADMIN'
|
||||||
|
);
|
||||||
|
|
||||||
|
If neither of these are enough to decide if an action should be called, you can have the check use a method. The method must be on the controller class and return true if the action is allowed or false if it isn't. To do this add the action to the array as an index with the value being the name of the method to called preceded by '->'. You are able to pass static arguments to the method in much the same way as you can with extensions. Strings are enclosed in quotes, numeric values are written as numbers and true and false are written as true and false. For example
|
||||||
|
static $allowed_actions = array(
|
||||||
|
'MyAwesomeAction',
|
||||||
|
'MyOtherAction' => true,
|
||||||
|
'MyLimitedAction' => 'CMS_ACCESS_CMSMain',
|
||||||
|
'MyAdminAction' => 'ADMIN',
|
||||||
|
'MyRestrictedAction' => '->myCheckerMethod("MyRestrictedAction", false, 42)',
|
||||||
|
'MyLessRestrictedAction' => '->myCheckerMethod'
|
||||||
|
);
|
||||||
|
|
||||||
|
In this example, `MyAwesomeAction` and `MyOtherAction` are always allowed, `MyLimitedAction` requires access to the CMS for the current user and `MyAdminAction` requires the current user to be an admin. `MyRestrictedAction` calls the method `myCheckerMethod`, passing in the string "MyRestrictedAction", the boolean false and the number 42. `MyLessRestrictedAction` simply calls the method `myCheckerMethod` with no arguments.
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
`[api:Controller]`
|
`[api:Controller]`
|
||||||
|
@ -533,7 +533,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
|||||||
/**
|
/**
|
||||||
* Return a new DataList instance with an inner join clause added to this list's query.
|
* Return a new DataList instance with an inner join clause added to this list's query.
|
||||||
*
|
*
|
||||||
* @param string $table Table name (unquoted)
|
* @param string $table Table name (unquoted and as escaped SQL)
|
||||||
* @param string $onClause Escaped SQL statement, e.g. '"Table1"."ID" = "Table2"."ID"'
|
* @param string $onClause Escaped SQL statement, e.g. '"Table1"."ID" = "Table2"."ID"'
|
||||||
* @param string $alias - if you want this table to be aliased under another name
|
* @param string $alias - if you want this table to be aliased under another name
|
||||||
* @return DataList
|
* @return DataList
|
||||||
@ -547,7 +547,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
|||||||
/**
|
/**
|
||||||
* Return a new DataList instance with a left join clause added to this list's query.
|
* Return a new DataList instance with a left join clause added to this list's query.
|
||||||
*
|
*
|
||||||
* @param string $table Table name (unquoted)
|
* @param string $table Table name (unquoted and as escaped SQL)
|
||||||
* @param string $onClause Escaped SQL statement, e.g. '"Table1"."ID" = "Table2"."ID"'
|
* @param string $onClause Escaped SQL statement, e.g. '"Table1"."ID" = "Table2"."ID"'
|
||||||
* @param string $alias - if you want this table to be aliased under another name
|
* @param string $alias - if you want this table to be aliased under another name
|
||||||
* @return DataList
|
* @return DataList
|
||||||
|
@ -874,7 +874,7 @@ class SQLQuery {
|
|||||||
else $filter = "(" . implode(") AND (", $join['filter']) . ")";
|
else $filter = "(" . implode(") AND (", $join['filter']) . ")";
|
||||||
|
|
||||||
$aliasClause = ($alias != $join['table']) ? " AS \"" . Convert::raw2sql($alias) . "\"" : "";
|
$aliasClause = ($alias != $join['table']) ? " AS \"" . Convert::raw2sql($alias) . "\"" : "";
|
||||||
$this->from[$alias] = strtoupper($join['type']) . " JOIN \"" . Convert::raw2sql($join['table']) . "\"$aliasClause ON $filter";
|
$this->from[$alias] = strtoupper($join['type']) . " JOIN \"" . $join['table'] . "\"$aliasClause ON $filter";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,13 @@ class RequestHandlingTest extends FunctionalTest {
|
|||||||
$response = Director::test("RequestHandlingTest_AllowedController/extendedMethod");
|
$response = Director::test("RequestHandlingTest_AllowedController/extendedMethod");
|
||||||
$this->assertEquals("extendedMethod", $response->getBody());
|
$this->assertEquals("extendedMethod", $response->getBody());
|
||||||
|
|
||||||
|
/* This action has been blocked by an argument to a method */
|
||||||
|
$response = Director::test('RequestHandlingTest_AllowedController/blockMethod');
|
||||||
|
$this->assertEquals(403, $response->getStatusCode());
|
||||||
|
|
||||||
|
/* Whereas this one has been allowed by a method without an argument */
|
||||||
|
$response = Director::test('RequestHandlingTest_AllowedController/allowMethod');
|
||||||
|
$this->assertEquals('allowMethod', $response->getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHTTPException() {
|
public function testHTTPException() {
|
||||||
@ -411,6 +418,8 @@ class RequestHandlingTest_AllowedController extends Controller implements TestOn
|
|||||||
static $allowed_actions = array(
|
static $allowed_actions = array(
|
||||||
'failoverMethod', // part of the failover object
|
'failoverMethod', // part of the failover object
|
||||||
'extendedMethod', // part of the RequestHandlingTest_ControllerExtension object
|
'extendedMethod', // part of the RequestHandlingTest_ControllerExtension object
|
||||||
|
'blockMethod' => '->provideAccess(false)',
|
||||||
|
'allowMethod' => '->provideAccess',
|
||||||
);
|
);
|
||||||
|
|
||||||
static $extensions = array(
|
static $extensions = array(
|
||||||
@ -426,6 +435,18 @@ class RequestHandlingTest_AllowedController extends Controller implements TestOn
|
|||||||
function index($request) {
|
function index($request) {
|
||||||
return "This is the controller";
|
return "This is the controller";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function provideAccess($access = true) {
|
||||||
|
return $access;
|
||||||
|
}
|
||||||
|
|
||||||
|
function blockMethod($request) {
|
||||||
|
return 'blockMethod';
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowMethod($request) {
|
||||||
|
return 'allowMethod';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,6 +85,14 @@ class DataListTest extends SapphireTest {
|
|||||||
$list->leftJoin('DataObjectTest_Team', '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"', 'Team');
|
$list->leftJoin('DataObjectTest_Team', '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"', 'Team');
|
||||||
$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", "DataObjectTest_TeamComment"."Created", "DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", "DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL THEN "DataObjectTest_TeamComment"."ClassName" ELSE '.$db->prepStringForDB('DataObjectTest_TeamComment').' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN "DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"';
|
$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", "DataObjectTest_TeamComment"."Created", "DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", "DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL THEN "DataObjectTest_TeamComment"."ClassName" ELSE '.$db->prepStringForDB('DataObjectTest_TeamComment').' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN "DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"';
|
||||||
$this->assertEquals($expected, $list->sql());
|
$this->assertEquals($expected, $list->sql());
|
||||||
|
|
||||||
|
// Test with namespaces (with non-sensical join, but good enough for testing)
|
||||||
|
$list = DataObjectTest_TeamComment::get();
|
||||||
|
$list->leftJoin('DataObjectTest\NamespacedClass', '"DataObjectTest\NamespacedClass"."ID" = "DataObjectTest_TeamComment"."ID"');
|
||||||
|
$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", "DataObjectTest_TeamComment"."Created", "DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", "DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL THEN "DataObjectTest_TeamComment"."ClassName" ELSE '.$db->prepStringForDB('DataObjectTest_TeamComment').' END AS "RecordClassName" ' .
|
||||||
|
'FROM "DataObjectTest_TeamComment" ' .
|
||||||
|
'LEFT JOIN "DataObjectTest\NamespacedClass" ON "DataObjectTest\NamespacedClass"."ID" = "DataObjectTest_TeamComment"."ID"';
|
||||||
|
$this->assertEquals($expected, $list->sql(), 'Retains backslashes in namespaced classes');
|
||||||
}
|
}
|
||||||
|
|
||||||
function testToNestedArray() {
|
function testToNestedArray() {
|
||||||
|
Loading…
Reference in New Issue
Block a user