Construire votre démarrage envoyer des rappels

Ce que vous allez créer

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 ce didacticiel en deux parties, je décris comment j'ai construit l'infrastructure pour les rappels et leur diffusion. Aujourd'hui, je vais vous guider tout au long de la surveillance pour savoir quand envoyer des rappels et comment envoyer les courriels..

Si vous n'avez pas encore essayé Meeting Planner, planifiez votre première réunion. Je participe aux commentaires ci-dessous, alors dites-moi ce que vous en pensez! 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.

Temps de surveillance pour les rappels

Au fil du temps, nous devons veiller à la MeetingReminder table pour savoir quand livrer des rappels. Idéalement, nous souhaitons que les rappels soient livrés exactement à l'heure, par exemple. à la minute.

Exécuter des tâches en arrière-plan

La rapidité d'exécution dépend de la fréquence à laquelle nous exécutons des tâches en arrière-plan pour la surveillance. Actuellement, dans notre phase pré-alpha, je les lance toutes les cinq minutes:

# m h dom commande mon dow * / 5 * * * * wget -O / dev / null http://meetingplanner.io/daemon/frequent

Ce script appelle MeetingReminder :: check (), qui trouve des rappels de réunion qui sont dus et demande à processus() leur:

// tâche cron fréquente appellera pour vérifier les rappels dus fonction publique statique check () $ mrs = MeetingReminder :: find () -> where ('due_at<='.time().' and status='.MeetingReminder::STATUS_PENDING)->tout(); foreach ($ mrs as $ mr) // traite chaque rappel de réunion MeetingReminder :: process ($ mr); 

Traitement d'un rappel

MeetingReminder :: process () rassemble les détails nécessaires pour créer un e-mail de rappel. Cela inclut le destinataire du rappel, les détails de la réunion et l'heure:

processus de fonction statique publique ($ mr) // récupère le rappel // envoie l'e-mail ou le sms // envoie des mises à jour sur les modifications apportées récemment à une réunion par $ user_id $ user_id = $ mr-> user_id; $ meeting_id = $ mr-> meeting_id; $ mtg = Meeting :: findOne ($ meeting_id); // n'envoie des rappels que pour les réunions confirmées si ($ mtg-> status! = Meeting :: STATUS_CONFIRMED) return false; // n'envoie que les rappels avec moins d'un jour de retard - à faire - à supprimer après la période de test si ((time () - $ mr-> due_at)> (24 * 3600 + 1)) return false; $ u = \ common \ models \ User :: findOne ($ user_id); // s'assure qu'il existe une clé d'authentification pour l'utilisateur destinataire if (vide ($ u-> clé_automatique)) return false;  // prépare les données pour le message // get time $ selected_time = Meeting :: getChosenTime ($ meeting_id); $ timezone = MiscHelpers :: fetchUserTimezone ($ user_id); $ display_time = Meeting :: friendlyDateFromTimestamp ($ selected_time-> start, $ timezone); // get place $ selected_place = Meeting :: getChosenPlace ($ meeting_id); $ a = ['user_id' => $ user_id, 'auth_key' => $ u-> auth_key, 'email' => $ u-> email, 'nom_utilisateur' => $ u-> nom_utilisateur]; // vérifie si le courrier électronique est correct et correct depuis sender_id if (User :: checkEmailDelivery ($ user_id, 0)) // Construit les liens absolus vers la réunion et les commandes $ links = ['home' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_HOME, 0, $ a ['user_id'], $ a ['auth_key']), 'view' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_VIEW, 0, $ a ['user_id'], $ a ['auth_key']), 'footer_email' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_EMAIL, 0, $ a [user_id ' ], $ a ['auth_key']), 'footer_block' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_BLOCK, 0, $ a ['user_id'], $ a ['auth_key']) , 'footer_block_all' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_BLOCK_ALL, 0, $ a ['user_id'], $ a ['auth_key']), 'running_late' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_RUNNING_LATE, 0, $ a ['user_id'], $ a ['auth_key']), 'view_map' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_VIEW_MAP, 0, $ a ['user_id'], $ a ['auth_key'])]; // envoyer le message $ message = Yii :: $ app-> mailer-> composer (['html' => 'reminder-html', 'text' => 'reminder-text'], ['meeting_id' => $ mtg-> id, 'sender_id' => $ user_id, 'user_id' => $ a ['user_id'], 'auth_key' => $ a ['auth_key'], 'display_time' => $ display_time, 'selected_place '=> $ selected_place,' links '=> $ links,' meetingSettings '=> $ mtg-> meetingSettings,]); if (! empty ($ a ['email'])) $ message-> setFrom (['[email protected]' => 'Planificateur de réunions']); $ message-> setTo ($ a ['email']) -> setSubject (Yii :: t ('frontend', 'Meeting Reminder:'). $ mtg-> subject) -> send ();  $ mr-> status = MeetingReminder :: STATUS_COMPLETE; $ mr-> update ();  

le Utilisateur :: checkEmailDelivery () La fonction vérifie que l'utilisateur n'a pas bloqué les courriels du système (ou de personnes particulières). Cela garantit que vous pouvez envoyer le rappel:

// vérifie si le courrier électronique est correct et correct depuis sender_id if (User :: checkEmailDelivery ($ user_id, 0)) // Construit les liens absolus vers la réunion et les commandes $ links = ['home' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_HOME, 0, $ a ['user_id'], $ a ['auth_key']), 'view' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_VIEW, 0, $ a ['user_id'], $ a ['auth_key']), 'footer_email' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_EMAIL, 0, $ a [user_id ' ], $ a ['auth_key']), 'footer_block' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_BLOCK, 0, $ a ['user_id'], $ a ['auth_key']) , 'footer_block_all' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_FOOTER_BLOCK_ALL, 0, $ a ['user_id'], $ a ['auth_key']), 'running_late' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_RUNNING_LATE, 0, $ a ['user_id'], $ a ['auth_key']), 'view_map' => MiscHelpers :: buildCommand ($ mtg-> id, Meeting :: COMMAND_VIEW_MAP, 0, $ a ['user_id'], $ a ['auth_key'])]; 

Ici se trouve le Utilisateur :: checkEmailDelivery méthode. Tout d'abord, il vérifie si l'utilisateur a complètement bloqué tous les courriels (espérons-le pas) ou si le message est envoyé par un utilisateur bloqué:

 Fonction statique publique checkEmailDelivery ($ user_id, $ sender_id) // vérifie si cet utilisateur_id reçoit un courrier électronique et si sender_id n'est pas bloqué // vérifie si tous ses messages sont désactivés $ us = UserSetting :: safeGet ($ user_id); if ($ us-> no_email! = UserSetting :: EMAIL_OK) return false;  // vérifie s'il n'y a pas d'expéditeur, c'est-à-dire une notification système if ($ sender_id == 0) return true;  // vérifie si l'expéditeur est bloqué $ ub = UserBlock :: find () -> where (['user_id' => $ user_id, 'block_user_id' => $ sender_id]) -> one (); if (! is_null ($ ub)) return false;  return true;  

Le nouveau modèle d'e-mail de rappel

Dans l'épisode Invitation à livrer votre réunion, j'ai écrit sur l'envoi de courriers électroniques dans le cadre Yii. Dans Raffiner les modèles de courrier électronique, j'ai décrit la mise à jour des modèles de nos nouveaux modèles réactifs basés sur Oxygen..

Voici le nouveau modèle de courrier électronique reminder_html.php:

   
Rappel de votre réunion
Juste un rappel de votre prochaine réunion à lieu-> nom; ?> (lieu-> voisinage; ?>, ) par téléphone ou vidéoconférence.
Cliquez ci-dessous pour voir plus de détails pour voir la page de la réunion.
"> Visitez la page de réunion
Options utiles:

view-> renderFile ('@ common / mail / section-footer-dynamic.php', ['links' => $ links])?>

Il comprend la date, l'heure et le lieu choisi (avec une adresse et un lien de carte). J'ai également ajouté le début d'une zone d'options utile avec une commande initiale, "Informez-les que je suis en retard":

Lorsque vous cliquez dessus, nous enverrons un e-mail ou un SMS au (x) autre (s) participant (s) vous indiquant que vous pourriez avoir cinq à dix minutes de retard Il n'y a rien d'autre à faire ou à taper pendant que vous êtes pressé.

Une éventuelle version mobile de Meeting Planner saura peut-être votre position GPS et leur indiquera à quelle distance vous vous trouvez. J'ai commencé à suivre des idées comme celle-ci dans Asana pour la planification des produits. Je demanderai aux déesses éditoriales Envato Tuts + (illustrées ci-dessous) si je peux écrire sur la mise en œuvre des fonctionnalités et le suivi des problèmes dans un futur tutoriel.

Améliorations des rappels

Le courrier électronique de rappel peut en réalité utiliser quelques fonctionnalités améliorées:

  • Terminer la mise en œuvre tardive du courrier électronique.
  • Affichage des informations de contact des autres participants, telles que les numéros de téléphone et les adresses électroniques. L'e-mail en retard peut indiquer uniquement les coordonnées de la personne en retard..
  • Afficher une carte Google statique indiquant l'emplacement de la réunion.
  • Lien vers une fonctionnalité pour demander ou exiger un report de la réunion.
  • Lien vers non seulement la carte mais les directions vers l'emplacement.
  • Lien pour ajuster vos rappels.

Il s’avère que la plupart de ces fonctionnalités nécessitent plus de travail que prévu dans ce tutoriel.. 

Par exemple, l'idée d'envoyer un e-mail en retard semble être une fonctionnalité simple, non? C'est un bon exemple du défi que les frameworks MVC posent parfois aux développeurs. L'implémentation d'une fonction de courrier électronique tardif en cours d'exécution nécessitait du code dans plusieurs fichiers, y compris un nouveau modèle de courrier électronique..

Implémentation de la fonctionnalité Running Late

Plutôt que de partager toutes les modifications de code requises pour cette fonctionnalité, je vais simplement résumer les endroits où des modifications étaient nécessaires dans le cadre:

  • Le mail de rappel avait besoin d'un lien avec une nouvelle commande
  • le COMMAND_RUNNING_LATE doit être défini dans le modèle et le contrôleur de la réunion et doit afficher un message de confirmation.

Voici un exemple de ce que vous voyez après avoir demandé l'envoi d'un avis de retard:

  • le sendLateNotice () méthode devait être construite dans Meeting.php
  • Le modèle de courrier électronique Late-html.php devait être créé. Cela inclut une option permettant à l’autre participant d’annoncer qu’il est «en retard aussi».
  • le UserContact :: buildContactString () La méthode devait être complétée pour inclure les coordonnées de la personne en retard..
  • le ACTION_SENT_RUNNING_LATE doit être créé pour enregistrer l'envoi d'un avis de retard au nom de cette personne dans le journal des réunions..
  • le sendLateNotice () la méthode devait vérifier le journal et afficher une erreur si la notification tardive avait déjà été envoyée une fois.

Voici ce que la notification tardive déjà envoyée affiche: 

Il fallait beaucoup de code pour implémenter ce qui semblait être un simple ajout. 

J'ai attendu de tester la fonctionnalité jusqu'à ce que tous les changements ci-dessus aient été apportés et j'ai été agréablement surpris de voir qu'ils fonctionnaient tous exactement comme prévu. Je n'ai eu qu'à apporter quelques modifications cosmétiques au texte.

Mise en œuvre de l'affichage des informations de contact du participant

Alors que cette fonctionnalité existait déjà pour les fichiers iCal, je devais la compléter pour les invitations à des réunions par courrier électronique. Donc j'ai étendu UserContact :: buildContactString ($ user_id, $ mode) pour $ mode = 'html'.

Voici le code mis à jour:

fonction statique publique buildContactString ($ user_id, $ mode = 'ical') // à faire - crée une vue pouvant être restituée $ contacts = UserContact :: getUserContactList ($ user_id); if (nombre (contacts)) == 0) renvoie "; si ($ mode == 'ical') $ str =";  else if ($ mode == 'html') $ str = '

'; $ str = \ common \ components \ MiscHelpers :: getDisplayName ($ user_id). ':'; if ($ mode == 'ical') $ str. = '\\ n'; else if ($ mode == 'html') $ str. = '
'; foreach ($ contacts en tant que $ c) if ($ mode == 'ical') $ str. = $ c-> type_amical. ':'. $ c-> info. ' ('. $ c-> détails.') \\ n '; else if ($ mode == 'html') $ str. = $ c-> type_amical. ':'. $ c-> info. '
'. $ c-> détails.'
'; if ($ mode == 'ical') $ str. = '\\ n'; else if ($ mode == 'html') $ str. = '

'; return $ str;

Je suis sûr qu'il faudra peaufiner les tests alpha et bêta, mais les fonctionnalités sont désormais là..

Vous pouvez voir les détails de contact affichés dans l'avis de retard complet ci-dessus, mais voici le segment qu'il génère:

Rappels de polissage

Dans l’ensemble, les choses se sont si bien déroulées avec ces dernières mini-fonctionnalités que j’ai ajouté le lien pour ajuster vos rappels à l’e-mail de rappel original..

Avec tout ce nouveau code, je suis certain d’améliorer et d’améliorer régulièrement la fonctionnalité des rappels au cours des prochaines semaines. Cependant, avec Meeting Planner, de nouvelles fonctionnalités sont souvent possibles, souvent avec peu de travail, car il existe un cadre et une base. Le modèle de données propres et le cadre MVC apportent régulièrement des améliorations incrémentielles relativement simples.

Tout cela fait de la création d’une start-up à la fois amusante et stimulante. Et travailler avec des dragons (certains jours, je ne peux pas croire qu'ils me paient pour le faire).

Et après?

Meeting Planner a réalisé des progrès considérables au cours des derniers mois. Je commence à expérimenter avec WeFunder sur la base 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. J'espère écrire plus à ce sujet dans un prochain tutoriel.

Et certainement, l'application présente encore de nombreuses lacunes. Assurez-vous de poster vos commentaires dans les commentaires ou ouvrez un ticket d'assistance..

J'espère que vous avez apprécié cet épisode. Surveillez les prochains tutoriels dans notre rubrique Construire votre démarrage avec la série PHP: il reste encore du travail de finition à faire, mais également de plus grandes fonctionnalités..

N'hésitez pas à ajouter vos questions et commentaires ci-dessous; Je participe généralement aux discussions. Vous pouvez également me joindre directement sur Twitter @reifman.

Liens connexes

  • Planificateur de réunion
  • Profil de financement de planificateur de réunion
  • Programmation avec Yii2: Mise en route
  • L'échange de développeurs Yii2