Deze tutorial maakt deel uit van de Build Your Startup With PHP-serie op Envato Tuts +. In deze serie begeleid ik je door een opstart van concept naar realiteit te starten met behulp van mijn Meeting Planner-app als een realistisch voorbeeld. Elke stap die ik doe, zal ik de Meeting Planner-code vrijgeven als open-source voorbeelden waar je van kunt leren. Ik zal ook opstartgerelateerde zakelijke problemen aanpakken zodra deze zich voordoen.
In deze tweedelige serie zal ik beschrijven hoe we de infrastructuur voor herinneringen en de levering ervan hebben gebouwd. Deze aflevering zal zich richten op de infrastructuur en gebruikerservaring achter het configureren van herinneringen.
Als u Meeting Planner nog niet hebt uitgeprobeerd, kunt u uw eerste vergadering plannen. Ik neem wel deel aan de opmerkingen hieronder, dus vertel me wat je denkt! Ik ben vooral geïnteresseerd als je nieuwe functies wilt of onderwerpen wilt voorstellen voor toekomstige zelfstudies.
Ter herinnering: alle code voor Meeting Planner is geschreven in het Yii2 Framework voor PHP. Als je meer wilt weten over Yii2, bekijk dan onze parallelle serie Programming With Yii2.
Aanvankelijk had ik enkele eenvoudige herinneringsopties gemaakt in de tabel UserSetting. Ik realiseerde me echter dat gebruikers veel meer flexibiliteit en controle willen over wanneer en hoe hun herinneringen binnenkomen.
Mensen moeten in staat zijn om 30 minuten vóór, 3 uur vóór en 48 uur vóór of slechts 1 uur eerder herinneringen in te stellen. Het zou helemaal aan hen moeten zijn. Ze moeten ook kunnen kiezen of ze herinneringen willen ontvangen via e-mail, sms of beide. Meeting Planner biedt nog geen ondersteuning voor sms, maar binnenkort wel, daar zal ook een tutorial over zijn.
Hier is een voorbeeld van de flexibiliteit die Apple Agenda biedt:
Laten we de infrastructuur bouwen om een aantal door de gebruiker aanpasbare herinneringen voor vergaderingen te ondersteunen.
Eerst heb ik een herinneringstabel gemaakt om een of meer herinneringsverzoeken van gebruikers voor al hun vergaderingen te ondersteunen. Zoals typisch is voor Yii2, heb ik de tabel gemaakt met een migratie.
Hier is de Yii console-opdracht om een databasemigratie aan te maken:
./ yii migreren / create create_reminder_table maken
Vervolgens heb ik dit skeletbestand aangepast met de eigenschappen die ik nodig heb:
class m160503_234630_create_reminder_table verlengt Migration public function up () $ tableOptions = null; if ($ this-> db-> driverName === 'mysql') $ tableOptions = 'KARAKTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> createTable ('% reminder', ['id' => Schema :: TYPE_PK, 'user_id' => Schema :: TYPE_BIGINT. 'NOT NULL', 'duration_friendly' => Schema :: TYPE_INTEGER. 'NOT NULL DEFAULT 0', 'unit' => Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'duration' => Schema :: TYPE_INTEGER. 'NOT NULL DEFAULT 0', 'reminder_type' => Schema: : TYPE_SMALLINT. 'NOT NULL DEFAULT 0', 'created_at' => Schema :: TYPE_INTEGER. 'NOT NULL', 'updated_at' => Schema :: TYPE_INTEGER. 'NOT NULL',], $ tableOptions); $ this-> addForeignKey ('fk_reminder_user', '% reminder', user_id ',' % user ',' id ',' CASCADE ',' CASCADE ');
Als een herinnering 48 uur eerder is, duration_friendly
en eenheid
zal zijn 48
en UNIT_HOURS
, Terwijl de looptijd
veld wordt in seconden vastgehouden, bijvoorbeeld 48 * 60 minuten * 60 seconden of 172.800 seconden vóór een vergadering. Dit helpt zowel bij het vereenvoudigen van de gebruikersinterface als bij het verwerken van herinneringen.
Reminder_type
zal e-mail, sms of beide specificeren.
Toen gebruikte ik Gii, de code-scaffolding-generator, om MVC-code snel te maken voor de controller, het model en de views. De eerste gebruikersinterface was binnen enkele minuten gereed. U kunt het aanmaken van een herinneringsformulier hierboven en de herinneringsindex hieronder zien.
Tegen de tijd dat ik aan herinneringen begon te werken, gebruikten mensen al Meeting Planner om vergaderingen te plannen. Dus ik moet de herinneringstabel zowel voor bestaande personen als voor elke nieuw geregistreerde persoon initialiseren.
Ik heb besloten dat er eerst drie standaardherinneringen voor gebruikers moeten zijn, gepland voor 3 uur, 1 dag en 3 dagen vóór een vergadering. De onderstaande code maakt deze herinneringen voor een gebruiker:
publieke statische functie initialiseren ($ user_id) // beginherinneringen maken voor een gebruiker $ r1 = nieuwe herinnering (); $ r1-> user_id = $ user_id; $ r1-> duration_friendly = 3; $ r1-> unit = Herinnering :: UNIT_HOURS; $ r1-> reminder_type = Herinnering :: TYPE_EMAIL; $ r1-> duur = 3600; $ R1-> validate (); $ R1-> save (); $ r2 = nieuwe herinnering (); $ r2-> user_id = $ user_id; $ r2-> duration_friendly = 1; $ r2-> unit = Herinnering :: UNIT_DAYS; $ r2-> reminder_type = Herinnering :: TYPE_EMAIL; $ r2-> duur = 1 * 24 * 3600; $ R2-> save (); $ r3 = nieuwe herinnering (); $ r3-> user_id = $ user_id; $ r3-> duration_friendly = 3; $ r3-> unit = Herinnering :: UNIT_DAYS; $ r3-> reminder_type = Herinnering :: TYPE_EMAIL; $ r3-> duur = $ r3-> duration_friendly * 24 * 3600; $ R3-> save (); Herinnering :: processNewReminder ($ R1-> id); Herinnering :: processNewReminder ($ R2-> id); Herinnering :: processNewReminder ($ R3-> id);
Maar wat doet processNewReminder
do? Het bouwt rijen in een andere tabel die ik hieronder zal beschrijven.
Het is geweldig dat we nu een manier hebben waarop gebruikers standaardherinneringskeuzes voor vergaderingen kunnen bieden. Maar hoe weet het systeem wanneer herinneringen aan elke gebruiker moeten worden verzonden voor hun vergaderingen? Dat is ingewikkelder.
Om prestatieredenen heb ik besloten dat het het beste is om een MeetingReminder
eigen tafel. Dit zou een notitie maken van de standaardherinneringen van de gebruiker wanneer vergaderingen worden gepland en bijhouden wanneer deze herinneringen voor elke vergadering moeten worden verzonden. Het is eigenlijk een vergaderingspecifieke herinneringstabel die de vooraf ingestelde voorkeuren van elke deelnemer weergeeft.
Naarmate vergadertijden worden bijgewerkt, is de MeetingReminder
tabelitems voor die vergadering moeten worden gewijzigd. Evenzo, als een persoon zijn herinneringsvoorkeuren, geplande herinneringen in de update MeetingReminder
tabel moet ook worden vernieuwd.
Laten we de migratie voor de maken MeetingReminder
tafel:
./ yii migreren / create maken_meeting_reminder_table
Hier is de migratiecode; het is vrij eenvoudig. Kortom, voor elke herinnering is er een MeetingReminder
wat overeenkomt met een herinnering aan een gebruiker voor een vergadering. Het weet dat een herinnering is due_at
een bepaalde tijd en heeft een status die bepaalt of het al is verzonden:
class m160510_062936_create_meeting_reminder_table breidt Migration uit public function up () $ tableOptions = null; if ($ this-> db-> driverName === 'mysql') $ tableOptions = 'KARAKTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> createTable ('% meeting_reminder', ['id' => Schema :: TYPE_PK, 'meeting_id' => Schema :: TYPE_INTEGER. 'NOT NULL DEFAULT 0', 'reminder_id' => Schema :: TYPE_BIGINT. 'NOT NULL', 'user_id' => Schema :: TYPE_BIGINT. 'NOT NULL', 'due_at' => Schema :: TYPE_INTEGER. 'NOT NULL', 'status' => Schema :: TYPE_SMALLINT. ' NOT NULL DEFAULT 0 ',], $ tableOptions); $ this-> addForeignKey ('fk_meeting_reminder_user', '% meeting_reminder', user_id ',' % user ',' id ',' CASCADE ',' CASCADE '); $ this-> addForeignKey ('fk_meeting_reminder_meeting', '% meeting_reminder', meeting_id ',' % meeting ',' id ',' CASCADE ',' CASCADE ');
De achtergrondmonitoringtaak zal het kunnen sorteren MeetingReminder
tabel op tijd verschuldigd en snel weten welke kleine set herinneringen daadwerkelijk moet worden afgeleverd. En het kan bijhouden welke voor elke vergadering en deelnemer zijn verzonden.
Opmerking: op dit moment is er geen functie waarmee mensen herinneringen voor een specifieke vergadering kunnen aanpassen, dus er is geen gebruikersinterface met de MeetingReminder-tabel. Ik zou dit later kunnen toevoegen.
Zoals ik eerder al liet doorschemeren, de MeetingReminder
tabel bleek een heleboel subtiele complexiteit te creëren:
Uiteindelijk vereiste het bouwen van herinneringsfunctionaliteit veel hulpfunctionaliteit.
Hier is een hulpfunctie die een MeetingReminder
voor een specifieke gebruiker voor hun herinnering voor een specifieke vergadering. Als de vergadering al is aangenomen, geeft de status aan dat:
openbare statische functie maken ($ meeting_id, $ user_id, $ reminder_id, $ differential) // verwijder elke eerder bestaande vergaderreminder voor deze reminder_id en meeting_id MeetingReminder :: deleteAll (['meeting_id' => $ meeting_id, 'reminder_id' => $ reminder_id]); $ mtg = Meeting :: findOne ($ meeting_id); if (is_null ($ mtg)) return false; $ selected_time = Meeting :: getChosenTime ($ meeting_id); $ mr = nieuwe MeetingReminder; $ mr-> reminder_id = $ reminder_id; $ mr-> meeting_id = $ meeting_id; $ mr-> user_id = $ user_id; $ mr-> due_at = $ selected_time-> start- $ differentieel; if ($ mr-> due_at> time ()) $ mr-> status = MeetingReminder :: STATUS_PENDING; else $ mr-> status = MeetingReminder :: STATUS_COMPLETE; $ mr-> save ();
Dus, wanneer een herinnering wordt aangemaakt, hier is de code die alle maakt MeetingReminder
ingangen voor elk van de vergaderingen van de gebruiker:
public static function processNewReminder ($ reminder_id) $ rem = Reminder :: findOne ($ reminder_id); // vind alle vergaderingen waar deze gebruiker deel van uitmaakt // creëer een vergaderingsherinnering voor alle vergaderingen waarbij de maker van deze herinnering de organisator is $ mtgs = Meeting :: find () -> where (['owner_id' => $ rem-> user_id]) -> alle (); // om prestaties te doen - zou een open join hierboven kunnen toevoegen aan deelnemers voor elk ($ mtgs als $ m) MeetingReminder :: create ($ m-> id, $ rem-> user_id, $ rem-> id, $ rem-> looptijd); // maak een afspraakherinnering voor alle vergaderingen waarbij de maker van deze herinnering deelnemer is $ part_mtgs = Deelnemer: find () -> where (['participant_id' => $ rem-> user_id]) -> all (); foreach ($ part_mtgs als $ m) MeetingReminder :: create ($ m-> id, $ rem-> user_id, $ rem-> id, $ rem-> duur);
Kortom, de code vindt alle vergaderingen voor een persoon, of ze nu organisator of deelnemer zijn, en maakt een MeetingReminder
invoer voor elk van de herinneringen van die persoon. Een persoon met drie standaard herinneringsvoorkeuren en drie geplande vergaderingen heeft bijvoorbeeld negen MeetingReminder
tabel ingangen.
Wanneer een persoon een nieuwe herinnering maakt, hebben we een code die de duur instelt op basis van hun instellingen en vervolgens een nieuwe maakt MeetingReminder
voor al hun nog hangende vergaderingen:
public function actionCreate () $ model = nieuwe herinnering (); $ model-> user_id = Yii :: $ app-> gebruiker-> getId (); $ model-> duur = 0; if ($ model-> load (Yii :: $ app-> request-> post ())) $ model-> duration = $ model-> setDuration ($ model-> duration_friendly, $ model-> unit); if ($ model-> validate ()) $ model-> save (); Herinnering :: processNewReminder ($ model-> id); Yii :: $ app-> getSession () -> setFlash ('succes', Yii :: t ('frontend', 'Uw herinnering is aangemaakt voor alle huidige en toekomstige vergaderingen.')); return $ this-> redirect ('index'); else // set set flash Yii :: $ app-> getSession () -> setFlash ('error', Yii :: t ('frontend', 'Er is een probleem opgetreden bij het maken van uw herinnering.')); return $ this-> render ('create', ['model' => $ model,]);
Als een gebruiker een herinnering wijzigt, moeten we het bijwerken MeetingReminder
tafel voor dat reminder_id
:
public static function updateReminder ($ reminder_id) // wanneer gebruiker een herinnering bijwerkt, update alle herinneringen voor de vergadering $ new_reminder = Herinnering :: findOne ($ reminder_id); $ mrs = MeetingReminder :: find () -> where (['reminder_id' => $ reminder_id]) -> all (); // update elke herinneringsbijeenkomst voor elke ($ mrs als $ mr) $ chosen_time = Meeting :: getChosenTime ($ mr-> meeting_id); $ mr-> due_at = $ chosen_time-> start- $ new_reminder-> duration; if ($ mr-> due_at> time ()) $ mr-> status = MeetingReminder :: STATUS_PENDING; else $ mr-> status = MeetingReminder :: STATUS_COMPLETE; $ mr-> update ();
Als het due_at
tijd voor een herinnering is al verstreken, dan stellen we de status in als voltooid.
Wanneer een vergadering is voltooid, is de tijd ingesteld en moeten we configureren MeetingReminders
op basis van de herinneringsinstellingen van elke deelnemer. De setMeetingReminders
methode doet dit:
openbare statische functie setMeetingReminders ($ meeting_id, $ chosen_time = false) // wanneer een vergadering is afgerond, herinneringen instellen voor de gekozen tijd voor alle deelnemers $ mtg = Meeting :: findOne ($ meeting_id); if ($ chosen_time === false) $ chosen_time = Meeting :: getChosenTime ($ meeting_id); // deelnemerslijst maken voor organisator en deelnemers $ deelnemers = array (); $ Aanwezigen [0] = $ mtg-> owner_id; $ cnt = 1; foreach ($ mtg-> deelnemers als $ p) if ($ p-> status == Deelnemer :: STATUS_DEFAULT) $ deelnemers [$ cnt] = $ p-> deelnemer_id; $ Cnt + = 1; // voor elke deelnemer foreach ($ deelnemers als $ a) // voor hun herinneringen $ rems = Herinnering :: find () -> where (['user_id' => $ a]) -> all (); foreach ($ rems als $ rem) // maak een afspraakherinnering voor die herinnering op dat moment MeetingReminder :: create ($ meeting_id, $ a, $ rem-> id, $ rem-> duur);
Op dezelfde manier, wanneer een ontmoetingstijd is veranderd na het feit (nog niet ondersteund in de huidige functieset), heb ik een eenvoudige functie gemaakt om te verwijderen en opnieuw te bouwen MeetingReminders
voor de nieuwe tijd:
openbare statische functie processTimeChange ($ meeting_id, $ chosen_time) // wanneer een vergadertijd is ingesteld of gewijzigd, reset de herinneringen voor alle deelnemers // wis oude vergaderherinneringen voor alle gebruikers voor deze vergadering MeetingReminder :: deleteAll (['meeting_id '=> $ MEETING_ID]); // stel vergaderherinneringen in voor alle gebruikers voor deze vergadering // noteer elke gebruiker heeft verschillende herinneringen Herinnering :: setMeetingReminders ($ meeting_id, $ chosen_time);
Een functie die in eerste instantie eenvoudig lijkt, vereist veel details en overzicht.
U hebt de basis voor herinneringen gezien. In de volgende zelfstudie laat ik zien hoe we de tijd bijhouden om te weten wanneer en hoe herinneringen moeten worden afgeleverd. En ik laat je zien hoe we de herinneringen via e-mail bezorgen (sms komt later).
Probeer tijdens het wachten de herinneringsfunctie uit, plan uw eerste vergadering en werk vervolgens uw herinneringsvoorkeuren bij. Ik zou het ook op prijs stellen als u uw ervaringen hieronder in de opmerkingen deelt en ik ben altijd geïnteresseerd in uw suggesties. Je kunt me ook rechtstreeks op Twitter @reifman bereiken.
Ik begin ook te experimenteren met WeFunder op basis van de implementatie van de nieuwe crowdfundingregels van de SEC. Overweeg om ons profiel daar te volgen. Ik kan hierover meer schrijven als onderdeel van onze serie.
Kijk uit voor komende tutorials in de Building Your Startup With PHP-serie. Naast herinneringen, is er ook veel Pools werk en een paar meer grote functies die eraan komen.