Dans notre développement de plug-in, nous utilisons Composer pour installer, par exemple, Symfony\Process
que nous utiliserons plus tard dans le code. La grande question est comment faire en sorte que cette dépendance ne soit pas en conflit avec un autre plugin en utilisant également Symfony\Process
dans une autre version.
Maintenant, je sais que c’est principalement un problème inhérent à PHP, mais nous souhaitons tout de même proposer à nos utilisateurs une solution qui les avertisse au moins lorsqu'un tel conflit se produit (au lieu d’échouer de manière irréversible). Une approche, par exemple, consisterait à analyser le répertoire des plugins à la recherche de dossiers vendor
et à essayer de déterminer si des versions incompatibles sont utilisées dans un autre plugin. Je sais que loin (comme vraiment, très loin) de la perfection, mais j'essaie juste de donner un exemple.
Comment gérez-vous cela? Je sais que Composer n’est pas encore très répandu parmi les développeurs de plug-ins, mais nous aurons tous ce problème tôt ou tard, alors je me demande si quelqu'un a imaginé une sorte de stratégie pour le résoudre.
La réponse est: vous ne pouvez pas parce que WordPress ne le peut pas. Il n'y a pas de concept de gestion de dépendance dans WP et c'était le même cas avant même que Composer n'existe.
La montée de l'autoload (Composer ou autre) y contribue légèrement, dans la mesure où vous pourriez simplement charger une copie différente (assez proche, espérons-le) plutôt qu'une erreur fatale pure et simple. Vous pouvez vérifier cela si vous concevez une méthode. Par exemple, en vérifiant les chemins, les définitions ont été chargées avec get_included_files()
, mais en réalité, ce n'est qu'un pansement, pas une solution.
Le seul scénario dans lequel Composer vraiment vous y aide est celui-ci qui permet de contrôler l’ensemble de l’installation WP, avec un seul dossier de fournisseur partagé.
Travaillant sur un CMS de petites annonces fortement inspiré de Wordpress (je ne l’ai pas nommé osclass.org), je suis tombé sur votre fil. Nous sommes exactement dans la même situation, devant gérer plusieurs plugins utilisant la même dépendance.
Pour expliquer la solution que nous avons trouvée, nous avons deux plugins:
Nous devons nous assurer que la version 1.30 est chargée pour que les deux plugins fonctionnent correctement.
Wordpress (et Osclass) ont une option active_plugins
(dans la table wp_options
) qui définit les plugins actifs et, plus important encore, dans notre cas: plugin loading order .
Ceci est un tableau simple.
Au début de nos deux plugins, nous vérifions la version de D1 pour nous assurer que celle-ci correspond à nos besoins (ou à une version supérieure).
// Custom autoloader, we'll check it in a moment.
require __DIR__ . "/vendor/composer_components/madhouse/autoloader/autoload.php";
if(!function_exists("mdh_utils") || (function_exists("mdh_utils") && strnatcmp(mdh_utils(), "1.30") === -1)) {
// Dependency version is lower than 1.30 (which we need), let's bump.
mdh_bump_me();
} else {
// Rest of the plugin code.
}
Cas simple: que se passe-t-il lorsque P2 est chargé avant P1?
Tout est bien.
Cas intéressant: que se passe-t-il lorsque P1 est chargé avant P2?
Voici la version bosse.
N'oubliez pas que les plugins sont chargés dans l'ordre défini dans active_plugins
.
La fonction bump - dans ce cas, mdh_bump_me () - place le plugin actuel en haut du active_plugins
(première position du tableau).
Ressemble à ça. Ceci est un code lié à Osclass, mais il peut facilement être modifié pour fonctionner avec Wordpress:
function mdh_bump_me()
{
// Sanitize & get the {PLUGIN_NAME}/index.php.
$path = str_replace(osc_plugins_path(), '', osc_plugin_path(__FILE__));
if(osc_plugin_is_installed($path)) {
// Get the active plugins.
$plugins_list = unserialize(osc_active_plugins()); // This is the active_plugins fields unserialized.
if(!is_array($plugins_list)) {
return false;
}
// Remove $path from the active plugins list
foreach($plugins_list as $k => $v) {
if($v == $path) {
unset($plugins_list[$k]);
}
}
// Re-add the $path at the beginning of the active plugins.
array_unshift($plugins_list, $path);
// Serialize the new active_plugins list.
osc_set_preference('active_plugins', serialize($plugins_list));
if(Params::getParam("page") === "plugins" && Params::getParam("action") === "enable" && Params::getParam("plugin") === $path) {
//osc_redirect_to(osc_admin_base_url(true) . "?page=plugins");
} else {
osc_redirect_to(osc_admin_base_url(true) . "?" . http_build_query(Params::getParamsAsArray("get")));
}
}
}
En un mot,
Un mot sur notre chargeur automatique personnalisé. L'autochargeur de compositeur charge chaque classe (même si elle a déjà été définie), la nouvelle remplaçant l'ancienne.
Notre autochargeur personnalisé ne charge une classe que s'il n'existe pas encore. Charge la première instance de chaque classe et ignore toutes les autres.
J'espère que c'est assez clair.
Loin, loin d’être une solution idéale, mais qui fonctionne pour nous et c’est un pas en avant.