Ce tutoriel fait partie de la série Construire votre démarrage avec PHP sur Envato Tuts +. Dans cette série, je vous guide dans le lancement d'une startup du concept à la réalité, en utilisant mon application Meeting Planner comme exemple concret. À chaque étape du processus, je publierai le code de Meeting Planner sous forme d’exemples open source à partir desquels vous pourrez apprendre. Je traiterai également les problèmes liés au démarrage au fur et à mesure qu'ils surviennent.
Dans l'épisode précédent, j'avais décrit la mise en place d'une infrastructure permettant de suivre les modifications des réunions afin que nous sachions comment partager les mises à jour avec les participants. Dans cet épisode, je couvrirai la surveillance du journal et l'envoi de notifications par courrier électronique des modifications..
Si vous n'avez pas encore essayé Meeting Planner, planifiez votre première réunion. Lorsque vos collègues et amis répondent, vous verrez les notifications en action. Je participe aux commentaires ci-dessous, alors partagez vos commentaires. Je suis particulièrement intéressé si vous souhaitez suggérer de nouvelles fonctionnalités ou de nouveaux sujets pour de futurs tutoriels..
Pour rappel, tout le code pour Meeting Planner est écrit dans le framework Yii2 pour PHP. Si vous souhaitez en savoir plus sur Yii2, consultez notre série parallèle Programmer avec Yii2.
Avec le MeetingLog de l'épisode précédent, nous surveillons régulièrement le moment où les modifications ont été effectuées il y a quelques minutes et les consolidons dans une seule mise à jour destinée aux autres participants ou à l'organisateur de la réunion..
Notre processus DaemonController actionFrequent vérifiera les réunions avec de nouvelles mises à jour toutes les quelques minutes:
fonction publique actionFrequent () // appelée toutes les trois à cinq minutes // notifie les utilisateurs de nouvelles modifications Meeting :: findFresh ();
Réunion :: findFresh ()
examine le journal des entrées plus anciennes que Journal de réunion :: TIMELAPSE
, actuellement cinq minutes. Quand il les trouve, il examine chacun des acteurs impliqués dans les changements et les informe via Réunion :: notify ()
:
Fonction statique publique findFresh () // identifie toutes les réunions dont les entrées de journal ne sont pas encore effacées $ meetings = Meeting :: find () -> où ('log_at-cleared_at> 0') -> all (); foreach ($ meetings as $ m) // à faire - choisissez un espace vide différent, pour le moment, d'une heure si ((time () - $ m-> log_at)> 3600) // à faire - envisagez de les éliminer. les anciens continuent; // entrée de journal non effacée antérieure à TIMELAPSE if ((time () - $ m-> log_at))> MeetingLog :: TIMELAPSE) // $ logs = MeetingLog :: find () -> where (['meeting_id' => $ m-> id]) -> groupBy ('actor_id') -> all (); $ current_actor = 0; foreach ($ log en tant que $ log) if ($ log-> actor_id <> $ current_actor) $ current_actor = $ log-> actor_id; // nouvel acteur, notifions les autres si ($ log-> actor_id == $ m-> owner_id) // il s'agit de l'organisateur // notifie les participants // echo 'notifie les participants'; foreach ($ m-> participants en tant que $ p) $ m-> notifier ($ m-> id, $ p-> id); else // il s'agit d'un participant // notifier l'organisateur et // faire - lorsqu'il y a plusieurs participants $ m-> notify ($ m-> id, $ m-> propriétaire_id); else // cette entrée de journal par le même acteur que la dernière action continue; // efface le journal de cette réunion Meeting :: clearLog ($ m-> id);
Si l'organisateur de la réunion a effectué le changement, le ou les participants doivent en être informés. Si un participant a effectué le changement, l'organisateur (et, à l'avenir, les autres participants) doivent être avertis. plusieurs réunions de participants seront implémentées dans des tutoriels ultérieurs.
Dans l'interface utilisateur actuelle de Meeting Planner, un certain nombre de modifications enregistrées font référence à des éléments identiques et s'annulent mutuellement. Par exemple, si vous cliquez sur le commutateur pour un lieu, celui-ci est d'abord rejeté. Vous devez cliquer à nouveau pour l'accepter. Les deux modifications sont enregistrées.
J'ai dû écrire du code supplémentaire pour créer un résumé textuel concis et précis du journal..
Voici, par exemple, l'historique MeetingLog des actions. Notez la répétition des actions de Cloudster qui s’annulent aux mêmes endroits et aux mêmes heures:
Une représentation textuelle de base dirait:
Cloudster ajouté note Merci pour le rappel. Je serai sûr de le faire., Heure acceptée jeu. 9 juin à 12h00, heure acceptée vendredi 10 juin à 12h00, heure refusée vendredi 10 juin à 12h00, heure refusée jeu. 9 juin à 12h00 PM, heure refusée mer. 8 juin à 12 h 30, lieu refusé. Café biologique Chaco Canyon, lieu accepté: café biologique Chaco Canyon, lieu refusé: café biologique Chaco Canyon, endroit accepté No Bones Beach Club et endroit refusé No Bones Beach Club.
Comment pouvons-nous créer un résumé textuel simple des modifications qui en résultent pour l'email de notification, comme illustré ci-dessous:
Dans Réunion :: notify ()
, nous demandons un historique d'activité pour cette réunion depuis la dernière notification:
// construit la notification en langue anglaise $ history = MeetingLog :: getHistory ($ meeting_id, $ user_id, $ mtg-> cleared_at);
Voici le code qui construit une chaîne textuelle de ce qui s'est passé. Je ferai probablement du polissage à l'avenir pour clarifier la description. Par exemple, la version finale fournit une liste grammaticale appropriée avec l'utilisation appropriée des virgules, puis «et» pour la dernière fois..
Fonction statique publique getHistory ($ meeting_id, $ user_id, $ cleared_at) // construire un historique textuel des événements pour cette réunion // non effectuée par cet utilisateur et depuis cleared_at $ str = "; $ events = MeetingLog :: find () -> where (['meeting_id' => $ meeting_id]) -> andWhere ('actor_id <>'. $ user_id) -> andWhere ('created_at>'. $ cleared_at) -> orderBy (['created_at' => SORT_DESC , 'actor_id' => SORT_ASC]) -> all (); $ num_events = count ($ événements); $ cnt = 1; $ current_actor = 0; $ current_str = "; $ items_mentION = []; foreach ($ events as $ e) if ($ e-> actor_id <> $ current_actor) // nouvel acteur, met à jour la chaîne globale $ str. = $ current_str. '
'; // réinitialise la chaîne d'événements de l'acteur actuel $ current_str = "; $ current_actor = $ e-> actor_id; $ actor = MiscHelpers :: getDisplayName ($ e-> actor_id); else $ actor ="; $ action = $ e-> getMeetingLogCommand (); $ item = $ e-> getMeetingLogItem (); if (in_array ($ e-> item_id, $ items_mentenced)) // ne mentionne l'élément que la première fois qu'il apparaît (dernière action, en tant que trié) continue; else $ items_mentenced [] = $ e-> item_id; if ($ actor == ") if ($ cnt == $ num_events) $ current_str. = 'et'. $ action.". $ item; else $ current_str. = ','. $ action. ". $ item; else $ current_str. = $ actor.". $ action. ". $ item; // compte les événements $ cnt + = 1; // add last current_str (peut être vide) $ str. = $ current_str. '
'; return $ str;
Essentiellement, getHistory () est spécifique à l'utilisateur. La requête ci-dessous trie les actions dans l'ordre inverse car, principalement, le dernier changement a un impact dominant:
$ events = MeetingLog :: find () -> where (['meeting_id' => $ meeting_id]) -> andWhere ('actor_id <>'. $ user_id) -> andWhere ('created_at>'. $ cleared_at) -> orderBy (['created_at' => SORT_DESC, 'actor_id' => SORT_ASC]) -> all ();
À l’avenir, il y aura plusieurs participants dont les actions se chevauchent dans le temps. Nous regroupons donc l’historique par actor_id
.
Ensuite, je dépiste le $ current_actor
alors que nous construisons la textualisation, nous ne mentionnons leur nom qu’une fois, c’est-à-dire "Jeff a fait ces actions. John a fait ces actions", et non "Jeff a fait cela, John a fait ceci, Jeff a fait ceci et John a fait ceci et John a fait cela."
De même, je traque la mention d'objets dans $ articles_mentionné
et ignorant les événements précédents, ne fournissant que la dernière action dominante sur un lieu ou une heure, par exemple "Jeff a accepté le No Bones Beach Club" et non "Jeff a rejeté le No Bones Beach Club, Jeff a accepté le No Bones Beach Club."
Le code était complexe et amusant à écrire. La textualisation résultante (illustrée ci-dessus) est amusante à observer.
Dans le didacticiel Raffinage des modèles de courrier électronique, j'ai décrit le passage à nos nouveaux modèles réactifs Oxygen. Cela a nécessité une révision du modèle notify-html.php et un polissage progressif au fil du temps.
Voici un extrait du modèle:
Changements à votre réunion salut id)); ?>, des changements ont été apportés à votre réunion.
Cliquez sur le bouton ci-dessous pour afficher la page de la réunion..
"> Visitez la page de réunion
La distribution du courrier électronique s'effectue de la même manière que nos invitations à des réunions avec l'extension Yii2 SwiftMailer via notre configuration Mailgun SMTP..
$ message = Yii :: $ app-> mailer-> composer (['html' => 'notify-html', 'text' => 'notify-text'], ['meeting_id' => $ mtg-> id , 'sender_id' => $ user_id, 'user_id' => $ a ['user_id'], 'auth_key' => $ a ['auth_key'], 'links' => $ links, 'meetingSettings' => $ mtg -> meetingSettings, 'history' => $ history,]); if (! empty ($ a ['email'])) $ message-> setFrom (['[email protected]' => 'Planificateur de réunions']); $ message-> setReplyTo ('mp _'. $ meeting_id.'@meetingplanner.io '); $ message-> setTo ($ a ['email']) -> setSubject (Yii :: t ('frontend', 'Meeting Update:'). $ mtg-> subject) -> send ();
J'espère que vous avez apprécié les didacticiels en deux parties sur les notifications. J'ai trouvé que construire le journal et créer une description textuelle de l'histoire était difficile et amusant à développer. Et cela s'est avéré utile pour le débogage et la synthèse des mises à jour de réunion pour les notifications. Cependant, les tests n'étaient pas faciles car il y avait toujours des horodatages et des tâches en arrière-plan qui devaient être manipulées pour vérifier que le code fonctionnait.
Veuillez essayer la fonctionnalité de notification en planifiant votre première réunion. Vous devriez recevoir des notifications régulières lorsque vos invités répondent. Aussi, je vous serais reconnaissant de partager votre expérience ci-dessous dans les commentaires, et vos suggestions m'intéresseront toujours. Vous pouvez également me joindre directement sur Twitter @reifman.
Je commence également à expérimenter WeFunder à partir de la mise en œuvre des nouvelles règles de la SEC en matière de financement participatif. S'il vous plaît envisager de suivre notre profil. Je peux écrire à ce sujet plus dans le cadre de notre série.
Surveillez les prochains tutoriels dans la série Construire votre démarrage avec PHP. Il y a quelques autres fonctionnalités plus importantes à venir.