--
-- Structure de la table `livre`
--
-- Création: Ven 07 Janvier 2011 à 14:31
--
DROP TABLE IF EXISTS `livre`;
CREATE TABLE IF NOT EXISTS `livre` (
`idlivre` int(11) NOT NULL AUTO_INCREMENT,
`titre` varchar(100) DEFAULT NULL,
`auteurs` varchar(100) DEFAULT NULL,
`prix` float DEFAULT NULL,
`categories` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idlivre`),
UNIQUE KEY `livre_unique` (`titre`,`auteurs`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
--
-- Structure de la table `membre`
--
-- Création: Ven 07 Janvier 2011 à 14:31
--
DROP TABLE IF EXISTS `membre`;
CREATE TABLE IF NOT EXISTS `membre` (
`idmembre` int(11) NOT NULL AUTO_INCREMENT,
`nom` varchar(45) DEFAULT NULL,
`prenom` varchar(45) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`mot_de_passe` varchar(45) DEFAULT NULL,
`liste_mots_cles_favoris` text,
`liste_livres_favoris` text,
`alerte_par_email` tinyint(1) DEFAULT '0',
PRIMARY KEY (`idmembre`),
UNIQUE KEY `membre_unique` (`nom`,`prenom`,`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=24 ;
--
-- Structure de la table `achats`
--
-- Création: Ven 07 Janvier 2011 à 14:31
--
DROP TABLE IF EXISTS `achats`;
CREATE TABLE IF NOT EXISTS `achats` (
`dateachat` date NOT NULL,
`membre_idmembre` int(11) NOT NULL,
`livre_idlivre` int(11) NOT NULL,
`quantite` int(11) DEFAULT '1',
`adresse_de_livraison` varchar(255) DEFAULT NULL,
UNIQUE KEY `achat_unique` (`dateachat`,`membre_idmembre`,`livre_idlivre`),
KEY `fk_achats_livre` (`livre_idlivre`),
KEY `fk_achats_membre` (`membre_idmembre`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Contraintes relationnelles pour la table `achats`
--
ALTER TABLE `achats`
ADD CONSTRAINT `fk_achats_livre` FOREIGN KEY (`livre_idlivre`) REFERENCES `livre` (`idlivre`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `fk_achats_membre` FOREIGN KEY (`membre_idmembre`) REFERENCES `membre` (`idmembre`) ON DELETE NO ACTION ON UPDATE NO ACTION;
Voici, un échantillon de données d'exemple que j'ai injecté pour les tests:
-- --------------------------------------------------------
--
-- Contenu de la table `livre`
--
INSERT INTO `livre` (`idlivre`, `titre`, `auteurs`, `prix`, `categories`) VALUES
(1, 'PHP débutant', 'Sadeq;Yves', 50, 'Programmation'),
(2, 'Excel 2007 avancé', 'Sadeq;Yves', 20, 'Bureautique'),
(4, 'Réseaux TCP/IP', 'Yves', 50, 'Informatique'),
(8, 'PHP avancé', 'Sadeq', 30, 'Programmation'),
(9, 'Excel 2007 débutant', 'Sadeq', 20, 'Bureautique'),
(12, 'Word 2007 débutant', 'Sadeq', 20, 'Bureautique'),
(13, 'La France médiévale en photos', 'Sadeq', 15, 'Histoire'),
(14, 'Le corbeau et le renard', 'La Fontaine', 5, 'Roman;Poésie');
-- --------------------------------------------------------
--
-- Contenu de la table `membre`
--
INSERT INTO `membre` (`idmembre`, `nom`, `prenom`, `email`, `mot_de_passe`, `liste_mots_cles_favoris`, `liste_livres_favoris`, `alerte_par_email`) VALUES
(1, 'Elmir', 'Sadeq', '[email protected]', '20EAfcH0JSFQY', 'php|programmation', ';1;8', 1),
(2, 'Legrand', 'Aline', '[email protected]', '20EAfcH0JSFQY', 'bureautique|réseau|php', ';1;2;4;8;9;12', 0),
(3, 'Dupont', 'Jean', '[email protected]', '20EAfcH0JSFQY', 'sadeq|informatique', ';1;2;4;8;9;12;13', 1),
(21, 'Varnier', 'Paul', '[email protected]', '20EAfcH0JSFQY', 'romans|poésie|histoire|la fontaine|php', ';1;8;13;14', 1),
(23, 'Niho', 'Lee', '[email protected]', '20EAfcH0JSFQY', 'informatique', ';4', 0);
Comme on peut remarquer dans cet échantillon de données et notamment dans la table "membre" que les listes de mots-clés sont des mots séparés par le caractère | et que les identifiants de livres favoris sont séparés par des points-virgules. C'est juste un choix technique, celui de spécifier le caractère de séparation | ou ; Code : Tout sélectionner
DEBUT
Pour chaque enregistrement de la table `membre`:
SI le champ `liste_mots_cles_favoris` n'est pas vide
ET SI l'un des mots contenus dans le champ `liste_mots_cles_favoris` se trouve dans les chaines : (NEW.titre +' ' +NEW.auteurs +' ' +NEW.categories)
ALORS
Ajouter l'identifiant du livre NEW.idlivre à la fin de la chaine du champ `liste_livres_favoris`:
membre.`liste_livres_favoris` = membre.`liste_livres_favoris` + ";" + NEW.idlivre
:Refaire la procédure pour le membre suivant
FIN.--
-- Déclencheurs `livre`
--
DELIMITER //
CREATE TRIGGER `livre_ajout` AFTER INSERT ON `livre`
FOR EACH ROW BEGIN
UPDATE `membre` SET liste_livres_favoris = concat( liste_livres_favoris, ';', NEW.idlivre )
WHERE TRIM(liste_mots_cles_favoris) <> ''
AND CONCAT(NEW.titre,' ',NEW.auteurs,' ',NEW.categories) REGEXP liste_mots_cles_favoris;
END
//
DELIMITER ;
Deux déclencheurs attachés à la table "membre" feront la même chose mais l'un surveillera l'jout et l'autre la mise à jour Code : Tout sélectionner
DEBUT
INITIALISER NEW.liste_livres_favoris = vide
SI NEW.liste_mots_cles_favoris n'est pas vide ALORS
Pour chaque enregistrement de la table `livre`:
SI l'un des mots contenus dans le champ NEW.liste_mots_cles_favoris se trouve dans les chaines : (livre.titre +' ' +livre.auteurs +' ' +livre.categories) ALORS
Ajouter l'identifiant du livre livre.idlivre à la fin de la chaine du champ NEW.liste_livres_favoris :
NEW.liste_livres_favoris = NEW.liste_livres_favoris + ';' + livre.idlivre;
:Refaire la procédure pour le membre suivant
SINON
INITIALISER NEW.alerte_par_email = 0;
FIN SI;
FIN.
--
-- Déclencheurs `membre`
--
DROP TRIGGER IF EXISTS `livres`.`membre_ajout`;
DELIMITER //
CREATE TRIGGER `livres`.`membre_ajout` BEFORE INSERT ON `livres`.`membre`
FOR EACH ROW BEGIN
DECLARE var_idlivre INT;
DECLARE var_nonTrouve BOOL DEFAULT FALSE;
DECLARE var_liste_livres CURSOR FOR SELECT idlivre FROM livre WHERE CONCAT(titre,' ',auteurs,' ',categories) REGEXP NEW.liste_mots_cles_favoris;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET var_nonTrouve := TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION CLOSE var_liste_livres;
SET NEW.liste_livres_favoris = '';
IF TRIM(NEW.liste_mots_cles_favoris) <> '' THEN
OPEN var_liste_livres;
FETCH var_liste_livres INTO var_idlivre;
WHILE var_nonTrouve = FALSE DO
SET NEW.liste_livres_favoris = CONCAT(NEW.liste_livres_favoris, ';', var_idlivre) ;
FETCH var_liste_livres INTO var_idlivre;
END WHILE;
CLOSE var_liste_livres;
ELSE
SET NEW.alerte_par_email=0;
END IF;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `livres`.`membre_maj`;
DELIMITER //
CREATE TRIGGER `livres`.`membre_maj` BEFORE UPDATE ON `livres`.`membre`
FOR EACH ROW BEGIN
DECLARE var_idlivre INT;
DECLARE var_nonTrouve BOOL DEFAULT FALSE;
DECLARE var_liste_livres CURSOR FOR SELECT idlivre FROM livre WHERE CONCAT(titre,' ',auteurs,' ',categories) REGEXP NEW.liste_mots_cles_favoris;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET var_nonTrouve := TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION CLOSE var_liste_livres;
SET NEW.liste_livres_favoris = '';
IF TRIM(NEW.liste_mots_cles_favoris) <> '' THEN
OPEN var_liste_livres;
FETCH var_liste_livres INTO var_idlivre;
WHILE var_nonTrouve = FALSE DO
SET NEW.liste_livres_favoris = CONCAT(NEW.liste_livres_favoris, ';', var_idlivre) ;
FETCH var_liste_livres INTO var_idlivre;
END WHILE;
CLOSE var_liste_livres;
ELSE
SET NEW.alerte_par_email=0;
END IF;
END
//
DELIMITER ;
Maintenant, ces déclencheurs vont surveiller les actions INSERT sur la table `livre`et INSERT et UPDATE sur la table `membre`. Le traitement des mots-clés est donc automatique.Code : Tout sélectionner
DEBUT
Préparer l'entête de la lettre-type en tant que Mail;
Pour chaque enregistrement de la table `membre`:
SI membre.alerte_par_email = 1 et membre.liste_livres_favoris n'est pas vide ALORS
Insérer dans la lettre les données identifiant le membre en cours : nom, prenom, email
DECLARER VARIABLE tableau_livres = convertir en tableau la chaine membre.liste_livres_favoris en utilisant le séparateur point-virgule
Le tableau contient à ce niveau N cases contenant chacune un idlivre
On va le parcourir pour afficher les infos des livres dans la lettre-type:
Pour chaque élément du tableau tableau_livres :
DECLARER VARIABLE var_idlivre = l'élément en cours;
DECLARER VARIABLE var_livre = Lire un enregistrement de la table `livre` dont le champ livre.idlivre = var_idlivre
SI var_livre n'est pas nul ALORS
le livre est trouvé, insérer donc dans la lettre-type les données identifiant le livre en cours: idlivre, titre, auteurs, prix, catégories, ...
FIN SI;
:Refaire la procédure pour l'élément livre suivant
A ce niveau la lettre-type pour le membre actuel est construite, il faut l'envoyer par mail:
MAIL (DE='Nous', A=membre.email, OBJET='Votre nouvelle sélection de livres favoris' , MESSAGE = la lettre-type rédigée);
FIN SI;
:Refaire la procédure pour le membre suivant
FIN.
<?php
//Paramètres du serveur Mail
ini_set("SMTP", "localhost");
//Entête du mail au Format HTML
$boundary = "nextPart";
$headers = "MIME-Version: 1.0\r\n";
$headers .= "From: Site Livres <[email protected]>\r\n";
$headers .= "Content-Type: multipart/alternative; boundary = $boundary\r\n";
//html version
$headers .= "\n--$boundary\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "This is the <b>HTML</b> version";
//Traitement de la lettre-type
//Obtenir la liste des membres
mysql_connect('localhost', 'root');
mysql_select_db('livres');
//Les membres à sélectionner doivent avoir choisi l'alerte email et avoir des livres favoris
$sql = "SELECT * FROM membre WHERE alerte_par_email = 1 AND TRIM(liste_livres_favoris) <>'' ";
$result_membres = mysql_query($sql);
while ($result_membres && $membre = mysql_fetch_array($result_membres)){
//insérer les données du membre dans la lettre-type
$lettre_type = sprintf("<h1>Vos Livres favoris</h1><p>Le %s</p><p>Membre n°:%s Nom: %s Prénom: %s Email: %s</p>", date("d/m/Y"), $membre['idmembre'], $membre['nom'], $membre['prenom'], $membre['email']);
$lettre_type .= "<p>Voici votre sélection de livres correspondant à vos critères de recherche</p><ul>";
//Obtenir la liste des livres favoris du membre correspondant à liste_livres_favoris
$sql = "SELECT * FROM livre WHERE '" . $membre['liste_livres_favoris'] ."' REGEXP idlivre" ;
$result_livres = mysql_query($sql);
while ($result_livres && $livre = mysql_fetch_array($result_livres)){
$lettre_type .= sprintf("<li>Livre n°:%s Titre: %s Auteurs: %s Catégories: %s Prix: %s </li>", $livre['idlivre'], $livre['titre'], $livre['auteurs'], $livre['categories'], $livre['prix']);
}
$lettre_type .= "</ul>";
//Enfin, on est prêt à envoyer le mail (A, OBJET, MESSAGE, EN-TÊTES_MAIL)
mail($membre['email'], "Vos Livres favoris", $lettre_type, $headers);
//on peut aussi faire une sauvegarde du mail au format HTML dans un dossier nommé "mails/"
$nom_fichier = "mails/membre_mail_".date("d-m-Y")."_".$membre['idmembre'].".htm";
file_put_contents($nom_fichier, $lettre_type);
//Et aussi afficher des liens vers les fichiers entegistrés
echo sprintf("<p><a href=\"%s\" />%s</a></p>", $nom_fichier, $nom_fichier);
} //répéter cette procédure pour le membre suivant
mysql_close();
?>
Finalement vous pouvez télécharger l'archive complète de ce projet de démonstration en espérant avoir clarifier le sujet.
CREATE TRIGGER `livre_ajout` AFTER INSERT ON `stock`
FOR EACH ROW BEGIN
UPDATE `membre` SET liste_livres_favoris = concat( liste_livres_favoris, ';', NEW.ref )
WHERE TRIM(liste_mots_cles_favoris) <> ''
AND CONCAT(NEW.auteur,' ',NEW.titre,' ',NEW.description,' ',NEW.commentaire) REGEXP liste_mots_cles_favoris;
END
je ne comprend pas. Peut être que la procédure que j'utilise est mauvaise , je n'ai encore jamais fait autre chose que créer des table sur mon admin. Je suis sur 1&1.
DELIMITER // -- déclaration d'un nouveau délimiteur d'instruction SQL ici le //
CREATE TRIGGER `livre_ajout` AFTER INSERT ON `stock` FOR EACH ROW BEGIN
-- instructions décrivant l'algorithme du trigger se terminant par le délimiteur normal ;
END;
// -- fin de l'instruction de création du trigger car il y a ici le délimiteur //
DELIMITER ; -- retour au délimiteur d'instructions normal qui est ;
Remarque que tout ce qui est avant // est une seule instruction : CREATE TRIGGER ... BEGIN .... END; // car avant on a déclaré les // comme délimiteur. A la fin du code on revient au délimiteur normal : DELIMITER ;DELIMITER //
CREATE TRIGGER `livre_ajout` AFTER INSERT ON `stock` FOR EACH ROW BEGIN
UPDATE `membre` SET liste_livres_favoris = CONCAT( liste_livres_favoris, ';', NEW.ref )
WHERE TRIM(liste_mots_cles_favoris) <> ''
AND CONCAT(NEW.auteur,' ',NEW.titre,' ',NEW.description,' ',NEW.commentaire) REGEXP liste_mots_cles_favoris;
END;
//
DELIMITER ;
3. Mais attention, Le support rudimentaire des déclencheurs (triggers) est inclus dans les versions de MySQL à partir de la version 5.0.2.
DROP TRIGGER IF EXISTS `livre_ajout`;
DELIMITER /
CREATE TRIGGER `livre_ajout` AFTER INSERT ON `stock`
FOR EACH ROW BEGIN
UPDATE `membre` SET liste_livres_favoris = CONCAT( liste_livres_favoris, ';', NEW.ref )
WHERE TRIM(liste_mots_cles_favoris) <> ''
AND CONCAT(NEW.auteur,' ',NEW.titre,' ',NEW.description,' ',NEW.commentaire) REGEXP liste_mots_cles_favoris;
END
/
DELIMITER ;
<?php
//Paramètres du serveur Mail
ini_set("SMTP", "localhost");
//Entête du mail au Format HTML
$boundary = "nextPart";
$headers = "MIME-Version: 1.0\r\n";
$headers .= "From: Site Livres <[email protected]>\r\n";
$headers .= "Content-Type: multipart/alternative; boundary = $boundary\r\n";
//html version
$headers .= "\n--$boundary\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "This is the <b>HTML</b> version";
//Traitement de la lettre-type
//Obtenir la liste des membres
mysql_connect('localhost', 'root');
mysql_select_db('livres');
//Les membres à sélectionner doivent avoir choisi l'alerte email et avoir des mots-clés de livres favoris
$sql = "SELECT * FROM membre WHERE alerte_par_email = 1 AND TRIM(liste_mots_cles_favoris) <>'' ";
$result_membres = mysql_query($sql);
while ($result_membres && $membre = mysql_fetch_array($result_membres)){
//insérer les données du membre dans la lettre-type
$lettre_type = sprintf("<h1>Vos Livres favoris</h1><p>Le %s</p><p>Membre n°:%s Nom: %s Prénom: %s Email: %s</p>", date("d/m/Y"), $membre['idmembre'], $membre['nom'], $membre['prenom'], $membre['email']);
$lettre_type .= "<p>Voici votre sélection de livres correspondant à vos critères de recherche</p><ul>";
//Obtenir la liste des livres favoris du membre correspondant aux mots-clés du champ liste_mots_clés_favoris (les mots-clés sont séparés par un |)
$sql = "SELECT * FROM livre WHERE CONCAT(titre,' ',auteurs,' ', categories) REGEXP ' " . trim($membre[' liste_mots_cles_favoris'], "|") ."' " ;
$result_livres = mysql_query($sql);
while ($result_livres && $livre = mysql_fetch_array($result_livres)){
$lettre_type .= sprintf("<li>Livre n°:%s Titre: %s Auteurs: %s Catégories: %s Prix: %s </li>", $livre['idlivre'], $livre['titre'], $livre['auteurs'], $livre['categories'], $livre['prix']);
}
$lettre_type .= "</ul>";
//Enfin, on est prêt à envoyer le mail (A, OBJET, MESSAGE, EN-TÊTES_MAIL)
mail($membre['email'], "Vos Livres favoris", $lettre_type, $headers);
//on peut aussi faire une sauvegarde du mail au format HTML dans un dossier nommé "mails/"
$nom_fichier = "mails/membre_mail_".date("d-m-Y")."_".$membre['idmembre'].".htm";
file_put_contents($nom_fichier, $lettre_type);
//Et aussi afficher des liens vers les fichiers entegistrés
echo sprintf("<p><a href=\"%s\" />%s</a></p>", $nom_fichier, $nom_fichier);
} //répéter cette procédure pour le membre suivant
mysql_close();
?>
Les modifications sont apportées aux 2 requêtes fondamentales du traitement à savoir:
$sql = "SELECT * FROM membre WHERE alerte_par_email = 1 AND TRIM(liste_mots_cles_favoris) <>'' ";
Qui sélectionne tous les membres qui doivent être alertés et qui ont des mots-clés enregistrés. Ici, on n'utilise plus le champ liste_livres_favoris car il n'est pas à jour.$sql = "SELECT * FROM livre WHERE CONCAT(titre,' ',auteurs,' ', categories) REGEXP ' " . $membre[' liste_mots_cles_favoris'] ."' " ;
Où on sélectionne pour chaque membre, les livres qui correspondent aux mots-clés se trouvant dans le champ liste_mots_cles_favoris.SELECT * FROM livre WHERE CONCAT(titre,' ',auteurs,' ', categories) REGEXP 'php|informatique|linux'
Ce qui veut dire que SQL va chercher soit php ou bien informatique ou bien linux dans les chaines concaténées : titre + auteurs + categories.