I wanted to build something that allowed users to define a schedule of when emails were sent — alas nothing by default so I built a Trait that uses Laravel’s existing scheduling to do just this!
30 Second Version ⏱
I have created a trait you can add in Laravel that will give it a schedule on which you can check against. The example for usage is when a user wants to receive their daily email at 16:00 on weekdays only — easy if everyone is the same but not when somebody wants it every day! It uses the Laravel Scheduler methods such as everyTenMinutes() to make it easy to build a schedule. Trait code is Here
Long Version with Code!
The Idea 💡
Build a Basecamp like check in app that asks “What are you working on?”
The Issue 🤔
In Basecamp you can set for every check in a custom schedule so it sends every X days/weeks at Y time and ignores Z. Laravel does not support this directly using its Scheduler
The End Goal 😎
The aim is that every minute Laravel Scheduler runs and checks through a collection of user generated ‘Check-ins’ to see if they are due to be sent.
The Detail ✍️
Laravel has almost everything built into it already! Yay! But it is hidden as a trait and not exposed to you directly; what we want is to add this magic dust to a Model (I am using a model called Checkin) and be able to add a schedule to it, store it and check when it needs to run.
I went down a rabbit hole of cron on a previous project and when I came across this functionality need I found out Laravel has everything I need by having the cron-expression package included. This allows for parsing and testing a cron string to find out when it should be run.
Instead of creating a bespoke class implementing the scheduling logic I was able to wrap it onto a Trait HasSchedule that links up all the scheduling goodies and cron-expression.
So you have a collection of models each with a custom schedule set. How do they get called/ do something with Laravel Scheduler?! Well add it to the App\Console\Kernel.php
This code every minute checks every Checkin to see if it is due on this exact minute. If it is a job is dispatched that sends an email using that Checkin.
Things to Add 🚀
The code is super basic but does a lot of lifting so you don’t have to!
What could be added is more interaction with cron-expression so you can pass in a DateTime and it evaluates against that rather than now.
You could also include a scope such as areDue() that return the collection of those due right now
One more thing I think is possible is to auto schedule the minute checks in a model without the intermittent collection check in Kernel.php. This is my next challenge to get this into core so you can call $schedule->callClass(Checkin::class) or similar
My Code (Higher Order Function FTW! 🤘)
I hope this was helpful — if so let me know! And do send me a message with any questions 😄