typo3/cms-fluid
TYPO3 Fluid template engine for the TYPO3 CMS. Provides rendering, ViewHelpers, and integration for building dynamic HTML views with a flexible, secure templating syntax used across TYPO3 extensions and frontend output.
Install the Package
composer require typo3/cms-fluid typo3fluid/fluid-core
Note: Avoid pulling in TYPO3-specific dependencies unless necessary. Use composer require typo3/cms-fluid --ignore-platform-reqs if version conflicts arise.
Register Fluid as a View Engine
Create a custom service provider (e.g., FluidServiceProvider) in app/Providers/:
use FluidTYPO3\Fluid\View\TemplateView;
use Illuminate\Support\ServiceProvider;
class FluidServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('view.engine.fluid', function ($app) {
return new TemplateView();
});
}
}
Register it in config/app.php under providers.
Configure Laravel to Use Fluid
Update config/view.php to include Fluid as an engine:
'engines' => [
'fluid' => FluidTYPO3\Fluid\View\Engines\FluidEngine::class,
],
Create a Fluid Template
Save a template file (e.g., resources/views/fluid/hello.html):
<html>
<body>
<h1>{greeting}</h1>
</body>
</html>
Render the Template In a controller:
public function show()
{
return view('fluid.hello', ['greeting' => 'Hello, Fluid!']);
}
Clear Caches Fluid compiles templates to PHP at runtime. Clear caches after changes:
php artisan view:clear
resources/views/ directory and Illuminate\View\Factory.vendor/typo3fluid/fluid-core for low-level integration details.Fluid supports layouts via <f:layout> and <f:section>:
<!-- resources/views/layouts/app.html -->
<html>
<body>
<f:section name="content"></f:section>
</body>
</html>
<!-- resources/views/fluid/home.html -->
<f:layout name="app">
<f:section name="content">
<h1>Home Page</h1>
</f:section>
</f:layout>
Create partials in resources/views/partials/:
<!-- resources/views/partials/alert.html -->
<f:if condition="{alert}">
<div class="alert">{alert}</div>
</f:if>
Include them in templates:
<f:render partial="Alert" arguments="{alert: 'Warning!'}" />
Fluid’s ViewHelpers replace Blade directives. Example: formatting dates:
<f:format.date format="Y-m-d">{date}</f:format.date>
Create custom ViewHelpers by extending TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper.
Pass Eloquent models or collections directly to Fluid:
public function show(User $user)
{
return view('fluid.user.profile', [
'user' => $user,
'posts' => $user->posts()->take(5)->get(),
]);
}
Access data in templates:
<f:for each="{posts}" as="post">
<h3>{post->title}</h3>
</f:for>
Fluid lacks native asset helpers (e.g., @vite()). Use custom ViewHelpers:
// app/ViewHelpers/ViteAssetViewHelper.php
namespace App\ViewHelpers;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use Illuminate\Support\Facades\Vite;
class ViteAssetViewHelper extends AbstractViewHelper
{
public function render()
{
return Vite::asset($this->arguments['asset']);
}
}
Register it in FluidServiceProvider:
$this->app->make('fluid.view.helper.resolver')->addViewHelper(
new \App\ViewHelpers\ViteAssetViewHelper()
);
Usage in template:
<app:viteAsset asset="resources/js/app.js" />
Wrap Laravel’s Auth facade in a ViewHelper:
// app/ViewHelpers/AuthViewHelper.php
namespace App\ViewHelpers;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use Illuminate\Support\Facades\Auth;
class AuthViewHelper extends AbstractViewHelper
{
public function render()
{
return Auth::check() ? 'Logged in' : 'Guest';
}
}
Usage:
<app:auth />
Use Laravel’s Form facade with Fluid:
use Illuminate\Support\Facades\Form;
return view('fluid.contact', [
'form' => Form::open()->method('POST'),
]);
Render in template:
{form->text('name', null, ['class' => 'form-control'])}
{form->submit('Send')}
{form->close()}
Leverage Laravel’s cache middleware with Fluid:
// app/Http/Middleware/FluidCache.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Cache;
class FluidCache
{
public function handle($request, Closure $next)
{
return Cache::remember('fluid_'.$request->path(), 60, function () use ($next) {
return $next($request);
});
}
}
Register in app/Http/Kernel.php.
Namespace Collisions
TYPO3\ namespace may conflict with Laravel’s autoloading. Use composer.json aliases:
"autoload": {
"psr-4": {
"App\\": "app/",
"TYPO3Fluid\\": "vendor/typo3fluid/fluid-core/src/"
}
}
ViewHelper Registration
ViewHelper not found errors.$this->app->make('fluid.view.helper.resolver')->addViewHelper(
new \TYPO3Fluid\Fluid\Core\ViewHelper\Format\DateViewHelper()
);
Template Compilation Overhead
php artisan view:cache
storage/framework/views for bloated compiled files.TYPO3-Specific Assumptions
f:link.page (TYPO3-specific). Replace with custom ViewHelpers or Laravel’s route() helpers.Debugging Fluid Errors
// config/fluid.php (if created)
'debug' => env('APP_DEBUG', false),
try-catch in ViewHelpers:
try {
return $this->renderStatic();
} catch (\Exception $e) {
return 'Error: '.$e->getMessage();
}
Partial Caching
<f:render>) are not cached by default. Use cacheKey:
<f:render partial="Header" cacheKey="header_{data.slug}" />
Hybrid Blade-Fluid Workflow
// Controller
return view('fluid.template', [
'data' => (new \App\Services\DataTransformer())->transform($model),
]);
@stack, @includeWhen).Type Safety with PHP 8+
/**
* @param array<string, mixed> $arguments
*/
public function initializeArguments()
{
parent::initializeArguments();
$this->registerArgument('arguments', 'array', 'Associative arguments');
}
Testing Fluid Templates
use TYPO3Fluid\Fluid\Core\ViewHelper\Abstract
How can I help you explore Laravel packages today?