Ce tutoriel fait partie des Envato Tuts+ Construire votre démarrage avec la série PHP. Dans cette série, je vous guide dans le lancement d’une startup du concept à la réalité en utilisant mes Planificateur de réunion application comme exemple de la vie réelle. À 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.
Au début de la phase de test de Meeting Planner alpha, la principale lacune était l'incapacité de modifier une réunion après sa planification. Ce n'est pas un problème facile. Est-il possible de changer une réunion sans la permission d'un participant? Ou devriez-vous demander? Ou bien, en fonction de votre rôle dans l’organisation de la réunion? Et si vous voulez juste demander s'il est acceptable de se réunir 15 minutes plus tard, cela devrait être facile, à droite?
Pour résoudre tout cela, il fallait réfléchir aux aspects sociaux de l’ajustement d’une réunion..
Au fil du temps, j'ai réalisé que la capacité d'ajuster facilement les réunions après leur planification pouvait faire ou défaire la marque Meeting Planner..
Dans notre dernier épisode sur la planification avancée, j’ai implémenté Faire des changements, qui permet à un organisateur ou à un participant disposant d’autorisations d’organiser à nouveau la réunion sans demander d’autorisation. Dans le tutoriel d'aujourd'hui, je vais vous guider dans la construction du Demander des modifications Infrastructure. Les participants doivent demander des modifications, puis les autres peuvent les accepter ou les refuser, ce qui affecte les détails du calendrier final de la réunion..
Pendant que vous lisez, j'espère que vous essayerez la nouvelle fonctionnalité "demander un changement" sur le site en direct et que vous partagerez vos réflexions et vos commentaires dans les commentaires ci-dessous. Je participe aux discussions, mais vous pouvez également me joindre à @reifman sur Twitter. Je suis toujours ouvert aux nouvelles idées de fonctionnalités de Meeting Planner ainsi qu'aux suggestions pour les futurs épisodes de la série..
Pour rappel, tout le code de Meeting Planner est fourni en open source et écrit dans le framework Yii2 pour PHP. Si vous souhaitez en savoir plus sur Yii2, consultez mes séries parallèles Programmer avec Yii2.
Commençons.
Outre les fonctionnalités d'affichage et de planification de la réunion, les modifications de demande ont nécessité plus de temps et de nouveau code que toute autre fonctionnalité de ce projet..
Comme je l'ai mentionné dans le dernier épisode, coder tout avec la sécurité de base prend un peu plus de temps que le prototypage rapide, mais la conception et la construction de cette fonctionnalité ont également touché de nombreux autres domaines de la plate-forme:
Ainsi, bien que ce ne soit pas une image parfaite des modifications apportées à cette fonctionnalité, voici des captures d'écran de l'extraction du code du serveur de production.
Voici les modifications apportées au code existant:
Et voici les nouveaux fichiers:
Il y avait beaucoup de nouveau code impliqué avec cette fonctionnalité.
Finalement, j'ai opté pour une architecture construite autour de deux tables. Le premier était Demandes
:
$ this-> createTable ('% request', ['id' => Schéma :: TYPE_PK, 'id_reunion' => Schéma :: TYPE_INTEGER. 'NOT NULL DEFAULT 0', 'id_remandeur' => Schéma: : TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'completed_by' => Schéma :: TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'time_adjustment' => Schéma :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'alter_time' => Schéma :: TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'meeting_time_id' => Schéma :: TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'place_adjustment' => Schéma :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'meeting_place_place_place' => Schema :: TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'note' => Schéma :: TYPE_TEXT. 'NOT NULL DEFAULT "" "," status "=> Schéma :: TYPE_SMALLINT." NOT NULL DEFAULT 0 "," created_at " => Schema :: TYPE_INTEGER. 'NOT NULL', 'updated_at' => Schéma :: TYPE_INTEGER. 'NOT NULL',], $ tableOptions); $ this-> addForeignKey ('fk_request_meeting', '% request', 'id_reunion', '% meeting', 'id', 'CASCADE', 'CASCADE'); $ this-> addForeignKey ('fk_request_user', '% request', 'requestor_id', '% user', 'id', 'CASCADE', 'CASCADE');
Voici les constantes qui expliquent davantage le modèle:
const STATUS_OPEN = 0; const STATUS_ACCEPTED = 10; const STATUS_REJECTED = 20; const STATUS_WITHDRAWN = 30; const TIME_ADJUST_NONE = 50; const TIME_ADJUST_ABIT = 60; const TIME_ADJUST_OTHER = 70; const PLACE_ADJUST_NONE = 80; const PLACE_ADJUST_OTHER = 90;
Il y aurait deux façons de régler l'heure: TIME_ADJUST_ABIT
, c'est-à-dire des intervalles de minutes ou d'heures plus tôt ou plus tard que l'heure choisie, ou TIME_ADJUST_OTHER
, un tout autre moment de réunion.
Et la deuxième table était RequestResponses
:
$ this-> createTable ('% request_response' ', [' id '=> Schema :: TYPE_PK,' request_id '=> Schema :: TYPE_INTEGER.' NON NULL DEFAULT 0 ',' responder_id '=> Schéma: : TYPE_BIGINT. 'NOT NULL DEFAULT 0', 'note' => Schéma :: TYPE_TEXT. 'NOT NULL DEFAULT ""', 'response' => Schéma :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'created_at' => Schema :: TYPE_INTEGER. 'NOT NULL', 'updated_at' => Schéma :: TYPE_INTEGER. 'NOT NULL',], $ tableOptions);
Fondamentalement, qui a demandé le changement, qui a répondu et quelle a été la réponse: accepter ou refuser.
La deuxième table est nécessaire pour un environnement à plusieurs participants.
Les organisateurs de la réunion et les participants peuvent accéder à Demander des modifications via le menu déroulant Les options menu que nous avons construit dans le dernier épisode:
RequestController.php's actionCreate ()
charge le formulaire à partir duquel la demande de l'utilisateur change:
Et voici où la complexité a commencé. Quels types de modifications les participants pourraient-ils demander??
Remarque: Je n'ai pas encore implémenté la possibilité d'ajouter de nouveaux lieux et horaires. À l'heure actuelle, vous pouvez choisir d'autres dates et lieux parmi ceux proposés au cours du processus de planification..
Le code pour créer la liste déroulante était complexe. J'ai fait en sorte que vous puissiez choisir des horaires deux heures et demie plus tôt ou plus tard, par incréments de 15 minutes proches de l'heure d'origine et par incréments de 30 minutes par la suite:
pour ($ i = 1; $ i<12;$i++) // later times if ($i<4 || $i%2 == 0) $altTimesList[$chosenTime->début + ($ i * 15 * 60)] = réunion :: friendlyDateFromTimestamp ($ heure choisie-> début + ($ i * 15 * 60), $ fuseau horaire, faux); // fois précédents $ previousIndex = ((12- $ i) * - 15); if ($ i% 2 == 0 || $ i> = 9) $ altTimesList [$ selectedTime-> start + ($ earlyIndex * 60)] = Réunion :: friendlyDateFromTimestamp ($ ChoisiTime-> start + ($ earlyIndex * 60) , $ timezone, false); $ altTimesList [$ selectedTime-> start] = ''; $ altTimesList [-1000] = Yii :: t ('frontend', 'Sélectionnez une autre heure ci-dessous'); ksort ($ altTimesList);
J'ai rempli $ altTimesList
avec les touches de chaque heure possible avec les valeurs de l'heure conviviale ajustées pour le fuseau horaire de l'utilisateur. Puis j'ai utilisé ksort ()
pour trier le menu déroulant si les temps plus tôt sont apparus avant plus tard.
L'un des conseillers de Meeting Planner (je n'en ai qu'un pour le moment), a suggéré d'indiquer l'heure de la réunion actuellement sélectionnée, ce que j'ai fait ci-dessous. J'ai également ajouté un séparateur avec l'option désactivée dans une liste déroulante.. Il divise les heures antérieures des heures ultérieures mais ne peut pas être sélectionné:
Voici le code déroulant, qui montre comment désactiver le séparateur en fonction de son $ currentStart
clé d'index:
field ($ model, 'altern_time') -> label (Yii :: t ('frontend', 'choisit une heure légèrement plus tôt ou plus tard que currentStartStr', '' currentStartStr '=> $ currentStartStr])) -> dropDownList ($ altTimesList, ['options' => [$ currentStart => ['disabled' => true]]]); ?>
Et, lorsque les participants veulent choisir l’une des autres fois, JQuery modifie les menus déroulants, ce qui complique encore la création des formulaires:
registerJsFile (MiscHelpers :: buildUrl (). '/ js / request.js', ['depend' => [\ yii \ web \ JqueryAsset :: className ()]); ?>
Voici /frontend/web/js/request.js:
$ ("# adjust_how") .change (function () if ($ ("# adjust_how") .val () == 50) $ ("# # choice_earlier"). addClass ('caché'); $ (" #choose_another "). addClass ('hidden'); else if ($ (" # adjust_how ") .val () == 60) $ (" # choice_earlier "). removeClass ('hidden'); $ (" #choose_another "). addClass ('hidden'); else $ (" # choice_earlier "). addClass ('hidden'); $ (" # choice_another "). removeClass ('hidden'););
Voici à quoi ressemble le formulaire avec les temps alternatifs cachés:
Différents lieux sont simplement intégrés dans la liste déroulante des lieux (comme vous pouvez le voir avec l'image en haut, en vedette).
Une fois la demande effectuée, nous informons le demandeur que d'autres participants à la réunion en seront informés. Et, chaque fois que des demandes actives pour une réunion existent, il existe un lien vers Les voir:
J'ai décidé que ce serait une approche simple et épurée pour permettre aux gens d'accéder aux demandes.
Voici la liste des demandes de réunion, le plus souvent une seule:
Request :: buildSubject ()
crée la chaîne ci-dessus en fonction du contenu de la demande, c'est-à-dire que l'heure et / ou le lieu ont changé:
Fonction statique publique buildSubject ($ request_id, $ include_requestor = true) $ r = Request :: findOne ($ request_id); $ requestor = MiscHelpers :: getDisplayName ($ r-> requestor_id); $ timezone = MiscHelpers :: fetchUserTimezone (Yii :: $ app-> user-> getId ()); $ rtime = "; $ place ="; switch ($ r-> time_adjustment) case Demande :: TIME_ADJUST_NONE: break; requête de requête :: TIME_ADJUST_ABIT: $ rtime = Meeting :: friendlyDateFromTimestamp ($ r-> heure_alternative, $ timezone); Pause; requête de requête :: TIME_ADJUST_OTHER: $ t = MeetingTime :: findOne ($ r-> meeting_time_id); if (! is_null ($ t)) $ rtime = Meeting :: friendlyDateFromTimestamp ($ t-> début, $ timezone) ;; Pause; if ($ r-> place_adjustment == Request :: PLACE_ADJUST_NONE || $ r-> place_adjustment == 0 && $ r-> meeting_place_id == 0) // ne fait rien else // récupère le lieu $ place = MeetingPlace :: findOne ($ r-> meeting_place_id) -> lieu-> nom; $ result = $ requestor.Yii :: t ('frontend', 'invité à se rencontrer à'); if ($ rtime == "&& $ place ==") $ result. = Yii :: t ('frontend', 'oops… aucun changement n'a été demandé.'); else if ($ rtime <> ") $ result. = $ rtime; if ($ place <>") $ result. = Yii :: t ('frontend', 'et'); if ($ place <> ") $ result. = $ place; return $ result;
Cette fonction est également utilisée à plusieurs reprises dans les notifications par courrier électronique..
Il y a aussi des limites dans RequestController.php qui empêchent les utilisateurs de faire plus d'une demande par réunion à la fois:
fonction publique actionCreate ($ meeting_id) // vérifie si le participant est (! Meeting :: isAttendee ($ meeting_id, Yii :: $ app-> user-> getId ())) $ this-> redirect (['site / authfailure ']); if (Request :: countRequestorOpen ($ meeting_id, Yii :: $ app-> user-> getId ())> 0) $ r = Request :: find () -> où (['meeting_id' => $ meeting_id ]) -> andWhere (['requestor_id' => Yii :: $ app-> user-> getId ()]) -> andWhere (['status' => Request :: STATUS_OPEN]) -> un (); Yii :: $ app-> getSession () -> setFlash ('info', Yii :: t ('frontend', 'Vous avez déjà une demande existante ci-dessous.')); return $ this-> redirect (['view', 'id' => $ r-> id]);
Voici la page de demande de vue montrant la limitation:
Si c'est votre propre demande, vous pouvez Retirer votre demande.
Comme vous pouvez le constater, de nombreuses fonctionnalités UX variées ont été créées pour cela. Et je ne vous ai pas montré quand des personnes autres que le demandeur répondent.
En construisant ces fonctionnalités, j’ai décidé de créer generic_html
et generic_text
modèles de courrier électronique ainsi qu'un réutilisable Request :: notify ()
fonction facilitant la diffusion de différents types d’annonces dans Meeting Planner.
Ici se trouve le Request :: create ()
méthode pour préparer un email:
fonction publique create () $ user_id = $ this-> requestor_id; $ meeting_id = $ this-> meeting_id; $ subject = Request :: buildSubject ($ this-> id); $ content = ['subject' => Yii :: t ('frontend', 'Modification demandée à votre réunion'), 'heading' => Yii :: t ('frontend', 'Demande de modification à votre réunion'), 'p1' => $ subject, 'p2' => $ this-> note, 'plain_text' => $ subject. ". $ this-> note. '...' .Yii :: t ('frontend', 'Répondre à la demande en visitant ce lien: '),]; $ button = [' text '=> Yii :: t (' frontend ',' Répondre à la requête '),' command '=> Réunion :: COMMAND_VIEW_REQUEST,' obj_id '=> $ this-> id,]; $ this-> notify ($ user_id, $ meeting_id, $ content, $ button); // ajouter au journal MeetingLog :: add ($ meeting_id, MeetingLog :: ACTION_REQUEST_SENT, $ user_id , 0);
le $ contenu
tableau est rempli pour l'objet du courrier électronique, l'en-tête du message et les paragraphes, tandis que le bouton $
tableau est utilisé pour tout bouton de commande tel que Répondre à une requête ou Voir la réunion.
Ici se trouve le notifier ()
méthode, semblable à la précédente envoyer()
et finaliser()
actions qui envoient un email:
fonction statique publique notify ($ user_id, $ meeting_id, $ content, $ button = false) // envoie un message générique basé sur les arguments $ mtg = Meeting :: findOne ($ meeting_id); // construit un tableau de participants pour tous les participants sans information de contact $ cnt = 0; $ participants = tableau (); foreach ($ mtg-> participants en tant que $ p) $ clé_auth = = commun \ modèles \ utilisateur :: find () -> où (['id' => $ p-> participant_id]) -> un () -> clé d'authentification; $ participants [$ cnt] = ['user_id' => $ p-> participant_id, 'auth_key' => $ auth_key, 'email' => $ p-> participant-> email, 'nomutilisateur' => $ p-> participant-> nom d'utilisateur]; $ cnt + = 1; // ajouter un organisateur $ auth_key = \ common \ models \ User :: find () -> où (['id' => $ mtg-> propriétaire_id]) -> one () -> auth_key; $ participants [$ cnt] = ['user_id' => $ mtg-> owner_id, 'auth_key' => $ auth_key, 'email' => $ mtg-> propriétaire-> email, 'username' => $ mtg-> propriétaire-> nom d'utilisateur]; // utilise ce code pour envoyer foreach ($ participants en tant que $ cnt => $ a) // vérifie si le courrier électronique est correct et correct pour cet expéditeur_id if ($ user_id! = $ a ['user_id'] && User :: checkEmailDelivery ($ a ['user_id'], $ user_id)) Yii :: $ app-> timeZone = $ timezone = MiscHelpers :: fetchUserTimezone ($ a ['user_id']); // Construit les liens absolus vers la réunion et les commandes $ links = ['home' => MiscHelpers :: buildCommand ($ mt--> 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, $ user_id, $ a ['user_id'], $ a ['auth_key']), 'footer_block_all' => MiscHelpers :: buildCommand ($ mt-> id, Meeting :: COMMAND_FOOTER_BLOCK_ALL, 0, $ a ['user_id'], $ a ['auth_key']),]; if ($ button! == false) $ links ['button_url'] = MiscHelpers :: buildCommand ($ mt--> id, $ button ['command'], $ button ['obj_id'], $ a ['user_id '], $ a [' auth_key ']); $ content ['button_text'] = $ button ['text']; // envoyer le message $ message = Yii :: $ app-> mailer-> composer (['html' => 'generic-html', 'text' => 'generic-text'], ['meeting_id' = > $ mtg-> id, 'sender_id' => $ user_id, 'user_id' => $ a ['user_id'], 'auth_key' => $ a ['auth_key'], 'links' => $ links, ' content '=> $ content,' meetingSettings '=> $ mtg-> meetingSettings,]); // à faire - ajouter le nom complet $ message-> setFrom (array ('[email protected] '=> $ mtg-> owner-> email)); $ message-> setReplyTo ('mp _'. $ mtg-> id. '@ meetingplanner.io'); $ message-> setTo ($ a ['email']) -> setSubject ($ content ['sujet']) -> send ();
La disposition generic_html.php est essentiellement basée sur le modèle de mise à jour textuelle simple dont j'ai parlé dans nos tutoriels sur les modèles de courrier électronique. Il fournit un moyen bien formaté de mettre à jour les participants par courrier électronique avec quelques paragraphes..
Voici le fichier de vue generic_html.php intégrant le $ contenu
et bouton $
Les données. Il vérifie les deuxième et troisième paragraphes, par exemple. $ p2
, $ p3
et bouton $
Les données:
salut ,
= Html::encode($content['p1']) ?>
") ?>= Html::encode($content['p2']); ?>
") ?>= Html::encode($content['p3']); ?>
"Cabine", Helvetica, Arial, sans serif; taille de police: 14px; poids de police: régulier; hauteur de ligne: 45px; mso-hide: tout; text-align: center; width: 155px "bgcolor =" # ff6f6f ">= Html::encode($content['button_text']); ?>
Voici un exemple de notification qui Rob Smith m'a demandé de changer l'heure et le lieu de la réunion (générés à partir du code ci-dessus):
Quand je clique Répondre à une requête, Je suis emmené au Demande de réponse
Contrôleur actionCreate ()
méthode:
Tout au long de l'application UX, j'ai intégré la possibilité pour les personnes de rédiger des notes fournissant un contexte pour les demandes et les réponses..
L'un des défis de ce formulaire consistait à déterminer comment diriger les réponses vers différentes méthodes de contrôleur en fonction du type de bouton de soumission sur lequel l'utilisateur avait cliqué. En d’autres termes, faire la distinction entre les différents clics du bouton Soumission POST.
fonction publique actionCreate ($ id) $ request = Request :: findOne ($ id); if (! Meeting :: isAttendee ($ request-> meeting_id, Yii :: $ app-> user-> getId ())) $ this-> redirect (['site / authfailure'])); // cet utilisateur a-t-il déjà répondu $ check = RequestResponse :: find () -> où (['request_id' => $ id]) -> andWhere (['responder_id' => Yii :: $ app-> user- > getId ()]) -> count (); if ($ check> 0) Yii :: $ app-> getSession () -> setFlash ('error', Yii :: t ('frontend', 'Désolé, vous avez déjà répondu à cette requête.')); return $ this-> redirect (['meeting / view', 'id' => $ request-> meeting_id]); if ($ request-> requestor_id == Yii :: $ app-> user-> getId ()) Yii :: $ app-> getSession () -> setFlash ('erreur', Yii :: t ('frontend ',' Désolé, je ne peux pas répondre à votre propre demande. ')); return $ this-> redirect (['meeting / view', 'id' => $ request-> meeting_id]); $ subject = Request :: buildSubject ($ id); $ model = new RequestResponse (); $ model-> request_id = $ id; $ model-> responder_id = Yii :: $ app-> user-> getId (); if ($ model-> load (Yii :: $ app-> request-> post ())) $ posted = Yii :: $ app-> request-> post (); if (isset ($ posted ['accept'])) // accepte $ model-> response = RequestResponse :: RESPONSE_ACCEPT; $ model-> save (); $ request-> accept ($ model); Yii :: $ app-> getSession () -> setFlash ('success', Yii :: t ('frontend', 'Demande acceptée. Nous mettrons à jour les détails de la réunion et en informerons les autres participants.')); else // rejette $ model-> response = RequestResponse :: RESPONSE_REJECT; $ model-> save (); $ demande-> rejeter (modèle $); Yii :: $ app-> getSession () -> setFlash ('success', Yii :: t ('frontend', 'Votre déclin a été enregistré. Nous informerons les autres participants.')); return $ this-> redirect (['/ meeting / view', 'id' => $ request-> meeting_id]); else return $ this-> render ('create', ['model' => $ model, 'subject' => $ subject, 'meeting_id' => $ request-> meeting_id,]);
Voici /frontend/views/request-response/_form.php:
= BaseHtml::activeHiddenInput($model, 'responder_id'); ?> = BaseHtml::activeHiddenInput($model, 'request_id'); ?> = $form->field ($ model, 'note') -> label (Yii :: t ('frontend', 'Inclure une note')) -> textarea (['rows' '=> 6]) -> hint (Yii :: t ('frontend', 'optionnel'))?>= Html::submitButton(Yii::t('frontend', 'Accept Request'), ['class' => 'btn btn-success', 'name' => 'accepter',])?> = Html::submitButton(Yii::t('frontend', 'Decline Request'), ['class' => 'btn btn-danger', 'nom' => 'rejeter', 'données' => ['confirmer' => Yii :: t ('interface', 'Êtes-vous sûr de vouloir refuser cette demande?'), 'méthode' => 'post',],])?>Essentiellement, je viens d'ajouter
prénom
valeurs de'Acceptez'
ou'rejeter'
à chaque bouton. Ensuite, cette valeur est livrée en tant que valeur publiée, comme indiqué:if ($ model-> load (Yii :: $ app-> request-> post ())) $ posted = Yii :: $ app-> request-> post (); if (isset ($ posted ['accept'])) // accepte $ model-> response = RequestResponse :: RESPONSE_ACCEPT; $ model-> save (); $ request-> accept ($ model); Yii :: $ app-> getSession () -> setFlash ('success', Yii :: t ('frontend', 'Demande acceptée. Nous mettrons à jour les détails de la réunion et en informerons les autres participants.')); else // rejette $ model-> response = RequestResponse :: RESPONSE_REJECT; $ model-> save (); $ demande-> rejeter (modèle $); Yii :: $ app-> getSession () -> setFlash ('success', Yii :: t ('frontend', 'Votre déclin a été enregistré. Nous informerons les autres participants.')); return $ this-> redirect (['/ meeting / view', 'id' => $ request-> meeting_id]);Lorsque le répondant accepte ou refuse la demande, un message flash leur est affiché et un courrier électronique est envoyé. En outre, la réunion n'a plus de demandes actives à afficher:
Ici se trouve le Changement demandé accepté email de notification:
Beaucoup se passe dans
Request :: accept ()
au dessous de:public function accept ($ request_response) // à faire - cela devra changer s'il y a plusieurs participants $ this-> status = Request :: STATUS_ACCEPTED; $ this-> update (); $ m = Meeting :: findOne ($ this-> meeting_id); // existe-t-il un nouveau commutateur horaire ($ this-> time_adjustment) case Request :: TIME_ADJUST_ABIT: // crée une nouvelle heure de réunion avec alternate_time $ this-> meeting_time_id = MeetingTime :: addFromRequest ($ this-> id); $ this-> update (); // marque comme sélectionné MeetingTime :: setChoice ($ this-> meeting_id, $ this-> meeting_time_id, $ request_response-> responder_id); Pause; case Request :: TIME_ADJUST_OTHER: // marque comme sélectionné MeetingTime :: setChoice ($ this-> meeting_id, $ this-> meeting_time_id, $ request_response-> responder_id); Pause; // existe-t-il un endroit différent if ($ this-> place_adjustment == Request :: PLACE_ADJUST_OTHER || $ this-> meeting_place_id! = 0) MeetingPlace :: setChoice ($ this-> meeting_id, $ this-> meeting_place_place_id, $ request_response-> responder_id); if ($ m-> isOwner ($ request_response-> responder_id)) // ils sont un organisateur $ this-> completed_by = $ request_response-> responder_id; $ this-> update (); MeetingLog :: add ($ this-> meeting_id, MeetingLog :: ACTION_REQUEST_ORGANIZER_ACCEPT, $ request_response-> responder_id, $ this-> id); else // ils sont participants MeetingLog :: add ($ this-> meeting_id, MeetingLog :: ACTION_REQUEST_ACCEPT, $ request_response-> responder_id, $ this-> id); $ user_id = $ request_response-> responder_id; $ subject = Request :: buildSubject ($ this-> id, true); $ p1 = MiscHelpers :: getDisplayName ($ user_id) .Yii :: t ('frontend', 'a accepté la demande:'). $ subject; $ p2 = $ request_response-> note; $ p3 = Yii :: t ('frontend', 'Vous recevrez une confirmation de réunion mise à jour reflétant ces modifications. Elle comprendra également une pièce jointe mise à jour pour votre calendrier.'); $ content = ['subject' => Yii :: t ('frontend', 'Modification demandée acceptée en réunion'), 'heading' => Yii :: t ('frontend', 'Modification demandée'), 'p1 '=> $ p1,' p2 '=> $ p2,' p3 '=> $ p3,' plain_text '=> $ p1. ". $ p2.". $ p3.'… '.Yii :: t (' frontend ',' Voir la réunion ici: '),]; $ button = ['text' => Yii :: t ('frontend', 'Voir la réunion'), 'command' => Meeting :: COMMAND_VIEW, 'obj_id' => 0,]; $ this-> notify ($ user_id, $ this-> meeting_id, $ content, $ button); // Modifie la réunion $ m-> augmentationSequence (); // renvoyer la finalisation - ce qui doit également être fait pour renvoyer l'invitation $ m-> finalize ($ m-> owner_id);Avant d'envoyer le courrier électronique, le calendrier des réunions est mis à jour pour refléter toute nouvelle date / heure et / ou nouvel endroit. Après l'envoi du courrier électronique, la réunion est finalisée. Ceci fournit une nouvelle mise à jour de la réunion avec le fichier de calendrier mis à jour à tous les participants:
Et après?
J'espère que vous avez apprécié ce tutoriel. La création de cette fonctionnalité a pris plus de temps que prévu, mais a bien fonctionné. Je pense que cela ajoute une dimension à la planification avec Meeting Planner unique en son genre.
Si vous ne l'avez pas encore fait, organisez votre première réunion avec Meeting Planner. J'ai continué à faire des progrès incroyables vers la version bêta, malgré les distractions (le codage est difficile):
Je prévois également d'écrire un tutoriel sur le financement participatif, alors merci de suivre notre page WeFunder Meeting Planner.
S'il vous plaît partager vos commentaires ci-dessous. Je suis toujours ouvert aux nouvelles idées de fonctionnalités et suggestions de sujets pour les prochains tutoriels. Vous pouvez également me contacter @reifman.
Restez à l'affût de tout cela et de plusieurs autres tutoriels à venir en consultant la série Construire son démarrage avec PHP. Et consultez certainement notre programmation avec la série Yii2 (Envato Tuts +).
Liens connexes
- Planificateur de réunion
- Suivre le profil de financement de Meeting Planner