Migration de wiki

Petit nouveau ! | 9 Messages

01 janv. 2009, 17:55

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

ViPHP
ViPHP | 5924 Messages

01 janv. 2009, 22:05

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…

Petit nouveau ! | 9 Messages

02 janv. 2009, 10:50

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

ViPHP
ViPHP | 5924 Messages

02 janv. 2009, 13:13

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é…

Petit nouveau ! | 9 Messages

03 janv. 2009, 09:04

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 ;-)

Eléphant du PHP | 254 Messages

03 janv. 2009, 10:18

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`

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

03 janv. 2009, 10:48

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.
Quand tout le reste a échoué, lisez le mode d'emploi...

ViPHP
ViPHP | 5924 Messages

03 janv. 2009, 12:10

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;

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

03 janv. 2009, 12:16

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 ?
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

ViPHP
ViPHP | 5924 Messages

03 janv. 2009, 12:28

Non mais j'ai été un peu rapide en effet (le réveil :) )

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

03 janv. 2009, 12:41

Pas de soucis ;)
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Petit nouveau ! | 9 Messages

03 janv. 2009, 15:05

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