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.
Augmenter la notoriété et l'utilisation de Meeting Planner est mon plus grand défi à l'heure actuelle. Sans de nombreuses contributions, il est difficile d'améliorer le produit et, sans croissance rapide, il est difficile d'attirer les investisseurs..
Je craignais que la marque Meeting Planner n'entraîne une incompréhension de l'utilité sociale de l'application, telle que la planification de rencontres amicales, de dates et de soirées.
De toute évidence, le choix des noms est limité par la disponibilité du domaine et / ou le budget que vous devez investir pour acheter des alternatives. Le planificateur de réunion semblait le meilleur à l'époque.
J'ai récemment remarqué que SimplePlanner.io était disponible, je l'ai donc enregistré et j'ai commencé à intégrer le domaine à côté du service Meeting Planner existant..
Il existe différentes approches pour ajouter des domaines à une application basée sur Yii2. Dans le tutoriel d'aujourd'hui, je vais couvrir les domaines les plus simples, en cours d'exécution, sur la même base de code..
Si vous n'avez pas encore essayé Meeting Planner, planifiez votre première réunion chez Simple Planner. Je participe aux commentaires ci-dessous, alors dites-moi ce que vous en pensez! Vous pouvez également me joindre sur Twitter @reifman. 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 et Simple 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.
Avant de commencer, j'aimerais aborder un aspect du défi de la création d'une startup..
J'ai travaillé sur cet épisode au cours du week-end, un "avantage" de #StartupLife. Je voulais partager quelques choses amusantes à ce sujet.
Premièrement, #StartupLife signifie souvent que vous n'avez pas le temps de finir de assembler IKEA Furniture, le tiroir le plus important:
Deuxièmement, cela signifie également de travailler dans des cafés dans des endroits amusants… Five Point Roasters à Portland, dans l'Oregon, possède une machine à bulles voisine (ou les gens y respirent des bulles):
Maintenant, revenons à l'objectif du tutoriel d'aujourd'hui…
Le modèle avancé Yii2 vous permet d’exécuter plusieurs sites dans une même arborescence de codes. J'ai utilisé son arborescence frontale pour créer Meeting Planner et son arborescence dorsale pour créer la suite d'outils administratifs du service. Aujourd’hui, cependant, je vais me concentrer sur le lancement d’un autre domaine par-dessus l’arborescence du front-end existant, ainsi que sur toutes les complexités, petites et grandes, qui vont de pair avec cet environnement..
Dans un prochain épisode, je couvrirai les sites de construction sur une troisième ou une quatrième arborescence, par exemple une API REST ou une startup associée à Meeting Planner (oui, une idée excitante vous attend)..
J'ai supposé qu'il serait assez simple (sans jeu de mots) de lancer Simple Planner, mais cela a pris quelques jours de travail.
Le travail simple consistait à configurer le serveur de base et à manipuler du code avec l’arbre Yii. Cependant, comme Meeting Planner est un service qui utilise beaucoup de courrier électronique (invitations, confirmations, annonces, mises à jour, etc.), il était important d'envoyer ces courriers électroniques avec le domaine à partir duquel les réunions ont été créées, soit SimplePlanner.io ou MeetingPlanner.io..
Je voulais aussi qu'il y ait une différenciation visuelle initiale entre les deux sites.
Commençons, et je vais progressivement révéler certaines des complexités que j'ai rencontrées.
Lorsque des personnes arrivent sur notre site par l'intermédiaire d'un navigateur, nous avons besoin d'un moyen dans Yii pour indiquer à tout le code exécuté le service à afficher: planificateur de réunion ou planificateur simple.?
Dans /frontend/config/main.php, il existe une configuration d'amorçage malheureusement nommée (car elle chevauche celle-ci avec Bootstrap) qui exécutera le code au début de l'appel de la structure:
'mp-frontend', 'name' => 'Meeting Planner', 'basePath' => dirname (__ DIR__), 'bootstrap' => ['log', '\ common \ components \ SiteHelper'], 'controllerNamespace' = > 'frontend \ controllers',
En plus d’appeler la journalisation ci-dessus, j’ai créé un composant à appeler nommé SiteHelper
:
Donc SiteHelper a tout le code pour personnaliser le service en fonction du site en cours d'exécution. Par exemple:
fonction privée commonMeetingPlanner () Yii :: $ app-> params ['site'] ['id'] = SiteHelper :: SITE_MP; Yii :: $ app-> params ['site'] ['domain'] = 'meetingplanner.io'; Yii :: $ app-> params ['site'] ['url'] = 'https://meetingplanner.io'; Yii :: $ app-> params ['site'] ['titre'] = Yii :: t ('frontend', 'Meeting Planner'); Yii :: $ app-> params ['site'] ['mtg'] = Yii :: t ('frontend', 'Meetings'); Yii :: $ app-> params ['site'] ['img'] = rand (2,3); Yii :: $ app-> params ['site'] ['navbar'] = 'navbar-inverse'; Yii :: $ app-> params ['site'] ['email_logo'] = 'https://meetingplanner.io/img/email-logo-mp.gif'; Yii :: $ app-> params ['site'] ['ga'] = 'UA-37244292-18'; fonction privée commonSimplePlanner () Yii :: $ app-> params ['site'] ['id'] = SiteHelper :: SITE_SP; Yii :: $ app-> params ['site'] ['domain'] = 'simpleplanner.io'; Yii :: $ app-> params ['site'] ['url'] = 'https://simpleplanner.io'; Yii :: $ app-> params ['site'] ['titre'] = Yii :: t ('frontend', 'Simple Planner'); Yii :: $ app-> params ['site'] ['mtg'] = Yii :: t ('frontend', 'Meetups'); Yii :: $ app-> params ['site'] ['img'] = rand (0,1); Yii :: $ app-> params ['site'] ['navbar'] = 'navbar-default'; Yii :: $ app-> params ['site'] ['email_logo'] = 'https://simpleplanner.io/img/email-logo-sp.gif'; Yii :: $ app-> params ['site'] ['ga'] = 'UA-37244292-21';
Ces fonctions changent les variables, les URL et les chaînes en fonction du service demandé. Ceux-ci sont appelés par le SiteHelper :: init ()
une fonction:
commonMeetingPlanner (); Yii :: $ app-> params ['site'] ['url'] = 'http: // localhost: 8888 / mp /'; Yii :: $ app-> params ['site'] ['ga'] = "; else if (stristr ($ baseUrl, '/ sp /')! == false) // local sp $ this-> commonSimplePlanner (); Yii :: $ app-> params ['site'] ['url'] = 'http: // localhost: 8888 / sp /'; Yii :: $ app-> params ['site'] [ 'ga'] = "; else if (stristr ($ baseUrl, 'simple')! == false) // simpleplanner.io $ this-> commonSimplePlanner (); else // meetingplanner.io $ this-> commonMeetingPlanner (); parent :: init ();
Les fonctions ci-dessus remplacent également les paramètres lors de l'appel de localhost: 8888
sites de développement.
Planificateur de réunion est SITE_MP
, Simple Planner is SITE_SP
, et SITE_FD
est mon secret de vous (pour l'instant).
Pour le moment, j'ai décidé de modifier rapidement l'apparence de Simple Planner (SP) et de Meeting Planner (MP) en utilisant les deux barres de navigation par défaut de Bootstrap 3.0..
Vous remarquerez ci-dessus les utilisations de MP Yii :: $ app-> params ['site'] ['navbar'] = 'navbar-default';
et SP utilise 'navbar-inverse';
.
Dans /frontend/views/layouts/home.php et main.php, ils sont appliqués de la manière suivante:
Yii :: $ app-> params ['site'] ['title']. ' Aperçu', //' brandUrl '=> Yii :: $ app-> homeUrl,' options '=> [' class '=> Yii :: $ app-> params [' site '] [' barre de navigation '].' navbar-fixed-top ',],
Cela crée les deux jeux de couleurs différents de la barre de navigation:
Mais qu'en est-il des images de couverture? J'ai autorisé deux images sociales ludiques pour SP et deux autres images professionnelles sérieuses pour MP.
Les images pivotent de manière aléatoire en fonction du service actif, les noms de fichiers d’images se terminant numériquement par 0, 1, 2 ou 3, par ex. /img/home/home-#.jpg.
Yii :: $ app-> params ['site'] ['img'] = rand (2,3);
Voici le code de mise en page home.php qui l’applique à l’image choisie:
beginBody ()?>Si vous actualisez les pages d'accueil pour SimplePlanner.io ou MeetingPlanner.io, les images oscillent..
Mise à jour du texte, des images et des liens
Les variables de SiteHelper ci-dessus permettent de personnaliser les étiquettes textuelles sur l'ensemble du site. Et à l'avenir, je peux le faire de manière plus détaillée:
Yii :: $ app-> params ['site'] ['titre'] = Yii :: t ('frontend', 'Meeting Planner'); Yii :: $ app-> params ['site'] ['mtg'] = Yii :: t ('frontend', 'Meetings');Pendant que MP appelle les réunions, je pourrais changer globalement de SP pour utiliser les expressions sociales les plus sociales:
Yii :: $ app-> params ['site'] ['titre'] = Yii :: t ('frontend', 'Simple Planner'); Yii :: $ app-> params ['site'] ['mtg'] = Yii :: t ('frontend', 'Meetups');Configuration des services
Meeting Planner utilise de nombreux services pour organiser la planification. Leur initialisation a pris le plus de temps.
Google Analytics et console de recherche
Google rend difficile l'utilisation de plusieurs domaines avec Analytics. Je les ai donc simplement divisés en différents comptes. Le SiteHelper configure le code GA:
Yii :: $ app-> params ['site'] ['ga'] = 'UA-37244292-18';Ensuite, ils sont définis dans les vues de mise en page Home.php et Main.php:
Il existe également un paramètre de domaine pour la console de recherche Google que j'ai configuré chez mon registraire (voir ci-dessous):
Connexion OAuth
Et, depuis que j'ai ajouté la connexion sociale via OAuth pour Facebook, Google et LinkedIn, je devais parler à tous ces services du domaine SimplerPlanner.io. Google et LinkedIn sont les plus déroutants, car chaque variante d'argument de requête doit être enregistrée auprès de ces génies:
Voici Google:
Voici le simple LinkedIn:
Mais Facebook est le plus simple et le moins difficile (gardez juste les images d'allaitement au minimum):
Mailgun Email
Depuis que j'utilise Mailgun pour envoyer des courriels, j'ai créé un compte de domaine pour Simple Planner avec eux:
Cela a nécessité des changements soigneux chez mon registraire de domaine:
SSL
J'utilise Let's Encrypt pour le https (SSL) avec Meeting Planner et son service administratif principal. Les installer s'est très bien passé pour moi. Mais ajouter SimplePlanner.io n'a pas fonctionné et j'ai finalement dû créer des fichiers de configuration Apache (.conf) distincts pour SP et personnaliser les fichiers moi-même..
Voici le fichier http sp.conf qui redirige vers https:
ServerName simpleplanner.io ServerAlias www.simpleplanner.io DocumentRoot "/ var / www / mp / frontend / web" AllowOverride All RewriteEngine sur RewriteCond% SERVER_NAME = simpleplanner.io [OU] RewriteCond% SERVER_NAME = www.simpleplanner.io RewriteRule ^ https: //% SERVER_NAME% REQUEST_URI [FIN, QSA, R = permanent]Les redirections ne fonctionnaient tout simplement pas avec deux noms de serveur et deux alias de serveur. Voici le fichier sp-ssl.conf:
ServerName simpleplanner.io ServerAlias www.simpleplanner.io DocumentRoot "/ var / www / mp / frontend / web" AllowOverride All RewriteEngine sur RewriteCond% SERVER_NAME = www.simpleplanner.io RewriteRule ^ https: //simpleplanner.io% REQUEST_URI [FIN, QSA, R = permanent] SSLCertificateFile /etc/letsencrypt/live/simpleplanner.io SSLCertificateKeyFile /etc/letsencrypt/live/simpleplanner.io/privkey.pem Incluez /etc/letsencrypt/options-ssl-apache.conf SSLCertificateChainFile /etc/letsencrypt/live/simpleplanner.io/chain.pemVoici comment j'ai finalement créé les certificats SSL avec Let's Encrypt:
cd / opt / letsencrypt / sudo ./letsencrypt-auto --apache -d simpleplanner.io -d www.simpleplanner.io -dLet's Encrypt est génial, mais ils sont encore jeunes et, même si leurs scripts continuent à devenir plus robustes, il existe encore parfois des problèmes comme celui-ci..
Différenciation du courrier électronique en arrière-plan
Le plus gros défi pour moi lors du lancement de Simple Planner était de traiter les emails de fond de sorte qu'ils provenaient du service approprié, à savoir MP ou SP, et tous leurs liens le faisaient également..
Depuis que j'ai gardé la base de données unifiée pour SP et MP, j'ai également laissé le traitement en arrière-plan à effectuer sur le domaine MP. J'ai donc dû étendre la base de données pour que la table User and Meeting enregistre un
ID du site
colonne pour indiquer quel service a créé chaque entrée.Voici la migration de la base de données Yii:
db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> addColumn ('% meeting', 'id_site ", Schema :: TYPE_SMALLINT.' NOT NULL DEFAULT 0 '); $ this-> addColumn ('% user', 'id_site', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); public function down () $ this-> dropColumn ('% meeting', 'id_site'); $ this-> dropColumn ('% user', 'id_site');J'ai utilisé le
beforeSave ()
méthode dans le modèle de réunion pour toujours configurer unID du site
En fonction du service actuel, vous vous souviendrez peut-être que j'ai créé cette méthode pour toujours générer un identifiant unique sécurisé pour chaque réunion:fonction publique beforeSave ($ insert) if (parent :: beforeSave ($ insert)) if ($ insert) $ this-> identificateur = Yii :: $ app-> security-> generateRandomString (8); $ this-> site_id = Yii :: $ app-> params ['site'] ['id']; return true;J'ai créé un similaire pour le modèle utilisateur:
fonction publique beforeSave ($ insert) if (parent :: beforeSave ($ insert)) if ($ insert) $ this-> id_site = Yii :: $ app-> params ['site'] ['id'] ; return true;Tout au long du service, j'utilise le
MiscHelpers :: buildCommand ()
méthode de construction de liens sécurisés qui n'exigent pas que les utilisateurs se connectent chaque fois qu'ils répondent à un courrier électronique.J'ai pensé qu'il serait facile de personnaliser cette commande en un seul endroit pour créer un lien vers le domaine de site approprié. Toutefois, cela nécessiterait que cette méthode fréquemment utilisée interroge la table Meeting pour la
ID du site
à plusieurs reprises. Par exemple, lebuildCommand ()
est appelé un certain nombre de fois pour chaque participant pour chaque réunion.Pour des raisons de performances, j'ai décidé de modifier tous les appels de cette fonction pour inclure
ID du site
. Par exemple, tous ces appels ont dû être modifiés comme indiqué ci-dessous:foreach ($ this-> participants en tant que $ p) if ($ p-> status! = Participant :: STATUS_DEFAULT) continue; // Construit les liens absolus vers la réunion et les commandes $ auth_key = \ common \ models \ User :: find () -> Où (['id' => $ p-> participant_id]) -> one () -> clé d'authentification; $ links = ['home' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_HOME, 0, $ p-> participant_id, $ auth_key, $ this-> site_id), 'view' => MiscHelpers: : buildCommand ($ this-> id, Meeting :: COMMAND_VIEW, 0, $ p-> participant_id, $ clé_auth, $ this-> site_id), 'finalize' => MiscHelpers :: buildCommand ($ this-> id), réunion: : COMMAND_FINALIZE, 0, $ p-> participant_id, $ clé_auth, $ this-> site_id), 'cancel' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_CANCEL, 0, $ p-> participant_id, $ auth_key, $ this-> site_id), 'décliner' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_DECLINE, 0, $ p-> participant_id, $ auth_key, $ this-> site_id), ' acceptall '=> MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_ACCEPT_ALL, 0, $ p-> identifiant_serveur, $ clé_auth, $ this-> identifiant_site),' acceptplaces '=> MiscHelpers :: buildCommand ($ this -> id, Meeting :: COMMAND_ACCEPT_ALL_PLACES, 0, $ p-> ID_participant, $ clé_auth, $ this-> site_id), 'accepttimes' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_ACCEPT_ALL_TIMES, 0, $ p-> participant_id, $ auth_key, $ this-> site_id), 'addplace' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_ADD_PLACE, 0, $ p-> ID_serveur, $ clé_auth, $ this-> site_id), 'addtime' => MiscHelpers :: buildCommand ($ this->) id, Meeting :: COMMAND_ADD_TIME, 0, $ p-> id_participant, $ clé_auth, $ this-> id_site), 'addnote' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_ADD_NOTE, 0, $ p -> participant_id, $ clé_auth, $ this-> site_id), 'footer_email' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_FOOTER_EMAIL, 0, $ p-> participant_id, $ auth_key, $ this-> site_id), 'footer_block' => MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_FOOTER_BLOCK, $ this-> owner_id, $ p-> participant_id, $ auth_key, $ this-> site_id), 'footer_block_all' = > MiscHelpers :: buildCommand ($ this-> id, Meeting :: COMMAND_FOOTER_BLOCK_ALL, 0, $ p-> participant_id, $ auth_key, $ this-> site_id),];Le modèle de réunion est toujours chargé avant ces appels. Vous devez donc accéder à la
ID du site
est le plus rapide d'ici.Et après?
Bien que toutes les configurations et les petites modifications variables de ce site aient été un peu gênantes à mettre en place, cela présente quelques fonctionnalités intéressantes du framework Yii. Si vous ne l'avez pas encore fait, essayez de planifier la planification sur le nouveau site, Simple Planner..
Partagez Meeting Planner avec vos associés et Simple Planner avec vos amis et votre famille.
Avez-vous vos propres pensées? Des idées? Retour d'information? Vous pouvez toujours me joindre directement sur Twitter @reifman. Surveillez les prochains tutoriels ici dans la série Construire votre démarrage avec PHP.
Je me rapproche également du lancement de l'expérience avec WeFunder basée sur la mise en œuvre des nouvelles règles de la SEC en matière de financement participatif. Vous pouvez suivre notre profil ici si vous le souhaitez. Je vais aussi écrire plus à ce sujet dans un prochain tutoriel.
Liens connexes
- Planificateur simple ou planificateur de réunion
- Page WeFunder de l'organisateur de réunions
- Programmation avec Yii2: Mise en route