2011-02-07 07:48:44 +01:00
# Controller
2012-06-30 05:19:36 +02:00
Base controller class. You will extend this to take granular control over the
actions and url handling of aspects of your SilverStripe site.
2011-02-07 07:48:44 +01:00
2013-01-28 22:35:32 +01:00
## Usage
2011-02-07 07:48:44 +01:00
2012-06-30 05:19:36 +02:00
The following example is for a simple `[api:Controller]` class. If you're using
the cms module and looking at Page_Controller instances you won't need to setup
your own routes since the cms module handles these routes.
2011-03-08 22:05:51 +01:00
`mysite/code/Controllers/FastFood.php`
2011-02-07 07:48:44 +01:00
:::php
< ?php
class FastFood_Controller extends Controller {
2013-01-28 22:35:32 +01:00
public static $allowed_actions = array('order');
2013-01-28 22:35:32 +01:00
public function order(SS_HTTPRequest $request) {
2011-02-07 07:48:44 +01:00
print_r($arguments);
}
}
2013-01-28 22:35:32 +01:00
## Routing
2012-06-30 05:19:36 +02:00
`mysite/_config/routes.yml`
2011-02-07 07:48:44 +01:00
2012-06-30 05:19:36 +02:00
:::yaml
---
Name: myroutes
After: framework/routes#coreroutes
---
Director:
2012-12-06 20:15:53 +01:00
rules:
'fastfood/$Action/$ID/$Name': 'FastFood_Controller'
2011-02-07 07:48:44 +01:00
2012-06-30 05:19:36 +02:00
Request for `/fastfood/order/24/cheesefries` would result in the following to
the $arguments above. If needed, use `?flush=1` on the end of request after
making any code changes to your controller.
2011-02-07 07:48:44 +01:00
:::ss
Array
(
[Action] => order
[ID] => 24
[Name] => cheesefries
)
2013-01-28 22:35:32 +01:00
< div class = "warning" markdown = '1' >
SilverStripe automatically adds a URL routing entry based on the controller's class name,
so a `MyController` class is accessible through `http://yourdomain.com/MyController` .
< / div >
## Access Control
### Through $allowed_actions
All public methods on a controller are accessible by their name through the `$Action`
part of the URL routing, so a `MyController->mymethod()` is accessible at
`http://yourdomain.com/MyController/mymethod` . This is not always desireable,
since methods can return internal information, or change state in a way
that's not intended to be used through a URL endpoint.
SilverStripe strongly recommends securing your controllers
through defining a `$allowed_actions` array on the class,
which allows whitelisting of methods, as well as a concise
way to perform checks against permission codes or custom logic.
:::php
class MyController extends Controller {
public static $allowed_actions = array(
// someaction can be accessed by anyone, any time
'someaction',
// So can otheraction
'otheraction' => true,
// restrictedaction can only be people with ADMIN privilege
'restrictedaction' => 'ADMIN',
// complexaction can only be accessed if $this->canComplexAction() returns true
'complexaction' '->canComplexAction'
);
}
There's a couple of rules guiding these checks:
* Each controller is only responsible for access control on the methods it defines
* If a method on a parent class is overwritten, access control for it has to be redefined as well
* An action named "index" is whitelisted by default
* A wildcard (`*`) can be used to define access control for all methods (incl. methods on parent classes)
* Specific method entries in `$allowed_actions` overrule any `*` settings
* Methods returning forms also count as actions which need to be defined
* Form action methods (targets of `FormAction` ) should NOT be included in `$allowed_actions` ,
they're handled separately through the form routing (see the ["forms" topic ](/topics/forms ))
* `$allowed_actions` can be defined on `Extension` classes applying to the controller.
If the permission check fails, SilverStripe will return a "403 Forbidden" HTTP status.
### Through the action
Each method responding to a URL can also implement custom permission checks,
e.g. to handle responses conditionally on the passed request data.
:::php
class MyController extends Controller {
public static $allowed_actions = array('myaction');
public function myaction($request) {
if(!$request->getVar('apikey')) {
return $this->httpError(403, 'No API key provided');
}
return 'valid';
}
}
Unless you transform the response later in the request processing,
it'll look pretty ugly to the user. Alternatively, you can use
`ErrorPage::response_for(<status-code>)` to return a more specialized layout.
Note: This is recommended as an addition for `$allowed_actions` , in order to handle
more complex checks, rather than a replacement.
### Through the init() method
After checking for allowed_actions, each controller invokes its `init()` method,
which is typically used to set up common state in the controller, and
include JavaScript and CSS files in the output which are used for any action.
If an `init()` method returns a `SS_HTTPResponse` with either a 3xx or 4xx HTTP
status code, it'll abort execution. This behaviour can be used to implement
permission checks.
:::php
class MyController extends Controller {
public static $allowed_actions = array();
public function init() {
parent::init();
if(!Permission::check('ADMIN')) return $this->httpError(403);
}
}
2011-02-07 07:48:44 +01:00
## URL Handling
2012-06-30 05:19:36 +02:00
In the above example the URLs were configured using the `[api:Director]` rules
in the **routes.yml** file. Alternatively you can specify these in your
Controller class via the ** $url_handlers** static array (which gets processed
by the `[api:RequestHandler]` ).
2011-02-07 07:48:44 +01:00
2012-06-30 05:19:36 +02:00
This is useful when you want to subvert the fixed action mapping of `fastfood/order/*`
to the function **order** . In the case below we also want any orders coming
through `/fastfood/drivethrough/` to use the same order function.
2011-02-07 07:48:44 +01:00
2011-03-08 22:05:51 +01:00
`mysite/code/Controllers/FastFood.php`
2011-02-07 07:48:44 +01:00
:::php
class FastFood_Controller extends Controller {
2013-01-28 22:35:32 +01:00
static $allowed_actions = array('drivethrough');
2011-02-07 07:48:44 +01:00
public static $url_handlers = array(
2012-06-30 05:19:36 +02:00
'drivethrough/$Action/$ID/$Name' => 'order'
);
2011-02-07 07:48:44 +01:00
## URL Patterns
2012-06-30 05:19:36 +02:00
The `[api:RequestHandler]` class will parse all rules you specify against the
following patterns.
2011-02-07 07:48:44 +01:00
2012-06-30 05:19:36 +02:00
**A rule must always start with alphabetical ([A-Za-z]) characters or a $Variable
declaration**
2011-02-07 07:48:44 +01:00
2011-03-08 22:05:51 +01:00
| Pattern | Description |
| ----------- | --------------- |
| `$` | **Param Variable** - Starts the name of a paramater variable, it is optional to match this unless ! is used |
| `!` | **Require Variable** - Placing this after a parameter variable requires data to be present for the rule to match |
| `//` | **Shift Point** - Declares that only variables denoted with a $ are parsed into the $params AFTER this point in the regex |
2011-02-07 07:48:44 +01:00
## Examples
See maetl's article in the Links below of a detailed explanation.
`$Action/$ID/$OtherID` - Standard URL handler for a Controller. Take whatever `URLSegment` it is set to, find
the Action to match a function in the controller, and parse two optional `$param` variables that will be named `ID` and
`OtherID` .
`admin/help//$Action/$ID` - Match an url starting with `/admin/help/` , but don't include `/help/` as part of the
action (the shift point is set to start parsing variables and the appropriate controller action AFTER the `//` )
`tag/$Tag!` - Match an URL starting with `/tag/` after the controller's `URLSegment` and require it to have something
after it. If the URLSegment is **order** then `/order/tag/34` and `/order/tag/asdf` match but `/order/tag/` will not
You can use the `debug_request=1` switch from the [urlvariabletools ](/reference/urlvariabletools ) to see these in action.
2012-06-28 11:43:56 +02:00
## Redirection
Controllers facilitate HTTP redirection.
2012-06-30 05:19:36 +02:00
2012-06-28 11:43:56 +02:00
Note: These methods have been formerly located on the `[api:Director]` class.
* `redirect("action-name")` : If there's no slash in the URL passed to redirect, then it is assumed that you want to go to a different action on the current controller.
* `redirect("relative/url")` : If there is a slash in the URL, it's taken to be a normal URL. Relative URLs
will are assumed to be relative to the site-root.
* `redirect("http://www.absoluteurl.com")` : Of course, you can pass `redirect()` absolute URLs too.
* `redirectBack()` : This will return you to the previous page.
The `redirect()` method takes an optional HTTP status code,
either `301` for permanent redirects, or `302` for temporary redirects (default).
2011-02-07 07:48:44 +01:00
## API Documentation
`[api:Controller]`
## Links
* `[api:Director]` class
* [execution-pipeline ](/reference/execution-pipeline )
* [URL Handling in Controllers ](http://maetl.net/silverstripe-url-handling ) by maetl