Building Your Startup: Preparing for Reminders

Final product image
What You'll Be Creating

This tutorial is part of the Building Your Startup With PHP series on Envato Tuts+. In this series, I'm guiding you through launching a startup from concept to reality using my Meeting Planner app as a real-life example. Every step along the way, I'll release the Meeting Planner code as open-source examples you can learn from. I'll also address startup-related business issues as they arise.

In this two-part series, I'll describe how we built the infrastructure for reminders and their delivery. This episode will focus on the infrastructure and user experience behind configuring reminders.

If you haven't tried out Meeting Planner yet, go ahead and schedule your first meeting. I do participate in the comment threads below, so tell me what you think! I'm especially interested if you want new features or to suggest topics for future tutorials.

As a reminder, all of the code for Meeting Planner is written in the Yii2 Framework for PHP. If you'd like to learn more about Yii2, check out our parallel series Programming With Yii2.

How Reminders Will Work

Initially, I had created some simple reminder options in the UserSetting table. However, I realized that users will want much more flexibility and control over when and how their reminders arrive.

People should be able to set reminders for 30 minutes before, 3 hours before, and 48 hours before—or only 1 hour before. It should be completely up to them. They should also be able to choose whether they want to receive reminders via email, SMS or both. Meeting Planner doesn't support SMS yet, but it will soon—there will be a tutorial about that too.

Here's an example of the flexibility that Apple Calendar offers:

Meeting Planner Reminders - Apple Calendar Reminder Alerts

Allowing People to Set Up Reminders

Let's build the infrastructure to support any number of user customizable meeting reminders.

Meeting Planner Reminders - Create a Reminder

The Reminder Table

First, I created a Reminder table to support one or more reminder requests by users for all their meetings. As is typical with Yii2, I created the table with a migration.

Here's the Yii console command to create a database migration:

Then I customized this skeleton file with the properties I need:

If a reminder is 48 hours before, duration_friendly and unit will be 48 and UNIT_HOURS, while the duration field will be held in seconds, e.g. 48 * 60 minutes * 60 seconds or 172,800 seconds before a meeting. This will help with both simplifying the user interface and processing reminders.

Reminder_type will specify email, SMS, or both.

Then I used Gii, its code scaffolding generator, to create MVC code quickly for the controller, model, and views. The initial user interface was ready in minutes. You can see the create a reminder form above and the reminder index below.

Meeting Planner Reminders - A persons customizable reminders

Initializing Reminders for Existing and New Users

By the time I began working on reminders, people were already using Meeting Planner to schedule meetings. So I need to initialize the Reminder table for existing people as well as each newly registered person.

I decided that there should be three default Reminders for users at first, scheduled for 3 hours, 1 day and 3 days before a meeting. The code below creates these reminders for a user:

But what does processNewReminder do? It builds rows in another table that I'll describe below.

Processing Reminders

It's great that we now have a way for users to provide default reminder choices for meetings. But how does the system know when to send reminders to each user for their meetings? That's more complicated.

For performance reasons, I decided it would be best to build a MeetingReminder table of its own. This would make a note of the user's default reminders as meetings are scheduled and track when to send out these reminders for each meeting. It's basically a meeting-specific reminder table reflecting each participant's configured reminder preferences.

As meeting times are updated, the MeetingReminder table entries for that meeting will need to change. Similarly, if a person updates their reminder preferences, scheduled reminders in the MeetingReminder table will also need to be refreshed.

Let's create the migration for the MeetingReminder table:

Here's the migration code; it's pretty simple. Basically, for each reminder, there is a MeetingReminder which corresponds to a reminder of a user for a meeting. It knows that a reminder is due_at a certain time and has a status which determines if it's been sent yet:

The background monitoring job will be able to sort the MeetingReminder table by time due and quickly know which small set of reminders actually need to be delivered. And it could track which ones have been sent for each meeting and participant.

Note: At this time, there's no feature that allows people to customize reminders for a specific meeting, so there's no user interface with the MeetingReminder table. I could add this later.

As I hinted at earlier, the MeetingReminder table turned out to create a lot of subtle complexity:

  • If people add, edit or delete reminders, this must be reflected in preconfigured meeting reminders.
  • If people change the time of a meeting or cancel it, the meeting reminders must be updated to reflect this.
  • If a person chooses not to attend a meeting, those reminders must be disabled.

Ultimately, building reminder functionality required a lot of helper functionality.

Here's a helper function that creates a MeetingReminder for a specific user for their reminder for a specific meeting. If the meeting has already passed, the status reflects that:

So, whenever a reminder is created, here's the code that creates all of the MeetingReminder entries for each of the user's meetings:

Basically, the code finds all the meetings for a person, whether they are organizer or participant, and creates a MeetingReminder entry for each of that person's reminders. For example, a person with three default reminder preferences and three meetings scheduled will have nine MeetingReminder table entries.

Handling the Creation of New Reminders

When a person creates a new reminder, we have code that sets the duration based on their settings and then creates a new MeetingReminder for all of their pending meetings:

Handling Changes to Reminders

If a user modifies a reminder, we need to update the MeetingReminder table for that reminder_id:

If the due_at time for a reminder has already passed, then we set its status as complete.

Handling When Meetings Are Finalized

When a Meeting is finalized, the time is set and we need to configure MeetingReminders based on each participant's Reminder settings. The setMeetingReminders method does this:

Handling When Meeting Times Change

Similarly, when a meeting time is changed after the fact (not yet supported in the current feature set), I created a simple function to remove and rebuild MeetingReminders for the new time:

A feature that seems simple at first turns out to require a lot of detail and oversight.

What's Next?

You've seen the foundation for reminders. In the next tutorial, I'll show you how we monitor time to know when and how to deliver reminders. And I'll show you how we deliver the reminders via email (SMS will come later).

Meeting Planner Reminders - Example of a Reminder Email

While you're waiting, try out the reminder feature, schedule your first meeting, and then update your reminder preferences. Also, I'd appreciate it if you share your experience below in the comments, and I'm always interested in your suggestions. You can also reach me on Twitter @reifman directly.

I'm also beginning to experiment with WeFunder based on the implementation of the SEC's new crowdfunding rules. Please consider following our profile there. I may write about this more as part of our series.

Watch for upcoming tutorials in the Building Your Startup With PHP series. In addition to reminders, there's also lots of polish work and a few more big features coming up.

Related Links

Tags:

Comments

Related Articles