Documentation : Plugins

Présentation

Il est possible de demander l'exécution de plugins, avant et/ou après l'exécution des contrôleurs de l'application. Techniquement, les plugins sont des contrôleurs possédant des méthodes spéciales, qui peuvent modifier la requête avant de la transmettre au plugin suivant ou au contrôleur désigné. On peut chaîner des plugins avant le contrôleur, et d'autres plugins après.

Les fichiers source des plugins sont stockés dans le répertoire controllers de l'application.

Un même objet peut avoir à la fois des rôles de plugin et de contrôleur.

Contrôle d'exécution

Les contrôleurs PRÉ s'exécutent avant le contrôleur, alors que les plugins POST s'exécutent après celui-ci.

Il est possible d'agir sur la chaîne d'exécution à plusieurs niveaux, en fonction des valeurs retournées par les plugins et les actions :

  • \Temma\Controller::EXEC_FORWARD : Passe à la suite normale de la chaîne d'exécution.
  • \Temma\Controller::EXEC_STOP : Arrête l'exécution des plugins.
    • Par un plugin PRÉ, aucun autre plugin PRÉ ne sera exécuté et on passera directement à l'exécution du contrôleur, puis à celle des plugins POST.
    • Par la méthode init() d'un contrôleur, l'action ne sera pas exécutée et on passera directement à l'exécution des plugins POST.
    • Par une action d'un contrôleur, cela n'a aucun effet particulier (identique à EXEC_FORWARD).
    • Par un plugin POST, aucun autre plugin POST ne sera exécuté.
  • \Temma\Controller::EXEC_HALT : Arrête toute la chaîne d'exécution et passe directement à la vue.
    • Par un plugin PRÉ, aucun autre plugin PRÉ ne sera exécuté, ni le contrôleur, ni de plugin POST.
    • Par la méthode init() d'un contrôleur, l'action ne sera pas exécutée ni aucun plugin POST.
    • Par une action d'un contrôleur, aucun plugin POST ne sera exécuté.
    • Par un plugin POST, aucun autre plugin POST ne sera exécuté (identique à EXEC_STOP).
  • \Temma\Controller::EXEC_QUIT : Arrête l'exécution du framework. Depuis un plugin ou un contrôleur, cela interrompt l'ensemble des traitements ; ni les autres plugins, ni le contrôleur, ne seront exécutés. Contrairement à EXEC_HALT, la vue ne sera pas exécutée et les demandes de redirection ne sont pas prises en compte.

Veuillez noter que les écritures suivantes sont strictement équivalentes :

  • return \Temma\Controller::EXEC_FORWARD;
  • return self::EXEC_FORWARD;
  • return null;
  • return;
Configuration

La configuration des plugins PRÉ et POST se fait en utilisant le fichier de configuration temma.json. Il est possible de configurer des plugins globaux, qui seront exécutés pour toutes les requêtes :

{
    "plugins": {
        /* liste des plugins PRÉ */
        "_pre": [
            "AuthenticationPlugin",
            "CmsController"
        ],
        /* liste des plugins POST */
        "_post": [
            "CleanSessionPlugin"
        ]
    }
}
						

Les plugins sont exécutés en suivant l'ordre dans lequel ils sont déclarés.

Il est possible de configurer des plugins qui ne s'exécuteront que pour certains contrôleurs :

{
    "plugins": {
        /* plugins exécutés systématiquement pour tous les contrôleurs */
        "_pre": ["AuthenticationPlugin", "CmsController"],
        "_post": ["CleanSessionPlugin"],
        /* plugins appelés uniquement pour le contrôleur de homepage */
        "HomepageController": {
            /* plugins exécutés avant le contrôleur */
            "_pre": ["SomePlugin", "AnotherPlugin"],
            /* plugins exécutés après le contrôleur */
            "_post": ["LastPlugin"]
        },
        /* plugins appelés uniquement pour le contrôleur d'affichage */
        "DisplayController": {
            "_post": ["CheckOutputPlugin"]
        }
    }
}
						

Il est même possible de définir des plugins qui ne vont être appelés que pour certaines actions :

{
    /* plugins appelés uniquement pour le contrôleur de homepage */
    "HomepageController": {
        /* plugins exécutés avant le contrôleur */
        "_pre": ["SomePlugin", "AnotherPlugin"],
        /* plugins exécutés après le contrôleur */
        "_post": ["LastPlugin"],
        /* plugins pour l'action execShow */
        "show": {
            "_pre": ["SpecialPlugin"],
            "_post": ["FooPlugin"]
        },
        /* plugins pour l'action execRemove*/
        "remove": {
            "_pre": ["BarPlugin"]
        }
    }
}
						

Les plugins sont exécutés dans l'ordre suivant :

  1. Les pré-plugins communs à tous les contrôleurs.
  2. Les pré-plugins communs à toutes les actions du contrôleur courant.
  3. Les pré-plugins spécifiques à l'action courante.
  4. Le contrôleur.
  5. Les post-plugins communs à tous les contrôleurs.
  6. Les post-plugins communs à toutes les actions du contrôleur courant.
  7. Les post-plugins spécifiques à l'action courante.
Code

Voici un exemple de plugin :

class CheckPlugin extends \Temma\Controller {
    public function plugin() {
        // on affecte une variable de template
        $this->set('checked', true);

        // on indique qu'on peut passer à la suite de la chaîne d'exécution ; c'est facultatif
        return (self::EXEC_FORWARD);
    }
}
						

Comme on peut le voir, peu de choses distinguent un plugin d'un contrôleur classique. La méthode appelée est nommée plugin(), ce qui fait qu'un contrôleur normal peut tout à fait avoir des capacités de plugin.

Pour qu'un même objet (qu'il ne soit qu'un plugin, ou contrôleur + plugin) puisse être à la fois un "pré-plugin" et un "post-plugin", en exécutant du code différent suivant le moment de son exécution, on peut définir des méthodes preplugin() et postplugin().

  • Lorsqu'un plugin est exécuté dans la chaîne d'actions PRÉ, Temma regarde d'abord s'il possède une méthode nommée preplugin(). Si c'est le cas, elle est exécutée ; sinon, on exécute la méthode plugin().
  • Lorsqu'un plugin est exécuté dans la chaîne d'actions POST, Temma regarde d'abord s'il possède une méthode nommée postplugin(). Si c'est le cas, elle est exécutée ; sinon on exécute la méthode plugin().

Voici un exemple de contrôleur qui est capable d'agir comme "pré-plugin" et/ou comme "post-plugin", en plus de posséder plusieurs actions :

class PageController extends \Temma\Controller {
    protected $_temmaAutoDao = true;

    // pré-plugin de vérification d'URL
    public function preplugin() {
        if (!$this->_checkUrl()) {
            $this->httpError(404);
            return (self::EXEC_QUIT);
        }
        $this->set('checked', true);
    }

    // post-plugin de retraitement de variables avant envoi au template
    public function postplugin() {
        $dirtyData = $this->get("dirtyData");
        $cleanData = htmlspecialchars($dirtyData);
        $this->set("cleanData", $cleanData);
    }

    // action racine
    public function execIndex() {
        $pages = $this->_dao->search();
        $this->set("pages", $pages);
    }

    // action supplémentaire
    public function execShow($id) {
        $page = $this->_dao->get($id);
        $this->set("page", $page);
    }

    // méthode privée
    private function _checkUrl() {
        // ...
        return (true);
    }
}