Plugins
1Presentation
It is possible to request the execution of plugins, before and/or after the execution of the application controllers. Technically, plugins are controllers with special methods, which can modify the request before passing it on to the next plugin or to the designated controller. You can chain plugins before the controller, and other plugins after.
The source files for plugins are stored in the controllers directory of the application.
The same object can have both plugin and controller roles.
Plugins provided by Temma
Temma provides several plugins, which documentation is available in the "Helpers" section:
2Configuration
The configuration of pre-plugins and post-plugins is done using the etc/temma.php file (see the configuration documentation). It is possible to configure global plugins, which will be executed for all requests:
<?php
return [
'plugins' => [
// list of pre-plugins
'_pre' => [
'AuthenticationPlugin',
'CmsController',
],
// list of post-plugins
'_post' => [
'CleanSessionPlugin'
]
]
];
Plugins are executed following the order in which they are declared.
It is possible to configure plugins that will only run for certain controllers:
<?php
return [
'plugins' => [
// plugins systematically executed for all controllers
'_pre' => [ 'AuthenticationPlugin', 'CmsController' ],
'_post' => [ 'CleanSessionPlugin' ],
// plugins called only for the homepage controller
'Homepage' => [
// plugins executed before the controller
'_pre' => [ 'SomePlugin', 'AnotherPlugin' ],
// plugins executed after the controller
'_post' => [ 'LastPlugin' ]
],
// plugins called only for the display controller
'Display' => [
'_post' => [ 'CheckOutputPlugin' ]
]
]
];
It is even possible to define plugins that will only be called for certain actions:
<?php
return [
'plugins' => [
// plugins called only for the homepage controller
'Homepage' => [
// plugins executed before the controller
'_pre' => [ 'SomePlugin', 'AnotherPlugin' ],
// plugins executed after the controller
'_post' => [ 'LastPlugin' ],
// plugins for the show action
'show' => [
// plugins executed before the action
'_pre' => [ 'SpecialPlugin' ],
// plugins executed after the action
'_post' => [ 'FooPlugin' ]
],
// plugins for the remove action
'remove' => [
// plugins executed before the action
'_pre' => [ 'BarPlugin' ]
]
]
]
];
It is also possible to define plugins that will be called for all controllers except one. In this case, simply place an hyphen ("-") in front of the controller name:
<?php
return [
'plugins' => [
// plugins called for all controllers except the authentication controller
'-Auth' => [
// plugins always executed before the controller
'_pre' => [ 'AuthPlugin' ],
// plugins always executed after the controller
'_post' => [ 'LastPlugin' ]
]
]
];
Finally, you can define plugins that will be called for all actions except one. Here again, simply place a hyphen ("-") in front of the action name:
<?php
return [
'plugins' => [
// plugins called only for the homepage controller
'Homepage' => [
// plugins for the show action
'show' => [
// plugins executed before the action
'_pre' => [ 'SpecialPlugin' ],
],
// plugins for all actions except the remove action
'-remove' => [
// plugins executed before the action
'_pre' => [ 'BarPlugin' ]
]
],
// plugins called for all controllers except the authentication controller
'-Auth' => [
// plugins executed before any action
'_pre' => [ 'FooPlugin' ],
// plugin executed before any action, except the login action
'-login' => [ 'AnotherPlugin' ]
]
]
];
3Write your own plugins
3.1Principles
Plugins make it possible to modularize the development of web applications. They make it possible in particular to factorize processing which must be done systematically at the start or at the end of all accesses.
This can be, for example, a plugin which checks that certain URLs are only accessible to authenticated users,
and which will be executed before the processes reach the controllers; if the user is not authenticated,
the plugin will redirect him to the authentication page, and the controller will not even be executed.
This can be a plugin which is executed at the end of the processing, to set template variables which are
necessary for all the pages.
The possibilities are limitless…
Plugins can even manipulate framework data, which gives them the ability to change the controller or the action that will be executed, as well as the parameters that will be passed to it.
3.2Development
Here is an example of a plugin:
class CheckPlugin extends \Temma\Web\Plugin {
public function plugin() {
// we set a template variable
$this['checked'] = true;
}
}
As can be seen in this example, plugins inherit from the \Temma\Web\Plugin parent class,
which itself derives from the \Temma\Web\Controller class. Plugins are therefore controllers
with just an additional capacity.
A plugin can therefore also be used as a controller, and a controller can also be used as a plugin.
In this example, we have defined a plugin() method, which will be executed when the plugin is called. It is therefore the configuration that will determine whether the object is a pre-plugin or a post-plugin.
To transmit data between plugins, or between plugins and the controller (and vice versa), template variables must be used. If a plugin sets a template variable, it will be accessible by all the plugins/controllers that follow in the execution chain.
So that the same object (whether it is only a plugin, or controller+plugin) can be both a pre-plugin and a post-plugin, by executing different code depending on the moment of its execution, we can define preplugin() and postplugin() methods.
- When a plugin is executed in the PRE action chain, Temma first looks to see if it has a method named preplugin(). If so, it is executed; otherwise, we execute the plugin() method.
- When a plugin is executed in the POST chain of actions, Temma first looks to see if it has a method named postplugin(). If so, it is executed; otherwise we execute the plugin () method.
Here is an example of a controller that is able to act as a pre-plugin and as a post-plugin, in addition to having several actions:
class Page extends \Temma\Web\Plugin {
protected $_temmaAutoDao = true;
// URL verification pre-plugin
public function preplugin() {
if (!$this->_checkUrl()) {
return $this->httpError(404);
}
$this['checked'] = true;
}
// post-plugin for reprocessing variables before sending to the template
public function postplugin() {
$dirtyData = $this['dirtyData'];
$cleanData = htmlspecialchars($dirtyData);
$this['cleanData'] = $cleanData;
}
// root action
public function index() {
$this['pages'] = $this->_dao->search();
}
// additional action
public function show($id) {
$this['page'] = $this->_dao->get($id);
}
// private method
private function _checkUrl() {
// ...
return (true);
}
}
3.3Handling plugins and controller
The plugins and the controller can dynamically modify the information that the framework uses to determine which plugins/controller to run.
Modifying plugins
In a plugin method or a controller method (initialization, action or finalization), it is possible to retrieve the complete list of plugins, and to update it.
This is done through the $this->_loader->config
object, which offers
the plugins attribute, readable and writable. This attribute directly contains
the array of plugins as defined in the etc/temma.php file
(see the configuration documentation).
If you change the plugins configuration, you may need to return an EXEC_RESTART or EXEC_REBOOT status, to force Temma to rerun the plugins chain.
Here is an example of a pre-plugin that reverses the order of the post-plugins.
class ReverseExamplePlugin extends \Temma\Web\Plugin {
public function preplugin() {
// retrieve the list of plugins
$plugins = $this->_loader->config->plugins;
// inversion of post-plugins
$plugins['_post'] = array_reverse($plugins['_post']);
// update the list of plugins
$this->_loader->config->plugins = $plugins;
}
}
Controller modification
In a plugin method or a controller method (initialization, action or finalization), it is possible to access the following information, and to modify it:
- The name of the controller to run.
- The name of the action to perform.
- The parameters supplied to the action.
All this information can be accessed by the $this->_loader->request object, which offers the following methods:
- getController(): Returns the name of the controller that will be executed. Identical to the $this['CONTROLLER'] template variable.
- getAction(): Returns the name of the action that will be executed. Identical to the $this['ACTION'] template variable.
- getNbrParams(): Returns the number of parameters.
- getParams(): Returns the list of parameters.
- getParam(int $index, [$default]): Returns the parameter whose index is given as a parameter. A default value can be passed as the second parameter; it will be returned if the requested parameter is not defined.
- setController(string $name): Sets the name of the controller to run.
- setAction(string $name): Defines the name of the action to run.
- setParams(array $params): Defines the list of parameters.
- setParam(int $index, string $value): Sets the value of a parameter whose index is provided.
Warning: If you modify the controller and/or the action with the setController() and setAction() methods, remember to update the corresponding template variables $this['CONTROLLER'] and $this['ACTION'], as well as $this['URL'].
3.4Plugin example
Here is an example of a simplistic pre-plugin that extracts the language at the beginning of the URL.
For example, for a URL /en/article/show/123/my-article, the plugin will put "en"
in the template variable $this['lang'], then do what it takes for Temma to do as if the received URL had been
/article/show/123/my-article.
class LangExamplePlugin extends \Temma\Web\Plugin {
public function preplugin() {
// retrieve the language
$lang = $this['CONTROLLER'];
// retrieve the controller
$newController = $this['ACTION'];
// retrieve the parameters
$params = $this->_loader->request->getParams();
// extract the action and shift the parameters
$newAction = array_shift($params);
// update the data in Temma
$this->_loader->request->setController($newController);
$this->_loader->request->setAction($newAction);
$this->_loader->request->setParams($params);
// update the template variables
$this['lang'] = $lang;
$this['CONTROLLER'] = $newController;
$this['ACTION'] = $newAction;
$this['URL'] = substr($this['URL'], strlen($lang));
}
}