Search by

fluidstan / typo3

sascha.egerer

TYPO3 integration for FluidStan: boots TYPO3, registers its Fluid namespaces and resolves EXT: paths

Package info

github.com/fluidstan/typo3

pkg:composer/fluidstan/typo3

Statistics

Installs: 52

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

0.3.0 2026-10-29 22:27 UTC

This package is auto-updated.

Last update: 2026-10-29 22:27:44 UTC


README

FluidStan Flowd GmbH

TYPO3 integration for FluidStan, the static analyser for Fluid templates and components powered by PHPStan. Developed and maintained by Flowd GmbH.

CI Packagist MIT

FluidStan output for the example extension in docs/example

FluidStan analyses Fluid templates without rendering them and reports property paths that do not exist on the model, values that cannot be rendered, loops over non-iterables, wrong ViewHelper and component argument types, undefined variables, unknown slots and more. The screenshot shows the analysis of docs/example, a small shop extension with an Extbase model, a component collection class and a collection configured in Configuration/Fluid/ComponentCollections.php (TYPO3 14): a typo in a property path, a DateTimeImmutable rendered without formatting, a file reference passed where a number is expected, a float passed to the arguments of f:translate, a missing getter on a related category read through an ObjectStorage, an undefined variable, an ObjectStorage passed to the count argument of the configured collection's component, and a property read on that int inside it. Run it yourself with composer fluidstan:example.

This package makes FluidStan work inside a TYPO3 project:

  • Boots TYPO3 like a CLI command, without opening a database connection, so the dependency injection container, extension paths and configuration are available while templates are parsed.
  • Registers TYPO3's global Fluid namespaces exactly as TYPO3 assembles them: f includes TYPO3\CMS\Fluid\ViewHelpers, and every Configuration/Fluid/Namespaces.php (TYPO3 14), $GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces'] and the ModifyNamespacesEvent are honoured.
  • Knows TYPO3 14's component collections defined in Configuration/Fluid/ComponentCollections.php, without a PHP class, and collection classes registered through dependency injection. Their variables come from the ProvideStaticVariablesToComponentEvent at runtime and are mixed in the analysis.
  • Resolves EXT: paths in the configuration, so templates are addressed the TYPO3 way.

Supports TYPO3 13.4 and 14.2 or newer on PHP 8.2 or newer, in Composer mode.

Installation

composer require --dev fluidstan/typo3

The core package comes along as a dependency.

Configuration

fluidstan.neon in the project root, next to composer.json:

parameters:
    environment: FluidStan\TYPO3\Typo3Environment
    bootstrapFiles:
        - vendor/autoload.php
    paths:
        - EXT:my_site/Resources/Private/Components
        - EXT:my_site/Resources/Private/Templates
    namespaces:
        my: My\Site\Components\ComponentCollection
    tmpDir: var/cache/fluidstan
  • environment activates this package.
  • bootstrapFiles must include the project's autoloader; TYPO3 is booted from it.
  • paths take EXT: notation or paths relative to the configuration file.
  • namespaces lists component collections and ViewHelper namespaces that are not registered globally in TYPO3, for example a collection a TYPO3 13 project registers only in ext_localconf.php. A component collection is given by its class name. Globally registered namespaces need no entry.
  • tmpDir holds the generated code and PHPStan's cache; keep it out of version control.

Then run the analysis:

vendor/bin/fluidstan
vendor/bin/fluidstan -c Build/fluidstan.neon   # configuration elsewhere
vendor/bin/fluidstan --error-format=json       # for CI tooling

Run it where TYPO3 runs. In a Docker or DDEV setup that is the PHP container, because the boot reads config/system/settings.php and additional.php, loads every extension's ext_localconf.php and builds the dependency injection container like any other TYPO3 CLI command. No database connection is opened. Without a settings.php TYPO3 only offers its failsafe mode, which knows the system extensions alone, so FluidStan stops with a message; a minimal settings.php with SYS/encryptionKey is enough.

What gets typed

  • Components declare their argument types with f:argument; FluidStan checks every use against the PHP classes behind them, including your Extbase models, DTOs and value objects.

  • Plain templates, partials and layouts have mixed variables unless you declare them with an annotation, which is also the way to type {settings}, {data} or anything else a controller assigns:

    <f:comment>
        @var My\Site\Domain\Model\Product product
        @var array<string, mixed> data
    </f:comment>
  • ViewHelper arguments are validated against the ViewHelper's argument definitions with the rules Fluid 5 applies at runtime. ViewHelpers that take services through their constructor are instantiated without the constructor to read their definitions, which is sufficient for the core and most extensions.

  • Variables a collection class provides through getAdditionalVariables() are typed from that method without running it, so a {component.class} your collection builds is a string and an unknown key is reported; see the core README for the details. Collections from ComponentCollections.php get theirs from a PSR-14 event at runtime, which the analysis cannot see, so those are mixed.

  • Conditions narrow: inside <f:if condition="{product}"> an optional product is no longer null.

  • Variables ViewHelpers assign are detected, in your ViewHelpers and in TYPO3's: inside <f:link.typolink parameter="{link}" partsAs="parts">, {parts} is a known array. Where detection cannot follow the code, declare the assignment in fluidstan.neon under viewHelperAssignments or with a @fluidstan-assigns tag; the core README has the details.

  • Strict mode (strict: true) also reports what Fluid tolerates silently, such as a string passed to an int argument or a path through a nullable Extbase relation; see the core README.

  • A baseline lets an existing project adopt FluidStan: vendor/bin/fluidstan --generate-baseline records the current errors in fluidstan-baseline.neon, and with includes: [fluidstan-baseline.neon] in fluidstan.neon only new ones are reported. ignoreErrors works as in PHPStan.

Roadmap

  • Typed TYPO3 variables out of the box: {settings}, {data}, {page}, {site}, {language}, {request}
  • Content Blocks field definitions as the type of {data} and of content element component arguments
  • Partials and layouts resolved through TYPO3's template paths from site sets and TypoScript
  • Extbase relations: ObjectStorage and lazy-loading proxies unwrapped to their element types

Development

composer install          # installs TYPO3 (typo3/minimal) and the example extension for the test suite
composer fluidstan:example # analyse docs/example
composer check            # everything below
composer lint             # syntax, composer.json, php-cs-fixer, PHPStan (max, strict, phpstan-typo3), Rector, dependency analysis
composer fix              # apply Rector, php-cs-fixer and composer normalize
composer test             # PHPUnit

Booting TYPO3 from the outside goes through SystemEnvironmentBuilder, which TYPO3 marks as internal; the same route typo3-console and the testing framework take. The package root is a minimal TYPO3 project with config/system/settings.php, so the example can be analysed and the integration test boots TYPO3 for real. CI runs the suite on PHP 8.2 to 8.5 against TYPO3 13.4 and 14.2.