Construire votre démarrage Approcher des améliorations majeures de fonctionnalités

Ce que vous allez créer

Ce tutoriel fait partie de la Construire votre démarrage avec la série PHP sur Envato Tuts +. 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.

Comment aborder les mises à jour majeures des fonctionnalités

Ces jours-ci, je travaille le plus souvent à ajouter de petites améliorations incrémentielles à Meeting Planner. Les bases fonctionnent plutôt bien et j'essaie d'améliorer progressivement l'application en fonction de ma vision et du retour des gens. Parfois, ma vision est un changement plus important, et cela peut être plus difficile maintenant que la base de code a tellement grandi.

Dans le tutoriel d'aujourd'hui, je vais parler des moyens de penser à apporter des modifications plus importantes à une base de code existante. Plus précisément, je vous expliquerai les effets de l’ajout de la possibilité, pour les participants à la réunion, de réfléchir ensemble et de décider des activités, c’est-à-dire ce que nous devrions faire lorsque nous nous rencontrons..

Si vous ne l'avez pas encore fait, essayez de planifier une réunion. Maintenant, vous pouvez également planifier une activité. Cela vous aidera à comprendre au fur et à mesure que vous avancez dans le tutoriel.

Avant de commencer, n'oubliez pas de partager vos commentaires et vos suggestions ci-dessous. Je les surveille et vous pouvez également me joindre sur Twitter @lookahead_io. 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.

La fonctionnalité de planification d'activité

En gros, Meeting Planner et Simple Planner sont conçus pour rendre la planification aussi simple que possible. Vous proposez quelques moments et endroits et vous le partagez avec une personne de plus pour qu’ils puissent peser sur les options. Ensuite, vous décidez ensemble et Meeting Planner conserve une trace des entrées d'agenda, des rappels et des moyens simples d'effectuer des ajustements après coup..

À titre d'exemple, voici une vidéo de planification pour les groupes:

Je voulais élargir le support de planification fourni pour les heures et les lieux au concept d'activités. Par exemple, lorsque vous planifiez une rencontre avec vos amis, vous demandez essentiellement si nous devons aller au cinéma, aller danser ou faire de la planche à neige..

En d'autres termes, je voulais créer un panneau comme celui des temps indiqués ci-dessous mais pour les activités: 

L'architecture de MVC et mon schéma de nommage de code sont très similaires entre les heures et les lieux de réunion. Les activités de construction semblaient donc assez simples en apparence. Cependant, la décision de le faire avait de vastes ramifications.

Portée des changements

Lors de l'ajout d'une fonctionnalité importante, il est important de penser à la fois aux endroits où le code doit changer et à tous les endroits de votre application susceptibles d'être affectés de réfléchir aux impacts..

Impact sur le client

Du point de vue de la conception, j'ai réfléchi à la manière dont les activités affecteront le service client:

  • Cela va changer en organisant une réunion pour permettre un nouveau type, un événement axé sur l'activité. Il y aura un panneau supplémentaire sur la page de planification.
  • Le panneau d’activité devra être conçu pour permettre aux utilisateurs de choisir des valeurs par défaut ou de personnaliser et d’ajouter les leurs, par exemple. skiez dans l’arrière-pays au lieu de simplement skier, "Allez voir Star Wars Rogue One" au lieu de "Allez voir un film".
  • Les invitations par courrier électronique devront inclure un espace pour répertorier les options d'activité..
  • Les événements du calendrier voudront intégrer l'activité choisie au sujet de la rencontre.
  • Les organisateurs peuvent vouloir envoyer des idées d’activités à un ami ou à un groupe sans avoir choisi de lieu. Je dois donc le permettre. Actuellement, le système ne vous permet pas d’envoyer une invitation tant qu’il n’ya pas au moins une heure et un lieu suggérés..
  • Si quelqu'un demande à modifier une réunion, la prise en charge des demandes de modification devra être étendue aux activités de support..

C'étaient la plupart des bases. Maintenant, réfléchissons au code.

Impacts du code

Branchement du code source

Il est souvent utile de créer votre propre code dans GitHub afin de pouvoir travailler sur la nouvelle fonctionnalité en plus de la base de code stable au niveau de la production. Cela vous permet de renvoyer et de corriger des bogues ou de faire des changements incrémentiels plus petits tout en travaillant sur un changement majeur. Les gens de GitHub sont plus stricts d’une manière qui a du sens pour les équipes:

Il n'y a qu'une seule règle: n'importe quoi dans le maîtriser la branche est toujours déployable.

Puisqu'il n'y en a qu'un et que je maîtrise assez bien mon code, je suis un peu plus laisser faire à propos de cette règle.

Mais le code de branchement est également utile pour examiner les modifications de code lorsque vous êtes prêt pour le test. Je partagerai une démonstration de ceci à la fin du tutoriel d'aujourd'hui.

Réplication du code commun

Il y aura maintenant deux types de réunions: celles basées uniquement sur les dates et heures et celles sur les activités, dates et heures. Le modèle de réunion doit donc s'adapter.

Pour les horaires et les lieux, il existe spécifiquement les modèles MeetingTime et MeetingPlace ainsi que des modèles pour les préférences de ceux-ci avec les participants, appelés MeetingTimeChoices et MeetingPlaceChoices. Vous pouvez en savoir plus sur la création de ce site dans Construire votre démarrage avec PHP: Planification de la disponibilité et des choix.

Donc, ajouter des activités nécessiterait essentiellement de les dupliquer, de créer MeetingActivity et MeetingActivityChoices et leurs contrôleurs, modèles, vues, migrations JavaScript et Ajax et de base de données,.

Paramètres du compte et de la réunion

En outre, les organisateurs préfèrent divers paramètres de compte et paramètres de réunion pour que les participants puissent suggérer et choisir l'activité finale..

Modèles de courrier électronique

L'ajout d'activités a également affecté les modèles de courrier électronique pour les invitations et les réunions terminées..

Historique des événements et journaux

Étant donné que chaque modification apportée à une réunion est enregistrée, chaque option d'activité et chaque modification doivent également l'être..

Autres domaines divers

Le fichier de calendrier .ics doit être modifié pour inclure l'activité. En fin de compte, il faudrait mettre à jour l’API et même les statistiques du tableau de bord administratif..

Bien que cela paraisse simple au départ, l’ajout d’activités nécessite en réalité beaucoup de nouveau code et de tests..

Points saillants du codage

Bien qu'il y ait trop de nouveau code à couvrir dans un tutoriel, passons en revue les aspects soulignés à partir de certains des concepts ci-dessus..

Migrations de bases de données

Tout d'abord, j'ai créé les migrations de bases de données. J'ai parlé plus tôt de la réplication de code avec des aspects de fonctionnalité en commun. Voici un exemple de migration MeetingActivity par rapport à la migration de table MeetingTime plus ancienne:

db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> createTable ('% meeting_activity' ', [' id '=> Schema :: TYPE_PK,' meeting_id '=> Schema :: TYPE_INTEGER.' NOT NULL ',' activity '=> Schema :: TYPE_STRING. 'NOT NULL', 'suggéré_by' => Schéma :: TYPE_BIGINT. 'NOT NULL', 'status' => Schéma :: TYPE_SMALLINT. 'NON NULL DEFAUT 0', 'disponibilité' => Schéma :: TYPE_SMALLINT. ' NOT NULL DEFAULT 0 ',' created_at '=> Schema :: TYPE_INTEGER.' NOT NULL ',' updated_at '=> Schema :: TYPE_INTEGER.' NOT NULL ',], $ tableOptions); $ this-> addForeignKey ('fk_meeting_activity_meeting', '% meeting_activity', 'id_reunion', '% meeting', 'id', 'CASCADE', 'CASCADE'); $ this-> addForeignKey ('fk_activity_suggested_by', '% meeting_activity', 'suggérées_by', '% user', 'id', 'CASCADE', 'CASCADE');  public function down () $ this-> dropForeignKey ('fk_activity_suggested_by', '% meeting_activity'); $ this-> dropForeignKey ('fk_meeting_activity_meeting', '% meeting_activity'); $ this-> dropTable ('% meeting_activity' ');  

Voici la migration de MeetingTime, et vous pouvez voir les similitudes:

db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> createTable ('% meeting_time', ['id' => Schema :: TYPE_PK, 'meeting_id' => Schema :: TYPE_INTEGER. 'NOT NULL', 'start' => Schema :: TYPE_INTEGER. 'NOT NULL', 'suggest_by' => Schéma :: TYPE_BIGINT. 'NOT NULL', 'status' => Schéma :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'created_at' => Schéma :: TYPE_INTEGER. ' NOT NULL ',' updated_at '=> Schema :: TYPE_INTEGER.' NOT NULL ',], $ tableOptions); $ this-> addForeignKey ('fk_meeting_time_meeting', '% meeting_time', 'id_reunion', '% meeting', 'id', 'CASCADE', 'CASCADE'); $ this-> addForeignKey ('fk_participant_suggested_by', '% meeting_time', 'suggérée_by', '% user', 'id', 'CASCADE', 'CASCADE');  public function down () $ this-> dropForeignKey ('fk_participant_suggested_by', '% meeting_time'); $ this-> dropForeignKey ('fk_meeting_time_meeting', '% meeting_time'); $ this-> dropTable ('% meeting_time');  

 Finalement, il me fallait cinq pour les nouvelles tables suivantes:

  1. m161202_020757_create_meeting_activity_table
  2. m161202_021355_create_meeting_activity_choice_table, pour stocker les préférences de disponibilité de chaque participant à la réunion pour chaque activité
  3. m161202_024352_extend_meeting_setting_table_for_activities pour les paramètres d'une réunion particulière pour l'ajout ou la sélection d'activités
  4. m161202_024403_extend_user_setting_table_for_activities pour les paramètres par défaut du compte
  5. m161203_010030_extend_meeting_table_for_activities et en ajoutant is_activity pour désigner la propriété d'une réunion avec ou sans activité 
./yii $ migrate / outil de migration jusqu'à Yû (basé sur Yii v2.0.10) au total 5 nouvelles migrations à appliquer: m161202_020757_create_meeting_activity_table m161202_021355_create_meeting_activity_choice_table m161202_024352_extend_meeting_setting_table_for_activities m161202_024403_extend_user_setting_table_for_activities m161203_010030_extend_meeting_table_for_activities Appliquer les migrations ci-dessus? (yes | no) [no]: yes *** application de m161202_020757_create_meeting_activity_table> créer une table % meeting_activity… done (heure: 0.032s)> ajouter une clé étrangère fk_meeting_activity_meeting: % meeting_activity (meeting_id) références  % meeting (id)… done (heure: 0.023s)> ajouter la clé étrangère fk_activity_suggested_by: % meeting_activity (suggérée_by) références % user (id)… done (heure: 0.006s) ** * appliqué m161202_020757_create_meeting_activity_table (time: 0.071s) *** application meeting_activity (id)… done (heure: 0.006s)> ajouter la clé étrangère fk_mac_user_id: % meeting_activity_choice (user_id) fait référence à % user (id)… done (heure: 0.004s) *** appliqué m161202_021355_create_meeting_activity_choice_table (time: 0.016s) *** application de m161202_024352_extend_meeti ng_setting_table_for_activities> ajouter une colonne participant_add_activité smallint NON NULL DEFAUT 0 à la table % meeting_setting ... done (heure: 0.013s)> ajouter une colonne participant_choose_activity smallint NON NULL DEFAUT 0 à la table % meeting_setting ... done (heure: 0.019s ) *** appliquée % user_setting… done (heure: 0.027s) *** appliqué s) *** appliqué m161203_010030_extend_meeting_table_for_activities (heure: 0.022s) 5 migrations ont été appliquées. Migré avec succès. 

Construire le cadre de travail pour le MVC

J'ai utilisé la capacité d'échafaudage Gii de Yii pour créer le modèle, le contrôleur et les vues initiales. J'ai couvert les migrations et Gii plus tôt dans la série.

Modifications JavaScript et jQuery

Des ajouts importants ont également été apportés à JavaScript et à jQuery utilisés, en particulier maintenant que l'interaction avec les éléments de planification pour une réunion est effectuée avec Ajax, sans rafraîchissement de la page..

Voici, par exemple, la boucle de code pour voir si une heure de réunion est choisie:

// répond au changement dans meeting_time $ (document) .on ("cliquez sur", '[id ^ = btn_mt_]', function (événement) current_id = $ (this) .attr ('id'); $ (this) .addClass ("btn-primary"); $ (ceci) .removeClass ("btn-default"); $ ('[id ^ = btn_mt _]'). each (fonction (index) if ($ (this). attr ('id')! = current_id) $ (this) .addClass ("btn-default"); $ (this) .removeClass ("btn-primary");); $ .ajax (url: $ ('# url_prefix'). val () + '/ meeting-time / choice', données: id: $ ('# meeting_id'). val (), 'val': id_ Current, succès: fonction (data ) displayNotifier ('choosetime'); refreshSend (); refreshFinalize (); return true;););

En utilisant un schéma de nommage commun, l'écriture du code pour les activités était réplicable à partir de ceci:

// répond au changement dans meeting_activity $ (document) .on ("cliquez sur", '[id ^ = btn_ma_]], function (événement) current_id = $ (this) .attr (' id '); $ (this) .addClass ("btn-primary"); $ (ceci) .removeClass ("btn-default"); $ ('[id ^ = btn_ma _]'). each (fonction (index) if ($ (this). attr ('id')! = current_id) $ (this) .addClass ("btn-default"); $ (this) .removeClass ("btn-primary");); $ .ajax (url: $ ('# url_prefix'). val () + '/ réunion-activité / choisir', data: id: $ ('# meeting_id'). val (), 'val': current_id, succès: function (data ) displayNotifier ('chooseactivity'); refreshSend (); refreshFinalize (); return true;););

D'autres fonctions, telles que celles qui affichent les réponses à l'utilisateur, devaient simplement être étendues pour les activités:

function displayNotifier (mode) if (notifierOkay) if (mode == 'time') $ ('# # notifierTime'). show ();  else if (mode == 'place') $ ('# notifierPlace'). show ();  else if (mode == 'Chooseplace') $ ('# notifierChoosePlace'). show ();  else if (mode == 'choosetime') $ ('# notifierChooseTime'). show ();  else if (mode == 'activité') $ ('# notifierPlace'). show ();  else if (mode == 'chooseactivity') $ ('# notifierChooseActivity'). show ();  else alert ("Nous informerons automatiquement l'organisateur lorsque vous aurez terminé les modifications.");  notifierOkay = false;  

Même avec une fonctionnalité reflétant les qualités des fonctionnalités existantes, les ajouts de nouveau code étaient considérables. Voici plus de JavaScript, par exemple. Ce code couvre beaucoup plus de la fonctionnalité interactive ajax des heures de réunion sur la page de planification:

function showActivity () if ($ ('# addActivity'). hasClass ("hidden")) $ ('# addActivity'). removeClass ("hidden"); $ ('. activité-formulaire'). removeClass ("hidden");  else $ ('# addActivity'). addClass ("caché"); $ ('. activité-formulaire'). addClass ("caché"); ; function cancelActivity () $ ('# addActivity'). addClass ("caché"); $ ('. activité-formulaire'). addClass ("caché");  function addActivity (id) activity = $ ('# meeting_activity'). val (); // ajax soumet le sujet et le message $ .ajax (url: $ ('# url_prefix'). val () + '/ meeting-activity / add', données: id: id, activité: encodeURIComponent (activité), , success: function (data) $ ('# meeting_activity'). val ("); loadActivityChoices (id); insertActivity (id); displayAlert ('activityMessage', 'activityMsg1'); return true;); $ ('#addActivity'). addClass ('hidden'); function insertActivity (id) $ .ajax (url: $ ('# url_prefix'). val () + '/ meeting-activity / insertactivity', données : id: id, tapez: 'GET', succès: fonction (données) $ ("# réunion-activité-liste"). html (données) .removeClass ('caché'); $ ("entrée [ name = 'meeting-activity-choice'] "). map (function () // $ (this) .bootstrapSwitch (); $ (this) .bootstrapSwitch ('onText', ' Oui'); $ (this) .bootstrapSwitch ('offText', ' non'); $ (this) .bootstrapSwitch ('onColor', 'success'); $ (this) .bootstrapSwitch ('offColor', 'danger'); $ (this) .bootstrapSwitch ('handleWidth', 50); $ (this) .bootstrapSwitch ('labelWidth', 1); $ (this) .bootstrapSwitch ('taille', 'petit'); ); ,); refreshSend (); refreshFinalize ();  function getActivities (id) $ .ajax (url: $ ('# url_prefix'). val () + '/ meeting-activity / getactivity', données: id: id,, tapez: 'GET', succès: fonction (données) $ ('# réunion-activité-liste'). html (données);,); 

Ajouts au cadre

Certes, il fallait ajouter des modèles, des contrôleurs et des vues. Voici un extrait du modèle MeetingActivity.php qui répertorie un certain nombre d'activités par défaut que l'utilisateur peut rapidement utiliser:

 SluggableBehavior :: className (), 'attribut' => 'nom', 'immuable' => vrai, 'assureUnique' => vrai,], * / 'horodatage' => ['classe' => 'yii \ comportements \ TimestampBehavior ',' attributs '=> [ActiveRecord :: EVENT_BEFORE_INSERT => [' created_at ',' updated_at '], ActiveRecord :: EVENT_BEFORE_UPDATE => [' updated_at '],],],],];  / ** * @inheritdoc * / public function rules () return [['' meeting_id ',' activity ',' suggéré_by ',],' requis '], [[' meeting_id ',' suggéré_by ',' status ',' created_at ',' updated_at '],' integer '], [[' 'activity'], 'string', 'max' => 255], [['suggéré_by'], 'exist', 'skipOnError' = > true, 'targetClass' => \ common \ models \ User :: className (), 'targetAttribute' => ['suggest_by' => 'id']], [['meeting_id'], 'exist', 'skipOnError '=> true,' targetClass '=> Meeting :: className (),' targetAttribute '=> [' meeting_id '=>' id ']],];  public static function defaultActivityList () $ activités = [Yii :: t ('frontend', 'Bachelor party'), Yii :: t ('frontend', 'Birthday party'), Yii :: t ('frontend' , 'Petit déjeuner'), Yii :: t ('frontend', 'Brunch'), Yii :: t ('frontend', 'Café, thé, bar à jus, et autres.'), Yii :: t ('frontend ',' Concert '), Yii :: t (' frontend ',' Counselling '), Yii :: t (' frontend ',' Cycling '), Yii :: t (' frontend ',' Dessert '), Yii :: t ('frontend', 'Dîner'), Yii :: t ('frontend', 'Promenade de chien'), Yii :: t ('frontend', 'Drinks'), Yii :: t ('frontend' , 'Dancing'), Yii :: t ('frontend', 'Bar'), Yii :: t ('frontend', 'Movies'), Yii :: t ('frontend', 'Happy hour'), ​​Yii :: t ('frontend', 'Randonnée'), Yii :: t ('frontend', 'Déjeuner'), Yii :: t ('frontend', 'Méditation'), Yii :: t ('frontend', 'Netflix and chill'), Yii :: t ('frontend', 'Party'), Yii :: t ('frontend', 'Protest'), Yii :: t ('frontend', 'Theatre'), Yii :: t ('frontend', 'Jouer aux jeux de société'), Yii :: t ('frontend', 'Jouer au scrabble'), Yii :: t ('frontend', 'Jouer aux jeux vidéo'), Yii :: t ('frontend', 'Running'), Yii :: t ('frontend', 'Shopping'), Yii :: t ('frontend', 'Sk iing '), Yii :: t (' frontend ',' Snowboarding '), Yii :: t (' frontend ',' Raquettes '), Yii :: t (' frontend ',' Stand up comedy '), Yii: : t ('frontend', 'Walking'), Yii :: t ('frontend', 'Regarder des films'), Yii :: t ('frontend', 'Regarder le sport'), Yii :: t ('frontend' , 'Volunteer'), Yii :: t ('frontend', 'Yoga'),]; retourner les activités $; 

Et voici un extrait de /frontend/views/activity/_form.php avec le widget TypeaheadBasic utilisant ce qui précède defaultActivityList ():

field ($ model, 'activity') -> label (Yii :: t ('frontend', 'Suggérer une activité')) -> widget (TypeaheadBasic :: classname (), ['data' => $ activities, ' options '=> [' placeholder '=> Yii :: t (' frontend ',' entrez vos suggestions '),' id '=>' meeting_activity ', //' class '=>' input-large form-control ' ], 'pluginOptions' => ['highlight' => true],]); ?> 

Mais il y a de nombreux changements dans le code en dehors des besoins du cadre commun. Voici le modèle Meeting.php peut envoyer(), la fonction qui détermine si l'utilisateur est autorisé à envoyer une invitation à une réunion. Il détermine si une réunion répond aux exigences minimales pour l'envoi, telles que l'heure et l'activité, ou l'heure et le lieu..

Ci-dessous, vous pouvez voir comment une nouvelle section a dû être ajoutée pour les activités:

fonction publique canSend ($ sender_id) // vérifie si une invitation peut être envoyée // req: un participant, au moins une place, au moins une fois $ cntPlaces = 0; foreach ($ this-> meetingPlaces as $ mp) if ($ mp-> status! = MeetingPlace :: STATUS_REMOVED) $ cntPlaces + = 1;  $ cntTimes = 0; foreach ($ this-> meetingTimes as $ mt) if ($ mt-> status! = MeetingTime :: STATUS_REMOVED) $ cntTimes + = 1;  $ cntActivities = 0; // pour chaque type de réunion if ($ this-> is_activity == Meeting :: IS_ACTIVITY) foreach ($ this-> meetingActivities en tant que $ ma) if ($ ma-> status! = MeetingActivity :: STATUS_REMOVED) $ cntActivities + = 1;  if ($ this-> owner_id == $ sender_id && count ($ this-> participants)> 0 && ($ cntPlaces> 0 || $ this-> isVirtual () || ($ this-> is_activity == Meeting :: IS_ACTIVITY && $ cntActivities> 0)) && $ cntTimes> 0 && ($ this-> is_activity == Meeting :: NOT_ACTIVITY || ($ this-> is_activity == Meeting :: IS_ACTIVITY && $ cntActivities> 0)) ) $ this-> isReadyToSend = true;  else $ this-> isReadyToSend = false;  return $ this-> isReadyToSend; 

Modèles de courrier électronique

La mise à jour des mises en page des courriers électroniques a nécessité une petite réflexion sur la conception et la meilleure façon de présenter les activités dans les invitations et les confirmations de réunions. Voici un exemple de l'invitation par courrier électronique mise à jour:

Essentiellement, si une réunion a une activité, l'invitation comprend une large ligne au-dessus des heures et des lieux, reproduisant à nouveau une grande partie du code existant pour les heures et les lieux:

   
Activités possibles
activité; ?>

participant_add_activity) ?>

Réflexion sur les changements

En fin de compte, la fonctionnalité d'activité a nécessité une nouvelle branche de code. Voici la demande de traction:

$ cd / var / www / mp && git tire la télécommande principale de l'origine: comptage d'objets: 183, terminé. remote: Compression d'objets: 100% (183/183), terminé. à distance: Total 183 (delta 115), réutilisé 0 (delta 0), pack-réutilisé 0 Réception d'objets: 100% (183/183), 111,48 Ko | 0 octet / s, fait. Résolution des deltas: 100% (115/115), terminé. De github.com:newscloud/mp * branche master -> FETCH_HEAD 923b514… cd16262 master -> origine / master Mise à jour de 923b514… cd16262 Common-components / components / MiscHelpers.php | 8 + - common / mail / finalize-html.php | 28 ++++++++ - common / mail / invitation-html.php | 39 ++++++++++++ - composer.lock | 228 ++++++++++++++++++++++++++++++++++++ ------------ ----------------------- console / migrations / m161202_020757_create_meeting_activity_table.php | 35 +++++++++++ console / migrations / m161202_021355_create_meeting_activity_choice_table.php | 34 +++++++++++ console / migrations / m161202_024352_extend_meeting_setting_table_for_activities.php | 22 +++++++ console / migrations / m161202_024403_extend_user_setting_table_for_activities.php | 24 ++++++++ console / migrations / m161203_010030_extend_meeting_table_for_activities.php | 22 +++++++ frontend / assets / AppAsset.php | 2 + - frontend / assets / HomeAsset.php | 2 + - frontend / assets / MapAsset.php | 2 + - frontend / assets / MeetingAsset.php | 2 + - frontend / config / main.php | 1 + frontend / controllers / DaemonController.php | 2 + - frontend / controllers / MeetingActivityChoiceController.php | 70 ++++++++++++++++++++++ frontend / controllers / MeetingActivityController.php | 261 ++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ frontend / controllers / MeetingController.php | 94 ++++++++++++++++++++++++++++++ - frontend / controllers / MeetingTimeController.php | 4 + - frontend / models / Fix.php | 9 + - frontend / models / Meeting.php | 125 ++++++++++++++++++++++++++++++++++++ ------ frontend / models / MeetingActivity.php | 260 +++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ frontend / models / MeetingActivityChoice.php | 158 +++++++++++++++++++++++++++++++++++++++++++++ + frontend / models / MeetingLog.php | 43 +++++++++++++ - frontend / models / MeetingPlaceChoice.php | 3 + - frontend / models / MeetingTimeChoice.php | 3 + - frontend / models / Participant.php | 2 + frontend / views / meeting-activity / _choices.php | 42 ++++++++++++++ frontend / views / meeting-activity / _form.php | 46 +++++++++++++++ frontend / views / meeting-activity / _list.php | 78 ++++++++++++++++++++++++++ frontend / views / meeting-activity / _panel.php | 81 +++++++++++++++++++++++++++ frontend / views / meeting-activity / _search.php | 39 +++++++++++++ frontend / views / meeting-activity / _thread.php | 15 +++++ frontend / views / meeting-activity / create.php | 21 +++++++ frontend / views / meeting-activity / index.php | 42 ++++++++++++++ frontend / views / meeting-activity / update.php | 23 ++++++++ frontend / views / meeting-setting / _form.php | 2 + frontend / views / meeting-time / _panel.php | 2 + - frontend / views / meeting-time / view.php | 4 + - frontend / views / meeting / _command_bar_planning.php | 11 +++ - frontend / views / meeting / _grid.php | 9 ++ - frontend / views / meeting / _panel_what.php | 1 + frontend / views / meeting / view.php | 22 +++++ - frontend / views / meeting / view_confirmed.php | 19 ++++++ frontend / views / meeting / viewactivity.php | 40 +++++++++++++ frontend / views / participant / _panel.php | 4 + - frontend / views / user-setting / _form.php | 7 ++ - frontend / web / css / site.css | 9 ++ - frontend / web / js / meeting.js | 284 ++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++ ------------------------- 49 fichiers modifiés, 2027 insertions (+) , 257 deletions (-) créent des attributs 100644 console / migrations / m161202_020757_create_meeting_activity_table.php mode création / 100644 console migrations / m161202_021355_create_meeting_activity_choice_table.php mode création / 100644 console migrations / m161202_024352_extend_meeting_setting_table_for_activities.php mode création / 100644 console migrations / m161202_024403_extend_user_setting_table_for_activities.php créer le mode console 100644 /migrations/m161203_010030_extend_meeting_table_for_activities.php crée le mode 100644 frontal / controllers / MeetingActivityChoiceController.php crée le mode /views/meeting-activity/_choices.php create mode 100644 frontend / views / meeting-activity / _form.php mode de création 100644 frontend / vues / activité-de-réunion / _list.php mode de création 100644 mode-vue / vues / activité-de-réunion / _panel.php mode de création 100644 mode / vues / activité-de-réunion / _search.php mode de création 100644 interface / mode view / meeting-activity / _thread.php 100644 mode frontend / views / meeting-activity / create.php mode création 100644 frontend / views / meeting-activity / index.php mode création 100644 frontend / views / meeting-activity / update. php create mode 100644 frontend / views / meeting / viewactivity.php 

C'était tellement gros que j'ai décidé de faire une vidéo amusante faisant défiler tous les changements dans GitHub avec la musique appropriée en fond sonore… profitez de:

Dans l’ensemble, la création de la fonctionnalité des activités m’a été difficile et utile de réfléchir à l’architecture du site et à la manière de progresser rapidement et de manière stable sur le code d’une base de démarrage unique. Utilisez la réplication, mais réfléchissez d'abord à l'étendue globale.

La fonctionnalité d'activité a fini par toucher plus de zones que prévu. 

En planifiant à l'avance, vous éviterez de vous perdre dans des pièges de codage sans fin pour de nouvelles fonctionnalités. Si vous vous trouvez dans une fosse profonde, un cauchemar de codage qui ne se termine tout simplement pas, vérifiez vos modifications apportées à votre branche de fonctionnalité, revenez au maître et travaillez sur autre chose. Ça aide à te vider la tête.

J'ai définitivement adopté une approche légèrement différente pour vous guider dans cet épisode, et j'espère que cela vous a été utile..

Avez-vous vos propres pensées? Des idées? Retour d'information? Vous pouvez toujours me joindre directement sur Twitter @lookahead_io. Surveillez les prochains tutoriels ici, dans la série Construire votre démarrage avec PHP. Il y a beaucoup de choses surprenantes devant nous.

Encore une fois, si vous n'avez pas encore essayé Meeting Planner ou Simple Planner, planifiez votre