Installation:
composer require comsolit/clock-bundle
Add to config/bundles.php:
return [
// ...
Comsolit\ClockBundle\ComsolitClockBundle::class => ['all' => true],
];
First Use:
Inject the Clock service into your controller/service:
use Comsolit\ClockBundle\Clock\ClockInterface;
public function __construct(private ClockInterface $clock) {}
Basic Usage:
$currentTime = $clock->getDateTime(); // Request-constant DateTime
$timestamp = $clock->getTimestamp(); // Unix timestamp
Use Case: Ensure all time checks in a request use the same reference point.
// In a login controller
if ($clock->hasElapsed(300, $lastAttempt->getDateTime())) {
$this->allowLogin();
}
Workflow:
ClockInterface into services/controllers.new DateTime() calls with $clock->getDateTime().hasElapsed, isExpired) for readability.Pattern: Mock the Clock service in tests to simulate time progression.
// tests/Feature/LoginTest.php
public function testLoginBlockAfterFailures()
{
$this->mock(ClockInterface::class, function ($mock) {
$mock->shouldReceive('hasElapsed')
->with(300, $lastAttempt->getDateTime())
->andReturn(true);
});
}
Integration Tip:
ClockAwareTrait to centralize clock usage:
trait ClockAware {
public function __construct(private ClockInterface $clock) {}
protected function isBlocked(DateTimeInterface $lastAttempt, int $blockingPeriod): bool {
return $this->clock->hasElapsed($blockingPeriod, $lastAttempt);
}
}
$fileName = $clock->getFileName() . '_backup.csv'; // e.g., "2023-11-15_14-30-00_backup.csv"
$this->logger->info('Backup started', ['timestamp' => $clock->getTimestamp()]);
Request-Scoped Time:
ClockInterface.// Fails: Clock time doesn't change mid-request
$clock->getTimestamp() + 1000; // Always uses the same timestamp
DateTime Mutability:
DateTime instance returned by $clock->getDateTime(). It’s managed by the bundle.$now = $clock->getDateTime();
$now->modify('+1 hour'); // May break internal state
Time Zone Assumptions:
$clock->setTimeZone(new \DateTimeZone('Europe/Berlin'));
Verify Clock Time: Add a debug dump to confirm the clock’s time isn’t advancing unexpectedly:
\Log::debug('Clock timestamp:', ['ts' => $clock->getTimestamp()]);
Test Mocking: Ensure test mocks return consistent values:
$mock->shouldReceive('getTimestamp')
->andReturn(1634567890); // Fixed timestamp for tests
Custom Clock Implementations: Override the default clock for specialized needs (e.g., frozen time for tests):
# config/services.yaml
services:
App\Clock\CustomClock:
arguments:
$timeZone: 'UTC'
tags: ['clock']
Helper Methods: Extend the clock with domain-specific helpers:
// src/Clock/ExtendedClock.php
class ExtendedClock implements ClockInterface {
public function isWeekend(): bool {
return $this->getDateTime()->format('N') > 5;
}
}
Configuration:
The bundle has minimal config. Override defaults via config/packages/comsolit_clock.yaml:
comsolit_clock:
default_timezone: 'America/New_York'
How can I help you explore Laravel packages today?