New in Symfony 8.2 (in development). To validate a cron expression typed by a user, we wrote a regular expression. It checks the shape, not the meaning: 60 * * * * (minute 60) or */0 * * * * (every zero minutes) go through, and the scheduler fails later, in the middle of the night.
The Cron constraint
#[Assert\Cron] parses the expression with the same package as the Scheduler component, dragonmantank/cron-expression:
use Symfony\Component\Validator\Constraints as Assert; class Report { // the five fields ("0 6 * * 1-5") and the aliases ("@daily") #[Assert\Cron] public string $schedule; // the five fields only #[Assert\Cron(mode: Assert\Cron::MODE_STANDARD)] public string $strictSchedule; // on top of that, the Scheduler's hashed expressions ("# # * * *", "#daily") #[Assert\Cron(mode: Assert\Cron::MODE_HASHED)] public string $task; }
A hashed expression lets the Scheduler replace each # with a value drawn from the name of the task: recurring tasks spread out over time instead of all starting at midnight.
Symfony 8.2 adds two other constraints: EntityExists, which checks that a Doctrine entity exists for an identifier received, and Audio, which checks the duration, the bitrate or the codec of a sound file.
Your task
PUT /reports/schedule saves the three schedules of a report: the delivery, started by our scheduler, the export copied over to a partner whose tool only knows the five fields, and the cleanup handed to the Scheduler. The regular expressions let impossible schedules through: the request in the "Requests" tab shows one.
Replace them with the Cron constraint, with the right mode for each field.