In an MVC application like IPS4, the job of the controller is to handle requests from users. They are, in effect, the middleman, requesting data from the models, doing necessarily processing, and handing it off to the view to display or otherwise output.
As discussed in Routing & URLs, methods in controllers map directly to a URL. When you visit a URL like community.com/index.php?app=core&module=messenger&controller=messenger, the controller at /applications/core/modules/front/messenger/messenger.php is initialized to handle the request.
All controllers exist in the /modules directory of an application. This directory has two sub-directories:
- /front - for modules that handle front-end (public) functionality
- /admin - for modules that handle admin control panel functionality
Admin controllers can only be accessed when the user is logged into an account with administrator permissions.
Anatomy of a controller
Here is a basic controller:
<?php namespace IPS\core\modules\front\example; class _example extends \IPS\Dispatcher\Controller { public function manage() { //... } public function otherMethod() { echo "Hello world"; //... } }
In this example, our controller is called example. As a result, it is saved in a file named example.php, which allows IPS4 to locate it. Our namespace should be IPS\<app>\modules\<location>\<module>, where app is the key of your app, location is either admin or front, and module is the name of the module this controller belongs to.
As discussed in Autoloading, the name of the controller class should be lowercase (matching the filename), and prefixed with an underscore; this allows IPS4 to properly locate and load your controller when needed.
At a minimum, controllers should extend \IPS\Dispatcher\Controller. There are other classes you can extend instead for additional functionality, which will be discussed later.
Methods inside a controller are request handlers, and are called when the do parameter in the URL matches the method name. In our example above, the URL community.com/index.php?app=core&module=example&controller=example&do=otherMethod would simply echo "Hello world".
Special methods
The execute method in a controller is run for every request to a handler in that controller. This means it's a good place to do any work that applies to all handlers - including CSS or JS files for the module, for example. If you define the execute method in your controller, you should always call the parent afterwards:
public function execute () { // Your work... parent::execute(); }
The manage method is the default handler in a controller. If no do parameter is present in the URL, then the manage method will be called.
Non-request methods
If your controller has methods that aren't request handlers (e.g. utility methods), you should prefix them with an underscore. These methods aren't accessible by URL like the standard methods.
protected function _someHelper () { // A method that our request handlers can call }
Advanced controllers
While most controllers will extend the \IPS\Dispatcher\Controller class, there are other controllers that may be extended instead to provide additional functionality (and they in turn extend \IPS\Dispatcher\Controller themselves). They include:
-
\IPS\Node\Controller
Handles functionality for nodes - tree-like data structures used extensively in IPS4 -
\IPS\Content\Controller
Additional functionality for IPS4's content items -
\IPS\Api\Controller
Handles API requests (this controller does not extend \IPS\Dispatcher\Controller)
These controllers will be discussed in more detail in later parts of this guide.
CSRF Protection
CSRF (Cross-site request forgery) is a type of web attack where a user is made to perform an action they did not intend to perform. In order to protect against this type of attack, a unique key is generated for each user and must be included with actions that make state changes, and then validated before those changes are saved. The Invision Community software makes it easy to do this.
Any URL that performs a state change (e.g. updates a value in the database or deletes a row in the database) should perform a CSRF check before making that change. The first step is to include the user's CSRF key in the URL to the controller handler. When using the \IPS\Http\Url class to generate a URL, you can do this easily by calling ->csrf() against the URL object. If you are generating the URL using a template helper, you can simply pass csrf="true" in the tag.
$url = \IPS\Http\Url::internal( "app=application&module=foo&controller=bar" )->csrf();
{url="app=application&module=foo&controller=bar" csrf="true"}
This will add a URL parameter &csrfKey=(unique key) to the URL, which you can then easily check in your controller method like so:
\IPS\Session::i()->csrfCheck();
This method will automatically show an error if the CSRF key is not valid.
That's all you have to do! Keep in mind this practice should be done for any state change (any time the database is altered by following a URL in the software).
Report Document