Important: This repository is NOT a library intended for end-users of the Waffle framework.
It is the central development and integration environment for contributors working on
the Waffle framework (waffle-commons/waffle) and its related components (waffle-commons/*).
It is a submodule of the waffle-commons/monorepo umbrella and is normally obtained as part of it (see Setup) — it is not used standalone, because its Composer path repositories point at sibling components (../cache, ../config, …).
If you want to build an application with Waffle, use the official skeleton instead:
composer create-project waffle-commons/skeleton:0.1.0-beta7 my-waffle-appName the version: until 1.0.0 every release is a beta, and Composer offers only stable releases unless you name one. Without PHP on your machine, the skeleton's create-project.sh does the same with Docker only.
This workspace serves several key functions for Waffle development:
- Orchestration: Manages the Docker development environment (FrankenPHP, PHP extensions, Xdebug, Composer).
- Local Linking: Its
composer.jsondeclares Composerpathrepositories for everywaffle-commons/*package (all pointing at../<component>), so the test app builds against your local checkouts without publishing anything. - Integration Testing: Provides a realistic application-like environment to run tests that span the core framework and its components.
- Consistency: Ensures all contributors use the same base development environment.
- Git
- Docker & Docker Compose
- PHP >= 8.5 + Composer (optional on the host — everything runs inside the container; handy for host-side Composer operations)
Never run PHP on the host. Every PHP / Composer / Mago / PHPUnit command runs inside the
waffle-devcontainer. ThewflCLI (below) wraps this for you.
The supported path is to clone the umbrella monorepo (which checks out workspace and every component as submodules) and let wfl bootstrap everything.
# 1. Clone the monorepo with all submodules
git clone --recurse-submodules git@github.com:waffle-commons/monorepo.git
cd monorepo
# 2. Bootstrap: init submodules, boot Docker, install git hooks, symlink `wfl` to ~/.local/bin
./bin/wfl init
# 3. Install the workspace's dependencies inside the container (creates the vendor/ symlinks)
wfl run workspace composer installBecause workspace/composer.json already declares a path repository for every component, composer install symlinks workspace/vendor/waffle-commons/* straight to your local ../<component> checkouts — there is nothing to hand-edit. Verify with:
ls -l workspace/vendor/waffle-commons/ # entries should be symlinks → ../../<component>The whole monorepo directory is mounted into the container at
/waffle-commons. The primary container iswaffle-dev; Redis iswaffle-redis.
wfl (bin/wfl at the monorepo root) is the host-side wrapper around docker compose / composer / mago / PHPUnit. After wfl init symlinks it into ~/.local/bin, it is available globally; from inside this submodule you can also invoke bin/wfl (a thin shim that forwards to the umbrella binary).
| Command | Description |
|---|---|
wfl up / wfl down |
docker compose up -d / down. |
wfl status |
Active PHP profile + container states. |
wfl shell [component] |
Open a shell in the container (cd'd into the component). |
wfl run <component> <cmd…> |
Run an arbitrary command in a component (e.g. wfl run workspace composer install). |
wfl mago [component] |
composer mago (fmt + lint + analyze + guard) for a component. |
wfl test [component] |
composer tests for a component. |
wfl igor |
Monorepo-wide Igor worker-safety / memory-leak audit (0 KO required). |
wfl compare-audit [comp…] |
SEC-03 gate: ban naive === / !== on secret/token/HMAC sites (must use hash_equals()). |
wfl check:all [--with-tests] |
Parallel composer mago across every component (add --with-tests for PHPUnit). |
wfl monorepo:sync [--fix] |
Report (or --fix align) waffle-commons/* version constraints across components. |
wfl academy:test [--lab=…] |
Run the Waffle Academy labs PHPUnit suite (academy/labs). |
wfl debug / wfl bench |
Switch the PHP profile (Xdebug-on vs JIT-on) and restart. |
wfl link <consumer> <provider> |
Wire <consumer> to build against your local <provider> checkout. |
wfl unlink <consumer> <provider> |
Undo a link. |
wfl components / wfl help |
List components / print help. |
See the wfl reference for the full surface.
-
Web server: the workspace test app is served at
https://localhost:8443(HTTPS, self-signed) orhttp://localhost:8080— accept the self-signed certificate generated by Caddy. -
Run a component's checks (preferred,
wflinfers the component from your directory):wfl test waffle # composer tests for waffle-commons/waffle wfl mago routing # fmt + lint + analyze + guard for waffle-commons/routing wfl test workspace # the cross-component integration suite
-
The underlying form (what
wflruns for you — the canonical invocation fromCLAUDE.md):docker exec -it -w /waffle-commons/waffle waffle-dev composer tests docker exec -it -w /waffle-commons/workspace waffle-dev composer update
-
Open a shell:
wfl shell workspace # or: docker exec -it -w /waffle-commons/workspace waffle-dev bash -
Stop the environment:
wfl down # or: docker compose down
- Start the environment:
wfl up. - Edit code in any component checkout (
cache/,routing/,data/, …). Changes are reflected in the container instantly via the volume mount, and across components via the path-repo symlinks. - Gate the components you touched:
wfl mago <component> && wfl test <component>. - Validate the integration:
wfl test workspace(and/or hit the web server).
The workspace is Option 3 of the cross-component linking model: its path repos are committed on purpose, so the integration app always builds against your live local code. For a focused change to a single component repo (not the workspace), prefer wfl link <consumer> <provider> over hand-editing composer.json, and wfl unlink before you open the PR. See How-To: Work on multiple components locally.
The workspace AppKernelFactory follows the same wiring as the skeleton — .env is parsed by DotEnv and merged with the live process environment via array_merge((new DotEnv($root))->load(), getenv()). Because array_merge is rightmost-wins on string keys, any variable exported by Docker / docker-compose.yml / your shell silently overrides the value in .env (Twelve-Factor convention).
When integration-testing changes to the config package or to AppKernelFactory, keep an eye on the OS-vs-.env precedence: a stale APP_ENV=dev in your shell will override .env's value for every docker exec invocation. See documentation/how-to/configuration.md for the full merge semantics and the APP_DEBUG/DEBUG type-normalization caveat.
Auth secrets.
workspace/.env.exampleshipsWAFFLE_AUTH_SECRET(the RFC-021 bridge HMAC secret — shared with thelegacy-backendmonolith viadocker-compose.ymlso it can verify assertions) andWAFFLE_DEMO_API_KEY(the demoX-Api-Keyservice account). Both are consumed bywaffle.auth.*inconfig/app.yaml; the committed values are dev-only placeholders.
Database & migrations. The workspace ships the RFC-022
waffle.database.*config and a samplemigrations/script with its down script. Apply them inside the container withdocker exec -it -w /waffle-commons/workspace waffle-dev php bin/waffle db:migrate;make:migration <Name>,db:statusanddb:rollback [--steps=N]complete the cycle ([OPS-03]). Thewaffle-mysqlandwaffle-mariadbservices exist only for thedatacomponent's live migration round trip; the app runs onwaffle-postgres. See How to: Database Migrations.
Queue worker.
bin/waffle queue:workhandles the messages of the Redis Streams queue (waffle.queue.*inconfig/app.yaml, on thewaffle-redisservice). Its demo handler,Workspace\Queue\EmailHandler, takes each queuedWorkspace\Mailer\LogMailer, which writes it to the log instead of sending it. Run it withdocker exec -it -w /waffle-commons/workspace waffle-dev php bin/waffle queue:work -v; Ctrl+C stops it once the message in flight is settled. Nothing in the HTTP app dispatches messages yet: code that starts background work takesQueueDispatcherInterface, which the Redis Streams driver implements.
This repository is intended for contributors to the Waffle ecosystem ONLY. Please refer to the CONTRIBUTING.md
file in the specific repository (waffle-commons/waffle, waffle-commons/*) you wish to contribute to.
Join the core team and contributors on Discord to shape the future of cloud-native PHP.
This project is licensed under the MIT License. See the LICENSE.md file for details.