fonda / f-status
Tracks and displays the status of registered system processes (imports, commands, etc.) in the TYPO3 Dashboard and Reports module
Requires
- typo3/cms-core: ^14.3
- typo3/cms-dashboard: ^14.3
- typo3/cms-reports: ^14.3
- typo3/cms-scheduler: ^14.3
This package is auto-updated.
Last update: 2026-05-30 05:55:46 UTC
README
Provides a TYPO3 Dashboard widget that shows the status of registered system processes (imports, scheduled commands, etc.).
Typical use cases are scheduler commands that should run regularly but have stopped running.
Requirements
- TYPO3 14.3.3+
📦 Installation
composer require fonda/f-status:@dev
The extension provides two integration points:
- Dashboard widget — add via the TYPO3 Dashboard interface (widget group: System Info, identifier:
fstatus_status) - Reports module — visible automatically under Admin Tools > Reports as System Status
🔌 1 — Registering a StatusReporter
Implement StatusReporterInterface in your extension. TYPO3's DI container auto-tags it — no further configuration needed.
class MyImportStatusReporter implements StatusReporterInterface { public function getIdentifier(): string { return 'my_extension.import'; } public function getLabel(): string { // Plain string or LLL: label reference return 'My Import'; } public function getExpectedMaxAge(): ?\DateInterval { // Return an interval to enable stale detection. // Return null if there is no regularity expectation (no stale warning). return \DateInterval::createFromDateString('1 day'); } }
That's it — the class is auto-discovered and appears in the widget immediately.
✍️ 2 — Writing the status
There are two approaches depending on the situation.
🤖 Approach A — Automatic via SchedulerCommandStatusListener (3rd-party commands, status only)
f_status ships a built-in AfterTaskExecutionEvent listener that automatically writes success/failure for any registered reporter. Use this when you cannot or do not want to modify the command itself.
The only requirement: the reporter's getIdentifier() must return the scheduler command identifier.
class MyCommandStatusReporter implements StatusReporterInterface { public function getIdentifier(): string { return 'vendor:package:command'; // must match the scheduler command identifier } public function getLabel(): string { return 'My Command'; } public function getExpectedMaxAge(): ?\DateInterval { return \DateInterval::createFromDateString('1 day'); } }
A working example is provided in Resources/Private/Example/SchedulerCommandStatusReporter.php.
🛠️ Approach B — Manual set() (own commands, rich messages)
Inject StatusService directly into your command and call set() with the result. Use this when you own the command and want to include a meaningful message (e.g. record counts, import details).
use Fonda\FStatus\Service\StatusService; use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; class MyImportCommand extends Command { public function __construct( private readonly MyImportService $importService, private readonly StatusService $statusService, ) { parent::__construct(); } protected function execute(InputInterface $input, OutputInterface $output): int { try { $info = $this->importService->run(); $this->statusService->set( identifier: 'my_extension.import', message: sprintf('%d inserted, %d updated', $info->inserted, $info->updated), severity: ContextualFeedbackSeverity::OK, ); return Command::SUCCESS; } catch (\Throwable $e) { $this->statusService->set( identifier: 'my_extension.import', message: $e->getMessage(), severity: ContextualFeedbackSeverity::ERROR, ); return Command::FAILURE; } } }
📊 Widget display logic
The widget determines the displayed state from the reporter and the stored status:
| Condition | getExpectedMaxAge() |
Displayed state | Badge colour |
|---|---|---|---|
| No DB entry | null |
Never run | info (blue) |
| No DB entry | interval set | Never run | error (red) |
| Entry exists, within max age | any | Severity from set() |
ok / warning / error |
| Entry exists, older than max age | interval set | Stale | warning (yellow) |
getExpectedMaxAge() returning null means "this process has no regularity expectation" — the widget will show the actual stored severity without any stale check.
The max age interval is shown in the widget next to the badge (e.g. 1 day, 2 hours).
🔧 StatusService API
// Write or update a status entry $statusService->set(string $identifier, string $message, ContextualFeedbackSeverity $severity): void; // Remove a status entry $statusService->remove(string $identifier): void; // Read a single entry (returns null if not found) $statusService->get(string $identifier): ?Status; // Get all entries for a given severity $statusService->getBySeverity(ContextualFeedbackSeverity $severity): Status[]; // Check whether a reporter is registered for the given identifier $statusReporterRegistry->has(string $identifier): bool;
