Human readable Intervals
Every Laravel application has several configuration values that represent a given amount of seconds or minutes.
Like the session.lifetime
, auth.password_timeout
, queue.connections.*.retry_after
and a lot more.
By default all these values are a single integer like 10800
, some of them even missing the unit in the description.
Multiplication
I bet that most of you know and have already done the easiest way - replace the single integer with a multiplication like 3 * 60 * 60
which is the same as 10800
.
Another benefit is that you can guess what's the interval as it's days * minutes * seconds
.
But there are still problems:
- it requires brain capacity to parse the multiplication
- not all intervals are seconds - how would you differentiate between
10 * 60
(10 hours in minutes) and10 * 60
(10 minutes in seconds) - it gets even harder when you need an interval like "2 days 6 hours" in seconds
(2 * 24 * 60 * 60) + (6 * 60 * 60)
Luckily there's a solution for both issues.
Carbon Interval
Some time ago @marcelpociot posted this solution on Twitter.
If you don't know the class already - the nesbot/carbon (required by Laravel itself) provides the \Carbon\CarbonInterval
class (docs).
This class comes with a human-readable fluent API to write your interval however you want.
The important part is the magic property totalSeconds
- similar properties exist for minutes, days and so on.
use Carbon\CarbonInterval;
CarbonInterval::days(2)->hours(6)->totalSeconds;
This is helpful in every part of your application - not only the configuration but also the real app code, for example cache TTL, signed URL expiration and wherever you need a given amount of seconds, minutes or other time units.
Constants
@devfrey asked how this works with constants.
Short: it doesn't.
I would recommend using the multiplication or single integer solution with an explanatory comment. I'm always using two comments - one above the const
which describes the value and one at the end of the line that contains the unit.
// 5 minutes
const DEFAULT_TTL = 5 * 60; // seconds
// 7 days
const REMINDER_DELAY = 7 * 24 * 60; // minutes
Environment Variables
In some cases you possibly want to use a .env
variable to define your config interval and it should be possible to change the insert units - for example for development/testing purposes.
So by default it's 7 days
but you want to be able to set it to 5 minutes
without adjusting your code or complex conditions.
The solution is the static \Carbon\CarbonInterval::fromString()
method that accepts a string, similar but different to strtotime()
function.
In one of our projects we had to prevent password reset for 7 days after it was successfully reset. But for sure we had to use something like 5-10 minutes on our local machines and several hours on our staging system.
use Carbon\CarbonInterval;
return [
// ...
'password_reset_decay' => CarbonInterval::fromString(env('PASSWORD_RESET_DECAY', '7 days'))->totalSeconds,
// ...
];
And in your .env
file you can define the values like the following.
# production
PASSWORD_RESET_DECAY="7 days"
# staging
PASSWORD_RESET_DECAY="1 day"
# development
PASSWORD_RESET_DECAY="6 hours"
# local
PASSWORD_RESET_DECAY="10 minutes"