This document describes how the bundle's demo applications run under FrankenPHP in Docker, and how to reproduce development (no cache, changes visible on refresh) and production (worker mode, cache enabled) configurations. The same approach can be used in other Symfony bundles or applications that ship a FrankenPHP-based demo.
- Overview
- What the demos include
- Development configuration
- Production configuration
- Switching between development and production
- Reproducing in another bundle
- Troubleshooting
The demo/ folder is not shipped when the bundle is installed (e.g. via composer require nowo-tech/doctrine-encrypt-bundle). It is excluded from the Composer package (via archive.exclude in the bundle's composer.json). The demo applications exist only in the bundle's source repository and are intended for development, testing, and documentation. To run or modify the demos, use a clone of the bundle repository.
The demos use:
- FrankenPHP (Caddy + PHP) in a single container.
- Docker Compose with the app and the parent bundle mounted as volumes (
../..→/var/doctrine-encrypt-bundle). - Two Caddyfiles:
Caddyfile(production, with worker) andCaddyfile.dev(development, no worker). - An entrypoint script that, when
APP_ENV=dev, copiesCaddyfile.devover the default Caddyfile and then starts FrankenPHP.
There are demos for Symfony 7 and Symfony 8 (e.g. demo/symfony7, demo/symfony8). Each has its own Dockerfile, docker-compose.yml and Makefile. From the bundle root you run e.g. make -C demo/symfony8 up (see the demo's README for the URL and port).
The main difference between development and production is:
| Aspect | Development | Production |
|---|---|---|
| FrankenPHP worker mode | Off (one PHP process per request) | On (workers keep app in memory) |
| Twig cache | Off (config/packages/dev/twig.yaml) |
On (default) |
| OPcache revalidation | Every request (docker/php-dev.ini) |
Default (e.g. 2 seconds) |
| HTTP cache headers | no-store, no-cache (in Caddyfile.dev) |
Omitted or cache-friendly |
APP_ENV / APP_DEBUG |
dev / 1 |
prod / 0 |
Ports: Each demo uses PORT from its .env. To run multiple demos at once, set a different PORT per demo (e.g. 8007 for symfony7, 8008 for symfony8).
The demo applications are configured for local development and debugging:
- Symfony Web Profiler and Debug bundle — enabled in
devandtestenvironments. - Doctrine Encrypt Bundle (
Nowo\DoctrineEncryptBundle\NowoDoctrineEncryptBundle) — the bundle under test; enabled in the demos.
Example config/bundles.php (aligned with demo/symfony8):
<?php
declare(strict_types=1);
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Nowo\DoctrineEncryptBundle\NowoDoctrineEncryptBundle::class => ['all' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
];In production (APP_ENV=prod), only bundles registered for all or prod are loaded.
Goal: every change to PHP, Twig or config is visible on the next browser refresh without restarting the container. No long-lived PHP workers; cache disabled or revalidated on every request.
The development Caddyfile is docker/frankenphp/Caddyfile.dev in each demo. It uses plain php_server (no worker) and cache-busting headers. The entrypoint copies it over /etc/frankenphp/Caddyfile when APP_ENV=dev. Mount it in docker-compose so you can edit it without rebuilding.
The demos include docker/php-dev.ini with opcache.revalidate_freq=0. Mount it in docker-compose: ./docker/php-dev.ini:/usr/local/etc/php/conf.d/99-dev.ini:ro.
The demos use config/packages/dev/twig.yaml with twig.cache: false so template changes are visible on refresh.
Each demo's docker-compose.yml sets APP_ENV=dev and APP_DEBUG=1, and mounts the app, the bundle (../..:/var/doctrine-encrypt-bundle), docker/frankenphp/Caddyfile.dev, and docker/php-dev.ini. The entrypoint copies Caddyfile.dev when APP_ENV=dev.
From the bundle root: make -C demo/symfony8 up (or make -C demo/symfony7 up). Or from the demo directory: make up.
Use the default Caddyfile (with worker). Set APP_ENV=prod and APP_DEBUG=0. Do not mount php-dev.ini. See TwigInspectorBundle DEMO-FRANKENPHP for the full production Caddyfile and steps.
- Development:
APP_ENV=dev,APP_DEBUG=1. Entrypoint copies Caddyfile.dev (no worker, no-cache headers). Mount php-dev.ini and dev twig cache off. - Production:
APP_ENV=prod,APP_DEBUG=0. Entrypoint leaves default Caddyfile (with worker). Do not mount php-dev.ini.
After changing env or Caddyfile, restart: docker-compose restart or make -C demo/symfony8 restart.
See TwigInspectorBundle DEMO-FRANKENPHP section "Reproducing in another bundle" for the full checklist.
- Changes not visible: Ensure worker mode is off in dev (Caddyfile.dev has no
worker), add dev twig.yaml and php-dev.ini, restart container, hard-refresh browser. - Web Profiler not visible: Check
APP_ENV=devandAPP_DEBUG=1, and that WebProfilerBundle is enabled fordevin bundles.php. - Demo times out: Check port is free, container logs (
docker-compose logs php), and required env vars (e.g. APP_SECRET).