Page 1 sur 1

Migration de wiki

Posté : 01 janv. 2009, 17:55
par scls19fr
Bonjour,

j'ai un site web depuis pas mal d'années.
J'utilise le wiki Wikini http://www.wikini.net
J'envisage de passer à un autre wiki (même syntaxe) : WikkaWiki http://wikkawiki.org
J'ai un nombre très important de pages donc je souhaite automatiser un peu la migration.
Les tables sont sensiblement les mêmes mais sur certaines tables il n'y a pas un champ donné. Sur d'autres tables il y a un champ qui n'existait pas dans le wiki initial.

Comment procéderiez-vous pour effectuer cette migration ?

Installer le deuxième wiki à côté et faire un script PHP qui se connecte à la base et qui récupère les données du premier et fait des INSERT INTO sur le second.

J'ai également entendu parler ETL (Talend...)
Est-ce adapté à mon besoin ?
J'ai aussi entendu par d'ORM (Doctrine, Propel...)
mais je n'ai pas pratiqué

Idéalement j'aimerais définir un schéma de mes tables du wiki initial
définir un schéma des tables du wiki final.
indiquer d'où proviennent les informations (créer éventuellement des fonctions de conversion s'il y a besoin de reformater les données)
et que ça se "dépatouille" tout seul (oui je sais que Noël est passé !)

Quelle stratégie adopteriez-vous ?

Merci d'avance

Posté : 01 janv. 2009, 22:05
par Sékiltoyai
INSERT SELECT est ton ami…
Personnellement quand j'ai une migration de ce style à faire, j'étudie le schéma des deux tables, établit les correspondances, les règles de transition, et ensuite je remplis les tables avec INSERT SELECT. Et ensuite je finalise le travail avec éventuellement des UPDATE supplémentaires si la transformation est plus complexe…

Posté : 02 janv. 2009, 10:50
par scls19fr
Et il n'y a pas d'outils pour gérer ça un peu plus "joliment"
J'imagine l'utilisation d'un ORM comme Propel ou Doctrine.
Tu crées une classe (ou un schéma) pour chaque table.
Tu définis les transitions d'une classe à l'autre


Sinon on va revenir à la méthode que tu évoques et essayer de voir comment l'appliquer sur mon cas concret.

Voici un export des tables dans les 2 wikis

Commençons par la
Table users
-----------

Wikini (le wiki original)

Code : Tout sélectionner

INSERT INTO `wikini_users` (`name`, `password`, `email`, `motto`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`) VALUES ('MonUser', 'hashmd5', '[email protected]', '', 20, 50, 'Y', '2009-01-01 10:08:12', 'N');
Wikka (le nouveau wiki

Code : Tout sélectionner

INSERT INTO `wikka_users` (`name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`, `status`) VALUES ('MonUser', 'hashmd5', '[email protected]', 20, 50, 'Y', '2009-01-01 10:55:24', 'N', NULL);
Comment fais-tu ton INSERT SELECT ?

moi j'ai fait ça

Code : Tout sélectionner

INSERT INTO `wikka_users` (`name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`) SELECT `name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments` FROM `wikini_users`
Je ne peux pas avec la même requete remplir les champs des la nouvelle table qui n'ont pas d'équivalent dans l'ancienne (en mettant un valeur par défaut)
ou suis-je obligé de faire un UPDATE après pour fixer ces champs ?

J'ai ensuite quelque chose d'un poil plus compliqué avec la table acls (Access Control List).
C'est la table qui gère les droits de lecture/ecriture/commentaire sur chaque page

Table acls
----------
Wikini

Code : Tout sélectionner

INSERT INTO `wikini_acls` (`page_tag`, `privilege`, `list`) VALUES ('PagePrincipale', 'write', 'MonUser'), ('PagePrincipale', 'read', '*'), ('PagePrincipale', 'comment', '+');
Wikka

Code : Tout sélectionner

INSERT INTO `wikka_acls` (`page_tag`, `read_acl`, `write_acl`, `comment_acl`) VALUES ('PagePrincipale', '*', 'MonUser', '+');
Comme tu peux voir dans le nouveau wiki pour une page il y a un seul enregistrement dans la table
alors que pour le wiki original il y en a 3

J'ai donc pensé à faire ça en 3 fois.

Code : Tout sélectionner

-- ajouter un enregistrement par page pour les acls en lecture INSERT INTO `wikka_acls` (`page_tag`, `read_acl`) SELECT `page_tag`, `list` FROM `wikini_acls` WHERE `privilege` LIKE 'read'
ça c'est ok

Code : Tout sélectionner

-- modifier l'enregistrement pour les acls en ecriture UPDATE `wikka_acls` SET `write_acl` = `wikini_acls`.`list` WHERE `wikini_acls`.`page_tag`=`wikka_acls`.`page_tag`
par contre là ça ne fonctionne pas (je ne suis pas un spécialiste des jointures)
MySQL a répondu:Documentation
#1109 - Unknown table 'wikini_acls' in where clause

et il faudrait faire quelque chose de similaire pour les acls des commentaires

Merci d'avance

Posté : 02 janv. 2009, 13:13
par Sékiltoyai
Le principe du INSERT SELECT, c'ets que tu mets ce que tu veux dans la SELECT, donc si tu as des champs supplémentaires, ou des options à prendre dans d'autres tables, tu peux très bien les rajouter dans tes clauses du SELECT en utilisant par exemple des jointures ou des requêtes imbriquées.
Le INSERT SELECT te donne une très grosse liberté…

Posté : 03 janv. 2009, 09:04
par scls19fr
Merci pour cette réponse

1)
mais si ça ne t'embête pas on va prendre un exemple

la migration de la table users

Comment modifer la requete

Code : Tout sélectionner

INSERT INTO `wikka_users` (`name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`) SELECT `name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments` FROM `wikini_users`
pour mettre "toto" dans le champ status de la nouvelle table
(à l'aide de la même requête c'est à dire sans faire un UPDATE après coup) ?


2) Pourquoi (concernant la table gérant les acls) la requête

Code : Tout sélectionner

-- modifier l'enregistrement pour les acls en ecriture UPDATE `wikka_acls` SET `write_acl` = `wikini_acls`.`list` WHERE `wikini_acls`.`page_tag`=`wikka_acls`.`page_tag`
ne fonctionne pas ?

3) Même si le wiki vers lequel je migre à la même syntaxe que le précédent,
je me demande comment j'aurai géré la situation si ça n'avait pas été le cas.
Peut-on en SQL utiliser des regexp pour modifier directement mes pages ou
suis-je obliger de passer par un script PHP qui se connecte à la base,
récupère pour chaque page son contenu puis applique les modifs via des regexp
et stocke dans la base ?

PS : cette 3ième question est subsidiaire ;-)

Posté : 03 janv. 2009, 10:18
par furiouslol
Salut

Pour modifier ta requete et insérer dans des champs qui n'existent pas dans la table de base tu peux faire un truc comme ca

Code : Tout sélectionner

INSERT INTO `wikka_users` (`name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`, `status`) SELECT `name`, `password`, `email`, `revisioncount`, `changescount`, `doubleclickedit`, `signuptime`, `show_comments`, "toto" FROM `wikini_users`

Posté : 03 janv. 2009, 10:48
par @rthur
Bonjour,

La solution ETL est faite pour cela, c'est typiquement ce qu'il fait de mieux.
Donc Talend peut être l'approche à préconiser dans ton cas.

Toutefois si tu connais déjà bien un langage de programmation typiquement le PHP et MySQL dans ton cas, il est possible que tu mettes moins de temps à tout faire en PHP qu'avec un ETL où il y a forcément une phase d'apprentissage pour que bien maitriser l'outil.

Posté : 03 janv. 2009, 12:10
par Sékiltoyai
Pour ton second problème, c'est juste un peu plus compliqué, mais ca fonctionne quand même :

Code : Tout sélectionner

INSERT INTO `wikka_acls` (`page_tag`, `read_acl`, `write_acl`, `comment_acl`) SELECT p1.page_tag, p1.list, p2.list, p3.list FROM wikini_acls p1, wikini_acls p2, wikini_acls p3 WHERE p1.page_tag=p2.page_tag AND p1.page_tag=p3.page_tag;

Posté : 03 janv. 2009, 12:16
par zeus
Pour ton second problème, c'est juste un peu plus compliqué, mais ca fonctionne quand même :

Code : Tout sélectionner

INSERT INTO `wikka_acls` (`page_tag`, `read_acl`, `write_acl`, `comment_acl`) SELECT p1.page_tag, p1.list, p2.list, p3.list FROM wikini_acls p1, wikini_acls p2, wikini_acls p3 WHERE p1.page_tag=p2.page_tag AND p1.page_tag=p3.page_tag;
Ne faudrait-il pas sécuriser le truc en forçant chaque table dérivée à l'attribut qu'on recherche, comme ça :

Code : Tout sélectionner

INSERT INTO `wikka_acls` (`page_tag`, `read_acl`, `write_acl`, `comment_acl`) SELECT p1.page_tag, p1.list, p2.list, p3.list FROM wikini_acls p1, wikini_acls p2, wikini_acls p3 WHERE p1.page_tag=p2.page_tag AND p1.page_tag=p3.page_tag AND p1.privilege LIKE 'write' AND p1.privilege LIKE 'read' AND p1.privilege LIKE 'comment';
Parce que sinon, on va récupérer plus que nécessaire.
J'ai bon ?

Posté : 03 janv. 2009, 12:28
par Sékiltoyai
Non mais j'ai été un peu rapide en effet (le réveil :) )

Posté : 03 janv. 2009, 12:41
par zeus
Pas de soucis ;)

Posté : 03 janv. 2009, 15:05
par scls19fr
Merci à vous tous

Je ne savais pas que l'on pouvait faire ce qu'indique furiouslol dans un SELECT !

Par contre je n'ai pas bien compris ce que signifient p1, p2, p3 dans les solutions proposées par
Sékiltoyai et zeus
Et en plus ça marche pô...mais j'ai corrigé

Code : Tout sélectionner

INSERT INTO `wikka_acls` ( `page_tag` , `read_acl` , `write_acl` , `comment_acl` ) SELECT p1.page_tag, p1.list, p2.list, p3.list FROM wikini_acls p1, wikini_acls p2, wikini_acls p3 WHERE p1.page_tag = p2.page_tag AND p1.page_tag = p3.page_tag AND p2.privilege LIKE 'write' AND p1.privilege LIKE 'read' AND p3.privilege LIKE 'comment';

Enfin pour ce qui est de la solution ETL qui a été évoquée par @rthur je pense que je vais aussi l'expérimenter par curiosité.
Mais j'imagine qu'il faut que je rapatrie mes tables dans une base en local (car c'est un hébergement mutalisé chez OVH... avec simplement FTP HTTP PHP MySQL et phpMyAdmin...

Après je pense que ça pourrait être sympa de regarder un ORM comme Propel ou Doctrine
Faire pour chaque table un schéma et décrire la transformation à réaliser en PHP (c'est un peu
plus "objet" comme approche mais ça peut servir)
Certains d'entre vous ont-il expérimenté ça ?

Enfin dernière chose, j'ai quand même quelques modifications à faire directement dans les pages
je pense qu'il faut faire un SQL UPDATE
mais je vais prendre un exemple
Pour insérer une image dans wikini j'utilisais la syntaxe

Code : Tout sélectionner

[[http://www.monsite.fr/me.png me]]
alors que dans wikka c'est

Code : Tout sélectionner

{{image url="../images/contact/me.png" title="me" alt="me"}}
J'imagine qu'il faut utiliser une REGEXP pour changer ça mais peut-on
faire un remplacement à l'intérieur du texte à l'aide de SQL ou suis-je obligé de faire
une extraction de chaque texte et le traiter ensuite par PHP ?
Dernière chose la syntaxe de wikini est la même pour les URL vers un site extérieur

Code : Tout sélectionner

[[http://www.domain.com lien externe]]
et pour les images donc il faudrait que la REGEXP teste si c'est un gif, un png ou un jpg et remplacer par la syntaxe wikka uniquement dans ce cas.

Edit :
Je pense avoir trouvé la RegExp qui va bien

Code : Tout sélectionner

preg_replace('/\[{2}([a-z0-9]+:\/\/[^ \t\n\r\f"\|\\\\\^\`\{\}\[\]><]+\.(gif|png|jpg|jpeg)) (.*)\]{2}/', '{{image url="$1" title="$2" alt="$2"}}', $string_from);
par contre je suis obligé d'utiliser PHP, d'importer chaque page, appliquer la regexp et renvoyer dans la base... je ne peux pas faire ça directement avec SQL