Du SQL pour pimenter Joomla! – Partie 3

Nous allons voir comment faciliter l’indexaction de votre site par les moteurs de recherche avec l’utilisation d’un sitemap ou plan de site en français.


Lors de nos deux précédents épisodes, nous avons pris contact avec la réalisation de requêtes SQL simples, mais utiles à l’administration de nos sites, tout en utilisant exclusivement les outils proposés par PHPMyAdmin et le gestionnaire de bases de données mySQL et en nous consacrant entièrement à une commande SQL unique : la commande SELECT.
Il est désormais temps d’aller plus loin et de commencer à prendre quelques risques en modifiant le contenu de nos bases de données Joomla ! Pour autant le travail effectué jusqu’ici n’a pas été inutile. Loin de là !

Antidigital – Flickr
Avertissement : Nous allons commencer à modifier le contenu des bases de données utilisées par Joomla!, il vous faut être bien conscient que ceci peut avoir un impact sur le fonctionnement même du CMS.  Je vous en avertis solennellement : ne tentez pas de me reprocher une dégradation de votre contenu ou de quelconques problèmes sur vos sites, car je vous le dis et ne le répéterai plus : avant tout travail visant à modifier le contenu d’une table, sauvegardez celle-ci. Mieux : sauvegardez la base de données intégralement à intervalles réguliers.
A.    Modifier les données dans la base Joomla ! : les principes
Si vous examinez un tant soit peu les requêtes proposées dans ces deux articles : Du SQL pour pimenter Joomla ! et Du SQL pour pimenter Joomla ! – Partie 2, vous constaterez rapidement que toutes nos requêtes sont de la même forme :
ORDRE – colonnes_concernées – FROM – nomtables – WHERE – clause_de_sélection
Où clause de sélection est une directive (sélection, sous-requête, jointure etc…) qui permet de réduire le champ d’application de l’ordre donné a seule fin de limiter l’ensemble de donénes concerné par cet ordre, nomtables est le nom de la ou des tables concernée(s) par la requête SELECT.
Jusqu’ici, les requêtes  présentées ont exclusivement utilisé l’ordre SELECT qui permet de sélectionner des informations en provenance d’une base de données. Les ordres UPDATE et DELETE suivent exactement la même approche, et s’appuie sur le même paradigme, nomtables est identique dans l’esprit et très proche dans l’écriture,  clause_de_sélection permet à l’identique de réduire (ou pas) l’ensemble de données affecté par l’ordre donné et peut être exactement identique dans sa formulation à la clause_de_sélection fournie dans une requête SELECT. Conseil : avant d’effectuer toute manipulation du contenu de vos tables, commencez systématiquement par vérifier avec un ordre SELECT que vous n’allez pas appliquer une modification ou une suppression sur plus de données que vous ne le souhaitez.
Sachez qu’en utilisant PHPMyAdmin pour modifier vos tables, vous travaillerez sans filets aucun. Vous avez peut être déjà entendu parler de transactions SQL et peut être même de COMMIT et de ROLLBACK. L’ordre COMMIT permet de valider une transaction SQL et donc d’en inscrire définitivement le résultat dans la base de données, alors que l’ordre ROLLBACK lui, permet d’annuler ce même traitement et de remettre la base de données dans l’état antérieur, quel que soit le nombre de modifications effectuées.Une requête exécutée via PHPMyAdmin utilise toujours une transaction et un COMMIT implicite. En conséquence, les ordres SQL que nous allons voir et utiliser, modifient immédiatement et sans possibilité de retour arrière automatique, le contenu de votre base de données Joomla!
{loadposition pub-j3pour-tous}
B.    Modifier un article de la base de données.
Un ou plusieurs articles, soyons clair, il n’y a aucune restriction quant au nombre d’articles traités en une seule requête, aucunes autres que celles imposées par la clause_de_sélection  placée après le mot-clé WHERE. Pour rappel, s’il n’y a pas de mot clé WHERE (il n’est pas obligatoire) et donc pas de clause_de_sélection alors tous les articles de la table (ou des tables) concernée(s) seront modifiés.
Passons maintenant à une étude de cas pratique détaillée.
II-a Réorganiser des catégories d’article
Mon site a désormais plus de 800 articles a disposition de ses utilisateurs, il arrive (pas trop souvent Dieu merci) que certains articles aient besoin d’être déplacés dans une sous catégorie nouvellement créé ou qu’une sous-catégorie soit supprimée et qu’il faille replacer les articles correspondant dans une catégorie parent, voire dans une autre catégorie plus adaptée.
Dans le premier cas : sauf cas particulier, aucune alternative, il faut article par article, ouvrir l’article, modifier la catégorie, sauvegarder l’article et recommencer avec  le suivant. Outre que c’est long et soumis à un risque d’erreur inhérent à ce genre de manipulations, les articles concernés voient leur date de modification mise à jour et ils repassent dans la liste des articles les plus récents, ce qui n’est pas forcément adéquat.
Dans le second cas, il est très facile de trouver une clause_de_sélection  efficace et d’écrire une requête modifiant les dits-articles.

Procédons étape par étape :
L’objectif est de se débarasser de la sous-catégorie AOM (id=61) et de remonter les articles concernés dans la catégorie Expertise (id=51). Une simple requête de sélection nous montre l’ensemble d’articles concernés :
SELECT DATE(created), c.title as ‘Article’, c.catid as ‘id catégorie’, ca.title as ‘Catégorie’FROM gucl0_content cINNER JOIN gucl0_users u ON u.id = c.created_byINNER JOIN gucl0_categories ca on ca.id = c.catidWHERE ca.id = 61

Seulement 4 articles, mais une sélection aisée à définir dans notre clause_de_sélection la modification est donc éligible facilement pour une requête de mise à jour :
UPDATE gucl0_content cSET c.catid = 51WHERE c.catid = 61
Comme vous pouvez le constater, cette requête (très simple au demeurant) est très courte ! Le paradigme est légèrement différent de celui de l’ordre SELECT, mais contient toutefois les mêmes informations :
ORDRE – nomtables – SET colonnes_concernées – WHERE – clause_de_sélection
Le mot-clé FROM disparaît (il est implicite), le mot-clé SET (obligatoire) précède colonnes_concernées qui précise en outre le nouveau contenu des dites colonnes.
Avant toute chose, commençons par sauvegarder la table concernée par l’opération, soit la table ##_content

Sélectionnez la table et utilisez les valeurs par défaut, est largement suffisant, n’oubliez pas de cliquer sur Exécuter pour finir et de placerle fichier déposé dans votre répertoire de téléchargement à l’abri, il contient outre vos données, le nécessaire pour reconstruire la table dans son intégralité (schéma ET données) en cas de nécessité.
Nous pouvons désormais exécuter la requête de mise à jour préparée ci-dessus. Aussitôt après l’exécution, PHPMyAdmin affiche le nombre de lignes traitées par la requête. Dans le cas présent : 4, ceci est normalement suffisant pour nous assurer du résultat, toutefois, nous pouvons nous assurer de la conformité de l’opération en reprenant la requête précédente :
SELECT DATE(created), c.title as ‘Article’, c.catid as ‘id catégorie’, ca.title as ‘Catégorie’FROM gucl0_content cINNER JOIN gucl0_users u ON u.id = c.created_byINNER JOIN gucl0_categories ca on ca.id = c.catidWHERE ca.id = 61
pour constater qu’il n’y a plus désormais d’articles présent dans notre catégorie AOM (id=61), modifions la requête pour lister les articles présents dans la catégorie Expertise (id=51) et vérifions que nos 4 articles y sont désormais bien présent. Dans le cas contraire (ce ne l’est pas !) nous pourrions restaurer notre table d’articles à son contenu précédent en effectuant la manipulation ci-dessous :

 
Attention : le fichier sauvegardé contient la totalité de votre table, avant de le restaurer, il vous faudra supprimer le contenu de la table via PHPMyAdmin.
La requête de mise à jour utilisée peut sembler très simple, comparée à la requête de sélection que nous avions utilisé pour vérifier l’ensemble de données retourné. En fait c’est la requête de sélection qui avait été complexifiée pour mettre à l’épreuve votre compréhension des deux premiers épisodes et aussi mieux visualiser nos données. L’on aurait tout aussi bien pu (ce n’était pas nécessaire dans ce cas) utiliser une jointure pour mettre à jour les catégories de nos articles en mimant précisément notre requête de sélection avec :
UPDATE gucl0_content c JOIN gucl0_users u ON u.id = c.created_by JOIN gucl0_categories ca on ca.id = c.catidSET c.catid = 51WHERE ca.id = 61
Qui nous donne exactement le même résultat que précédemment (encore heureux !).
II-b Quelques autres requêtes de mise à jour d’articles
Parmi les choses difficiles à faire depuis l’administration Joomla!, quelques unes concernent la manipulation du compte administrateur, comme :
N’exécutez pas cette requête sur votre site de production sans motifs extrêmement sérieux et impératif !
II-b-1 Se retirer à soi-même l’autorisation d’administrer un site.
Comme pour la requête précédente, affichons d’abord la requête SELECT correspondant à notre souhait :
SELECT us.id, us.name, us.username, um.group_id as ‘groupe actuel’, ug.title as ‘nom du groupe’FROM `gucl0_users` us JOIN gucl0_user_usergroup_map um ON um.user_id=us.idJOIN gucl0_usergroups ug ON ug.id = um.group_idWHERE us.username = ‘master1’
Ce qui nous affiche comme résultat :

La requête permettant de supprimer les droits d’administration (en gardant le fait d’être un compte enregistré) s’écrit de la manière suivante :
UPDATE gucl0_user_usergroup_map umJOIN `gucl0_users` us  ON um.user_id=us.idSET um.group_id = 2WHERE us.username = ‘master1’
Note : Cette requête ne supprime pas le compte Master1, (il faudrait une requête SQL DELETE que nous verrons bientôt), mais change l’état du compte de l’utilisateur Master1 le passant de ‘super utilisateur’ à ‘enregistré’. Les différents états autorisés sont accessibles dans la table ##_usergroups. Par défaut, le groupe public à un group_id égal à 1, enregistré à le group_id égal à 2 et super utilisateur le group_id égal à 8
Evidemment, après exécution de la requête, une tentative de connexion est douloureuse surtout si la requête ci-dessus n’était pas délibérément souhaitée !

Heureusement, vous avez la parade dans la requête même, il suffit de relancer la requête ci-dessus, légèrement modifiée !
II-b-2 Accorder l’autorisation d’administrer un site à un identifiant donné.
UPDATE gucl0_user_usergroup_map umJOIN `gucl0_users` us  ON um.user_id=us.idSET um.group_id = 8WHERE us.username = ‘master1’
Après avoir vérifié dans la table ##_usergroups que l’identifiant associé au ‘super utilisateur’ est bien 8, ce qui vous livre du même coup le code de la requête permettant de transformer n’importe quel utilisateur enregistré en ‘super utilisateur’, et par extension, de promouvoir ( ??) n’importe quel groupe à ‘super utilisateur’ ou à n’importe quel autre niveau d’ailleurs.
Lister les ‘administrateurs’ existant avant de les passer tous au niveau ‘super utilisateur’, est bien évidemment devenu pour vous un jeu d’enfant :
SELECT us.id, us.name, us.username, ug.idFROM `gucl0_users` us JOIN gucl0_user_usergroup_map um ON um.user_id=us.idJOIN gucl0_usergroups ug ON ug.id = um.group_idWHERE ug.title = ‘administrateur’
Requête qui retourne la liste des utilisateurs ayant le droit d’administrateur de votre site et vous livre du même coup l’id correspondant (7 pour mon site, ce qui est la valeur par défaut)  :
Assez joué avec le feu ! Passons à quelques requêtes d’un usage plus utile ou en tout cas plus fréquent.
Vous avez besoin de modifier dans le contenu de vos articles un nom de marque, un slogan, voire une phrase ou une image dont l’url doit être changé ? Facile : Rappelez-vous de notre requête pour lister toutes les occurrences du mot Joomla! dans vos articles :
SELECT id, title, introtext, `fulltext`, date(created) as ‘Créé le’FROM `br8l3_content`WHERE introtext LIKE ‘%joomla!%’ OR `fulltext` LIKE ‘%joomla!%’
Sur un site fraîchement installé avec les textes par défaut de la version française de Joomla!, cette requête retourne 13 occurrences du mot Joomla!, je vous propose à titre d’exercice de remplacer Joomla! par … WordPress  (franchement : dans la pratique, faites plutôt le contraire !) :
UPDATE br8l3_content c SET c.introtext = REPLACE(c.introtext, ‘Joomla!’, ‘Wordpress’), c.fulltext = REPLACE(c.fulltext, ‘Joomla!’, ‘Wordpress’)
Attention : la fonction REPLACE de mySQL est case-sensitive, par conséquent Joomla! et joomla! ne retournent pas le même ensemble d’information (alors que la fonction LIKE de notre clause_de_sélection  dans la requête SELECT de l’épisode 2 n’est pas case-sensitive elle! En outre, je vous recommande la plus extrême attention dans l’utilisation de cette requête. Réfléchissez méticuleusement à ce que vous demandez à mySQL d’effectuer. Dans la demande ci-dessus, sur le site de démonstration installé par Joomla! « joomla » n’apparaît pas que dans le texte, mais également dans des url (ex : //help.joomla.org), ce qui ne fournit pas évidemment les résultats attendus, (//help.wordpress.org) après remplacement. Par conséquent n’oubliez jamais le conseil de début : sauvegardez d’abord votre base de données.
Conclusion partielle
Effectuer des requêtes SQL de substitution, n’est pas plus compliqué que d’effectuer des requêtes de sélection. Il faut juste bien en mesurer le risque et prendre les mesures préventives qui s’imposent. Lorsque le mal est fait, il est souvent t(trop) tard pour revenir en arrière et parfois même impossible. Le remplacement de joomla par wordpress dans l’exemple ci-dessus en est un exemple parfait, qui saurait dire, pour revenir en arrière après l’exécution de la requêtes quels occurrences d wordpress doivent être remplacés par joomla ?
 Il nous reste à parler des commandes SQL DELETE et INSERT, à aborder également l’écriture des procédures stockées, … donc … à très bientôt !