fonda/f-status

Tracks and displays the status of registered system processes (imports, commands, etc.) in the TYPO3 Dashboard and Reports module

Maintainers

Package info

github.com/fonda-gmbh/f_status

Type:typo3-cms-extension

pkg:composer/fonda/f-status

Statistics

Installs: 38

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-05-30 05:55 UTC

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.

example.png

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;