Écrire une mise à niveau de plugin
De temps en temps, il arrive un moment où un plugin doit modifier le contenu ou la structure des données qu’il a stockées soit dans la base de données, soit dans le répertoire des données.
La raison de ceci pourrait être que la structure des données doit être convertie en une structure plus efficace ou plus flexible. Ou peut-être en raison d’un bogue les éléments de données ont été enregistrés d’une manière non valide, et ils doivent être convertis dans le format correct.
De telles migrations et conversions peuvent prendre beaucoup de temps s’il y a beaucoup de données à traiter. C’est pourquoi Elgg fournit la classe Elgg\Upgrade\AsynchronousUpgrade
qui peut être utilisée pour implémenter des mises à niveau de longue durée.
Déclarer la mise à niveau d’un plugin
Le plugin peut communiquer la nécessité d’une mise à niveau avec la clé upgrades
dans le fichier elgg-plugin.php
. Chaque valeur du tableau doit être le nom complet d’une classe de mise à niveau qui étend la classe Elgg\Upgrade\AsynchronousUpgrade
.
Exemple tiré du fichier mod/blog/elgg-plugin.php
:
return [
'upgrades' => [
Blog\Upgrades\AccessLevelFix::class,
Blog\Upgrades\DraftStatusUpgrade::class,
]
];
- Les noms de classe dans l’exemple se réfèrent aux classes :
mod/blog/classes/Blog/Upgrades/AccessLevelFix
mod/blog/classes/Blog/Upgrades/DraftStatusUpgrade
Note
Les classes de mise à niveau du noyau Elgg peuvent être déclarées dans engine/lib/upgrades/async-upgrades.php
.
La classe de mise à niveau
Une classe qui étend la classe Elgg\Upgrade\AsynchronousUpgrade
a beaucoup de liberté sur la façon dont elle souhaite gérer le traitement réel des données. Elle doit cependant déclarer certaines variables constantes et également prendre soin de marquer si chaque élément traité a été mis à niveau avec succès ou non.
La structure de base de la classe est la suivante :
<?php
namespace Blog\Upgrades;
use Elgg\Upgrade\AsynchronousUpgrade;
use Elgg\Upgrade\Result;
/**
* Fixes invalid blog access values
*/
class AccessLevelFix extends AsynchronousUpgrade {
/**
* Version of the upgrade
*
* @return int
*/
public function getVersion() {
return 2016120300;
}
/**
* Should the run() method receive an offset representing all processed items?
*
* @return bool
*/
public function needsIncrementOffset() {
return true;
}
/**
* Should this upgrade be skipped?
*
* @return bool
*/
public function shouldBeSkipped() {
return false;
}
/**
* The total number of items to process in the upgrade
*
* @return int
*/
public function countItems() {
// return count of all blogs
}
/**
* Runs upgrade on a single batch of items
*
* @param Result $result Result of the batch (this must be returned)
* @param int $offset Number to skip when processing
*
* @return Result Instance of \Elgg\Upgrade\Result
*/
public function run(Result $result, $offset) {
// fix 50 blogs skipping the first $offset
}
}
Avertissement
Ne présumez pas quand votre classe sera instanciée ou quand/combien de fois ses méthodes publiques seront appelées.
Méthodes de la classe
getVersion()
Cela doit renvoyer un entier représentant la date à laquelle la mise à niveau a été ajoutée. La valeur se compose de huit chiffres au format yyyymmdnn
où:
yyyy
représente l’année
mm
représente le mois (avec le zéro initial)
dd
représente le jour (avec le zéro initial)
nn
est un numéro d’incrément (à partir de00
) qui est utilisé au cas où deux mises à niveau distinctes auraient été ajoutées au cours de la même journée
shouldBeSkipped()
Cela devrait renvoyer false
à moins que la mise à niveau ne soit pas nécessaire.
Avertissement
Si true
est renvoyé, la mise à niveau ne peut pas être exécutée plus tard.
needsIncrementOffset()
Si true
, votre méthode run()
recevra comme $offset
le nombre d’éléments déjà traités. Ceci est utile si vous ne modifiez que des données et que vous devez utiliser le $offset
dans une fonction comme elgg_get_entities()
pour savoir combien d’éléments ont déjà été traités.
Si false
, votre méthode run()
recevra comme $offset
le nombre total d’échecs. false
doit être utilisé si votre processus supprime ou déplace des données en dehors du processus. Par exemple, si vous supprimez 50 objets sur chaque run()
, vous n’avez pas vraiment besoin de $offset
.
countItems()
Récupère le nombre total d’éléments à traiter pendant la mise à niveau. Si ce nombre est inconnu, Batch::UNKNOWN_COUNT
peut être retourné, mais run()
doit alors marquer manuellement la mise à niveau terminée.
run()
Cette fonction doit effectuer une partie de la mise à niveau effective. Et en fonction de la durée nécessaire, elle peut être appelée plusieurs fois au cours d’une seule demande.
Elle reçoit deux arguments :
$result
: Une instance de l’objetElgg\Upgrade\Result
$offset
: Le décalage à partir duquel la prochaine portion de mise à niveau doit commencer (ou le nombre total de défaillances)
Pour chaque élément que la méthode traite, elle doit appeler selon les cas :
$result->addSuccesses()
: Si l’élément a bien été mis à niveau
$result->addFailures()
: Si l’élément n’a pas pu être mis à niveau
Les deux méthodes ont par défaut un seul élément, mais vous pouvez éventuellement passer le nombre d’éléments.
En outre, elle peut définir autant de messages d’erreur que nécessaire dans le cas où quelque chose ne va pas :
$result->addError("Le message d'erreur est indiqué ici")
Si countItems()
renvoie Batch::UNKNOWN_COUNT
, alors à un moment donné run()
doit appeler $result->markComplete()
pour terminer la mise à niveau.
Dans la plupart des cas, votre méthode run()
voudra passer le paramètre $offset
à l’une des fonctions elgg_get_entities()
:
/**
* Process blog posts
*
* @param Result $result The batch result (will be modified and returned)
* @param int $offset Starting point of the batch
* @return Result Instance of \Elgg\Upgrade\Result;
*/
public function run(Result $result, $offset) {
$blogs = elgg_get_entitites([
'type' => 'object'
'subtype' => 'blog'
'offset' => $offset,
]);
foreach ($blogs as $blog) {
if ($this->fixBlogPost($blog)) {
$result->addSuccesses();
} else {
$result->addFailures();
$result->addError("Failed to fix the blog {$blog->guid}.");
}
}
return $result;
}
getUpgrade()
Utilisez cette fonction pour obtenir l’entité ElggUpgrade
associée à cette mise à niveau.
Interface d’administration
Chaque mise à niveau étendant la classe Elgg\Upgrade\AsynchronousUpgrade
est répertoriée dans le panneau d’administration après avoir déclenché la mise à niveau du site depuis le tableau de bord d’administration.
Lors de l’exécution des mises à niveau, Elgg fournit :
Durée estimée de la mise à niveau
Nombre d’éléments traités
Nombre d’erreurs
Messages d’erreur possibles