système d'alerte lors de mise a jour de la base

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : système d'alerte lors de mise a jour de la base

Re: système d'alerte lors de mise a jour de la base

par sadeq » 15 janv. 2011, 01:36

Bonjour yadutonus,

Pour le premier problème tu peux enlever le TRIM car il ne sert à rien et vérifie bien que les valeurs dans ta base dans le champ liste_mots_cles_favoris sont bien séparées par un caractère |.

Voici la correction:
$sql = "SELECT * FROM stock WHERE CONCAT(auteur,' ',titre,' ',description,' ',commentaire) REGEXP ' " .  $membre[' liste_mots_cles_favoris'] ."' ORDER BY ref DESC " ;
Pour ta deuxième question concernant les nouveaux livres. Il faut ajouter un champ "date_entree_livre" dans le stock pour repérer les nouveaux livres par rapport à la dernière date d'alerte envoyée à un membre et pour cette dernière il faut ajouter un champ "date_derniere_alerte" dans la table membre.
La date d'entrée du livre sera renseignée à l'ajout d'un nouveau livre et la date de dernière alerte sera mise à jour après la réussite de l'envoi d'un mail d'alerte pour un membre.
La comparaison de ces deux dates doit donc être ajoutée à la requête de sélection des livres d'un membre alerté dans le programme d'envoi des e-mails.

Re: système d'alerte lors de mise a jour de la base

par yadutonus » 15 janv. 2011, 00:15

Encore une chose dans le code actuel, email envoyé recherche dans toute la table livre or il faudrait que la recherche se concentre sur les livres dernièrement ajoutés (cad nouveau depuis le dernier mail d'alerte). Comment faire pour ajouter cette contrainte ?

Re: système d'alerte lors de mise a jour de la base

par yadutonus » 15 janv. 2011, 00:10

Hello,
Le processus fonctionne mais il y a un petit problème, l'émail reçu à toutes les livres du stock !! Il semble que la partie
" . trim($membre[' liste_mots_cles_favoris'], "|") ."

ne soit pas prise en compte, et si je la remplace par exemple par (Colette|Jean) cela fonctionne.

Je te donne la partie de mon code adapté
//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>Les livres que vous recherchez sont peut-&ecirc;tre arriv&eacute;s</h1><p>Le %s</p><p>(%s)  Bonjour %s  %s (%s)</p>", date("d/m/Y"), $membre['idmembre'], $membre['nom'], $membre['prenom'], $membre['email']);
        $lettre_type .= "<p>Voici les derniers livres correspondant &agrave; vos alertes 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 stock WHERE CONCAT(auteur,' ',titre,' ',description,' ',commentaire) REGEXP ' " . trim($membre[' liste_mots_cles_favoris'], "|") ."' ORDER BY ref DESC " ;
        $result_livres = mysql_query($sql);
Merci encore pour ton aide !

Re: système d'alerte lors de mise a jour de la base

par sadeq » 12 janv. 2011, 19:34

Merci pour ta gentillesse :boire9: mais je suis loin de Paris.

Re: système d'alerte lors de mise a jour de la base

par Yadutonus » 12 janv. 2011, 11:43

Merci pour ta réponse rapide !! Je tente de le mettre en place cette semaine, j'espère que je n'aurais pas de problème. Si par hasard tu es parisien ou si tu passes par Paris, je t"offrirais une bière avec plaisir !!

Merci

Re: système d'alerte lors de mise a jour de la base

par sadeq » 10 janv. 2011, 15:55

Bonjour,

Oui c'est possible de faire autrement sans utiliser les trrigers. C'est à dire effectuer le traitement de recherche des livres favoris au moment où la procédure d'envoi des emails d'alerte est exécutée. Puisque de toutes façon cette procédure d'alerte doit être exécutée soit manuellement ou par un planificateur de tâches, il suffit donc d'inclure la procédure de recherche de livres dans le même programme. Dans ce cas, le champ "liste_livres_favoris" ne sert plus à rien puisqu'on peut s'appuyer sur le champ "liste_mots_clés_favoris" pour chercher directement les livres à inclure dans le courrier destiné au membre.

Soit les modifications suivantes dans le programme : membre_email.php
<?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.

Et la seconde requête est :
$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.
Le choix d'une expression régulière permet de simplifier le traitement de recherche dans la mesure où les mots-clés stockés dans le champ liste_mots_cles_favoris sont séparés par le caractère | qui est interprété par l'instruction REGEXP comme un OU. Voici un exemple d'exécution de cette instruction:
Si liste_mots_clés_favoris = 'php|informatique|linux' alors la requête devient:
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.

A+

Re: système d'alerte lors de mise a jour de la base

par yadutnous » 10 janv. 2011, 15:11

Aïe !! je viens d'appeler 1&1 et dans mon pack avec serveur mutualisé les triggers ne sont pas activés.
Il y a t il un autre moyen d'arriver au même résultat ?
est il nécessaire que je passe sur un serveur dédié, le prix est beaucoup plus cher !

#-o #-o #-o

Re: système d'alerte lors de mise a jour de la base

par sadeq » 09 janv. 2011, 23:38

Essaye ça avec un seul / comme délimiteur, en enlevant le point-virgule après le dernier END. C'est vrai que les triggers sous mysql sont vraiment une calamité au niveau syntaxe :
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 ;

Re: système d'alerte lors de mise a jour de la base

par stealth35 » 09 janv. 2011, 23:25

enlève les //

Re: système d'alerte lors de mise a jour de la base

par Invité » 09 janv. 2011, 23:07

En effet, j'ai vu ces erreurs. En ce qui concerne les delimiteurs, je les avait enlévés car j'avais une erreurs de syntaxe d'aprés mysql !
J'ai retapée ton nouveau code corrigé et voila la capture:

Image


Penses tu que les procédures Triggers sont disponibles ? J'ai l'impressions que oui si je regarde le FAQ 1&1, mais je ce n'ai pas claire.
Je sais que je suis sous version MySQL5 mais je ne sais pas si c'est 5.0.2 ou plus !!

:?: :?:

Re: système d'alerte lors de mise a jour de la base

par sadeq » 09 janv. 2011, 20:56

Bonjour,

A première vue, au niveau de la syntaxe, j'ai quelques remarques :
1. Il manque la déclaration du délimiteur de fin du trigger, c'est obligatoire. Dans mes requêtes précédente j'ai toujours utiliser l'instruction DELIMITER // qui permet de déclarer les // comme marque de fin de la structure du trigger, ceci sert à l'exécuteur SQL de ne pas exécuter les instructions interne du trigger qui suivent BEGIN jusqu'à END, car le délimiteur officiel est un point-virgule ; qui fait office de fin d'une instruction SQL exécutable. Donc pour un trigger, il faut absolument changer le délimiteur ; en un autre comme // pour pouvoir le créer d'abord sans exécuter son contenu.

Ceci s'écrit:
Code sql
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 ;

2. J'ai aussi remarqué l'absence d'espace entre certaine instructions et clauses SQL dans le code comme "WHERETRIM" et "ANDCONTACT"

Voici normalement la correction:
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.

Re: système d'alerte lors de mise a jour de la base

par yadutonus » 09 janv. 2011, 16:36

Bonjour, je tente d'adapter ton code à mon site.
Je souhaite créer le premier trigger mais Sql que renvoi une erreur inconnu (voir la capture) ?

Image

et voici le code que j'utilise:
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.

Merci

Re: système d'alerte lors de mise a jour de la base

par yadutonus » 08 janv. 2011, 14:16

Superbe travail ! Je vais avoir besoins de temps pour tout comprendre et l'adapter a ma base existante. Merci beaucoup pour le temps que tu as passé ! Je débute, je ne connaissait pas l'existence de trigger !. Je reviendrais surement vers toi pour te tenir au courant du développement ou des problèmes (je risque d'en rencontrer).

Merci encore.

Re: système d'alerte lors de mise a jour de la base

par sadeq » 07 janv. 2011, 23:12

Bonjour, je continue alors le développement de cette conception. Je vais utiliser un exemple simplifié pour illustrer toutes les étapes du développement.

En premier lieu voici le modèle relationnel sur lequel je vais me baser:
Image
Comme on peut le lire sur le modèle, un membre achète des livres et un livre est acheté par plusieurs membres.

Dans la table "membre", un membre peut enregistrer plusieurs mots-clés de livres favoris correspondant soit à des titres, des auteurs, des catégories de livres, ... Ces mots-clés sont stockés dans le champ "liste_mots_clés_favoris" séparés par des points-virgules ou des barres verticales | ou par tout autre caractère de séparation qu'on choisira techniquement plu-tard.
Par exemple : "informatique;histoire;php;word;microsoft;linux;...." ou "la fontaine|bureautique|excel|réseau|poésie|..."

Quand un membre a des mots-clés enregistrés le système doit remplir automatiquement le champ "liste_livres_favoris" par les identifiants des livres qui correspondent aux mots-clés enregistrés. Pour cela, on va utiliser des triggers (déclencheurs) qui peuvent surveiller tout ajout de nouveaux livres ou de nouveau mots-clés de membres.
Comme le champ des mots-clés, le champ "liste_livres_favoris" contiendra donc une liste d'identifiants des livres favoris déterminés par nos triggers.
Par exemple: "1;4;10" ici il s'agit de 3 livres ayant les numéros 1, 4 et 10.

Le champ "alerte_par_email" est un champ logique (booléen) qui prend soit VRAI soit FAUX (1 ou 0). Ce champ servira quand il vaudra VRAI (1) à envoyer au membre concerné un mail contenant la liste des livres favoris conformément aux identifiants listés dans le champ "liste_livres_favoris".

Et voici le script SQL qui traduit notre base de données sous MySQL:
--
-- 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 ;
Le caractère | par exemple me permet dans le cas des mots-clés d'utiliser une expression régulière pour faciliter la recherche de ces mots dans la table "livre" par rapport au titre, aux auteurs et aux catégories. et le fait de lister les données a pour avantage d'éviter des tables externes supplémentaires et simplifie considérablement les traitements.
Car on peut à tout moment transformer ces listes de données (CSV) en tableaux de programmation ou en listes déroulantes...

On remarque aussi qu'un membre peut choisir ou non d'être averti par mail quand il a des mots-clés mais il faut noter qu'il faut désactiver automatiquement l'alerte par mail d'un membre quand il n'a pas de mots-clés enregistrés.

Toutes ces contraintes de validité des données peuvent être prises en compte dans les triggers (déclencheurs) qu'on va construire.

Les Triggers (déclencheurs) nécessaires sont situés au niveau des 2 tables "livre" et "membre":

Un déclencheur attaché à la table "livre": Nom: livre_ajout:
Quand un nouveau livre est ajouté alors il faut ajouter son identifiant dans tous le champs "liste_livres_favoris" de chaque membre si le champ "liste_mots_cles_favoris" contient un mot-clé correspondant au titre, aux auteurs et catégories du nouveau livre en question.

Algorithme:
Nom de la procédure : `livre_ajout`
Contexte
Ce programme se déclenche après l'ajout d'un nouvel enregistrement dans la table `livre`
Les valeurs insérées dans la table livre seront préfixées par l'objet conteneur nommé "NEW",
en voici la liste de ceux qui nous intéressent: New.idlivre, New.titre, New.auteurs, NEW.categories

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.
Code SQL correspondant à l'algorithme:
--
-- 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

Quand on ajoute un nouveau membre avec des mots-clés ou bien on modifie la liste des mots-clés d'un membre existant, alors il faut chercher tous les livres correspondant aux nouveaux mots-clés et ajouter leurs identifiants dans le champ `liste_livres_favoris` du membre en question. Par contre, si le champ `liste_mots_cles_favoris` est vide, aucune recherche de livres n'est nécessaire et le champ `alerte_par_email` doit être forcement mis à zéro.

Ce traitement doit donc se déclencher à l'ajout et à la modification d'un membre.

Algorithme général pour les deux déclencheurs:
Nom des procédures : `membre_ajout` et `membre_maj`
Contexte
Ce programme se déclenche à l'ajout et la modification d'un enregistrement de la table `membre`
Les valeurs insérées dans la table 'membre` seront préfixées par l'objet conteneur nommé "NEW",
en voici la liste de ceux qui nous intéressent: NEW.liste_mots_cles_favoris, NEW.liste_livres_favoris, NEW.alerte_par_email

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.
Code SQL correspondant à l'algorithme:
--
-- 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.

On peut s'intéresser maintenant au traitement du e-mailing pour envoyer un publipostage basé sur un modèle de lettre présentant pour chaque membre sa liste des livres favoris.
Pour chaque enregistrement de la table `membre` dont le champ `alerte_par_email`= 1, le contenu de la lettre se base sur les identifiants contenus dans le champ `liste_livres_favoris`.

Voici donc l'algorithme :

Nom de la procédure : membre_mailing
Contexte
L'objectif est de construire et d'envoyer une lettre de livres favoris pour chaque membre souhaitant la recevoir par mail.
Cette tâche peut être déclenchée manuellement ou être planifiée automatiquement dans le temps par un planificateur de tâche comme CRON.
Elle utilise un modèle de lettre-type et comme source de données la table `membre` agrémentée par la table 'livre'
pour compléter les données sur les livres favoris
Les données nécessaires sont:
1. De la table `membre` : nom, prenom, email, alerte_par_email, liste_livres_favoris (contenant des idlivres séparés par un ;)
2. De la table `livre` : idlivre, titre, auteurs, prix, catégories, ...
3. Les relations entre la table `membre` et la table `livre` sont réalisées par les valeurs `idlivre` qui se
trouvent dans le champ `liste_livres_favoris`

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.
Voici le programme PHP équivalent : membre_mailing.php
<?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.

Re: système d'alerte lors de mise a jour de la base

par moogli » 07 janv. 2011, 14:45

Salut,

Il faut un declencheur, par exemple passer un champ (flag) a uk pour indiquer la mise a jour et faire le traitement d'envoi de mail.
Le probleme est de ne le faire pour chaque livre ajouter sinon tu spam tout. Donc le plus simple c'est de faire la mise a jour de la
Base et de lancer a la main le script d'envoi en fin de maj.

Pour ce qui est de la structure
Une table livre
Une membre
Un table critere avec 3 champs idcritere (clef primaire auto_increment), idmembre (correspond a la clef primaire de la table membre permet la liaison entre les tables) et un champ critere dans lequel tu met un critere unique, le membre veut plusieurs critere tu insere plusieurs tuples ;)

Ainsi tu peut cerer tout cela independament ;)

@+