35 votes

Plugin WordPress : Comment éviter le "couplage étroit" ?

Je travaille sur un plugin WordPress et j'essaie d'assurer les meilleures pratiques. J'ai deux classes, la classe de mon plugin "Jargonaut" qui est obligatoire et une autre classe appelée "Dictionary" qui est incluse dans le plugin. require_once() dans mon fichier principal de plugin.

La majeure partie du code de la classe Jargonaut concerne l'initialisation et fournit des fonctionnalités de type contrôleur, mais une grande partie de ce code dépend fortement de l'utilisation de l'objet Dictionary (c'est-à-dire qu'il est étroitement couplé, selon ma compréhension du terme). Je souhaite garder la classe Dictionary séparée car elle agit davantage comme un modèle (dans l'architecture MVC) et s'interface avec ma base de données.

Je vois beaucoup de zones d'ombre dans le couplage étroit ou lâche et j'ai du mal à décider combien est trop ?

60voto

hakre Points 102271

Si votre plugin a besoin de l'objet dictionnaire, il doit le demander :

class MyPlugin
{
    /**
     * @var Dictionary
     */
    private $dictionary;
    private function __construct(Dictionary $dictionary)
    {
        $this->dictionary = $dictionary;
    }

Vous avez maintenant couplé de manière souple votre plugin avec l'application Dictionary La classe du plugin n'est plus responsable de la création du dictionnaire pour elle-même, puisqu'elle est injectée. Elle prend ce dont elle a besoin.

Alors, comment cela fonctionnerait-il ? Le plugin doit être créé quelque part, ce qui nécessite une fabrique. La méthode de construction de la fabrique sait ce dont votre plugin a besoin :

class MyPluginFactory
{
    public static function build($pluginName)
    {
        $plugin = NULL;
        switch($pluginName)
        {
            case 'MyPlugin':
                $dictionary = new Dictionary();
                $plugin = new MyPlugin($dictionary);
        }
        return $plugin;
    }
}

Comme il s'agit de wordpress, nous savons que l'amorçage du plugin est fait en incluant le fichier du plugin. Donc au départ, le plugin doit être créé. Comme les inclusions se font dans la portée globale, nous voulons conserver l'objet plugin en mémoire mais sans qu'il soit disponible comme variable globale probablement. Cela ne vous empêche pas de créer plus d'une instance de plugin, mais cela garantit que lorsque wordpress initialise votre plugin (le charge), il n'utilisera que cette seule instance. Cela peut être fait en faisant de la fabrique du plugin une fonction supplémentaire :

class MyPluginFactory
{
    ...
    public static $plugins;
    public static function bootstrap($pluginName)
    {
        $plugin  = self::build($pluginName);
        self::$plugins[] = $plugin;
        return $plugin;
    }

Veillez à ce que la variable membre statique de la classe ne soit utilisée que pour garantir que le plugin reste en mémoire. Techniquement, il s'agit d'une variable globale que nous voulons normalement éviter, cependant, l'instance doit être stockée quelque part, donc la voici (je l'ai changée en public parce que c'est une variable de la classe). est une variable globale et il ne doit pas hésiter à le faire. Avoir une variable publique peut aider dans certaines circonstances où private ou protected sont trop restrictifs. De plus, cela ne devrait pas être un problème. Si elle est un problème, il y a un autre problème qui doit être réglé en premier).

Cela permet de découpler le code de votre plugin de Wordpress lui-même. Vous pouvez également créer une classe qui offre une interface à toutes les fonctions de wordpress que vous utilisez, de sorte que vous n'êtes pas lié à ces fonctions directement et que le code de votre plugin reste propre et faiblement couplé à wordpress lui-même.

class WordpressSystem
{
    public function registerFilter($name, $plugin, $methodName)
    {
        ... do what this needs with WP, e.g. call the global wordpress function to register a filter.
    }
    ...
}

Ensuite, ajoutez-le à nouveau comme dépendance si votre plugin a besoin de l'option WordpressSystem pour effectuer des tâches (ce qui est normalement le cas) :

class MyPlugin
{
    ...
    public function __construct(WordpressSystem $wp, Dictionary $dictionary)
    ...

Ainsi, pour conclure, seul le fichier php du plugin est nécessaire :

<?php
/*
 * MyPlugin
 * 
 * Copyright 2010 by hakre <hakre.wordpress.com>, some rights reserved.
 *
 * Wordpress Plugin Header:
 * 
 *   Plugin Name:    My Plugin
 *   Plugin URI:     http://hakre.wordpress.com/plugins/my-plugin/
 *   Description:    Yet another wordpress plugin, but this time mine
 *   Version:        1.2-beta-2
 *   Stable tag:     1.1
 *   Min WP Version: 2.9
 *   Author:         hakre
 *   Author URI:     http://hakre.wordpress.com/
 *   Donate link:    http://www.prisonradio.org/donate.htm
 *   Tags:           my
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
Namespace MyPlugin;

# if your file is named 'MyPlugin.php' this will be 'MyPlugin'.
return PluginFactory::bootstrap(basename($plugin, '.php'));

class PluginFactory
{
    private static $plugins;
    public static function bootstrap($pluginName)
    {
        $plugin = self::build($pluginName);
        self::$plugins[] = $plugin;
        return $plugin;
    }
    public static function build($pluginName)
    {
        $plugin = NULL;
        switch($pluginName)
        {
            case 'MyPlugin':
                # Make your plugin work with different Wordpress Implementations.
                $system = new System\Wordpress3();
                $dictionary = new Dictionary();
                $plugin = new Plugin($system, $dictionary);
        }
        return $plugin;
    }
}

class Plugin
{
    /**
     * @var System
     */
    private $system;
    /**
     * @var Dictionary
     */
    private $dictionary;
    private function __construct(System $system, Dictionary $dictionary)
    {
        $this->system = $system;
        $this->dictionary = $dictionary;
    }

...

La méthode bootstrap peut également s'occuper de l'enregistrement d'un autoloader ou faire le nécessaire.

J'espère que cela vous sera utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X