Skip to content

Pick the PHP versions you install, like the databases - #16

Merged
zelti merged 2 commits into
mainfrom
feat/php-versions-selectable
Aug 24, 2026
Merged

zelti merged 2 commits into
mainfrom
feat/php-versions-selectable

Conversation

@zelti

@zelti zelti commented Aug 24, 2026

Copy link
Copy Markdown
Owner

All three PHP versions ran whether you wanted them or not: 5.7 GB of images (1.9 GB each) and three containers, for what is usually one version plus an occasional second. Databases already work the other way round, so versions become profiles too.

What changes

  • The installer asks which versions to install and, when you pick more than one, which is the default. --php=84,83 installs both and the first is the default, so --php=84 keeps meaning what it meant.
  • forge php list|on|off, alongside forge db. They are ordinary profiles, so they also show in forge profile list.
  • forge php off refuses the default; forge use 8.5 installs 8.5 first if you do not have it.
  • Asking for a version you did not install returns a page naming the command to add it, on both Apache and nginx, instead of a bare 503.
  • An existing .env keeps every version it had, announced once — a git pull cannot silently break a --pNN host.

The obstacle

Compose refuses to parse a project whose dependency sits behind a disabled profile:

service "web" depends on undefined service "php84": invalid compose project

Every compose command fails with it, forge included, so depends_on: php${PHP_VERSION}dev is gone from both web servers. It only ordered startup — the backend is resolved per request in resolve_docroot.lua.

The invariant that keeps it safe: COMPOSE_PROFILES always carries the default version's profile. Zero php[0-9][0-9] entries can then only mean a .env written before this change, which is what the migration keys off.

Verification

Run against a real stack, both servers, before pushing. Three things it caught that CI would have taken a round trip each to find: the page cannot be written from the fixups hook (/ goes through DirectoryIndex, and the internal redirect discards the body — an empty 200 on a directory), Lua locals are invisible to functions defined above them (500 on every request), and paste -sd', ' alternates delimiters, so three versions printed as 8.3,8.4 8.5.

Both new CI steps were falsified once: the page by blanking ENABLED_PROFILES, the migration by removing the call from need_env.

zelti added 2 commits August 24, 2026 11:00
All three ran whether you wanted them or not: 5.7 GB of images and three
containers for what is usually one version plus an occasional second.
Databases already work the other way round, so versions become profiles
too -- php83, php84, php85 -- and the installer asks which to install and
which of them is the default.

Compose refuses to parse a project whose dependency sits behind a
disabled profile, so `depends_on: php${PHP_VERSION}dev` had to go from
both web servers. It only ordered startup; the backend is resolved per
request in resolve_docroot.lua. Keeping it would have meant one bad edit
of .env bricking every compose command, forge included.

The invariant: COMPOSE_PROFILES always carries the default version.
Zero php entries can then only mean a .env written before this change,
which is what ensure_php_profiles keys off -- it keeps every version
that .env used to run and says so once. forge php off refuses the
default, forge use installs what it switches to.

Asking for a version that is not installed used to proxy to a host that
does not resolve: a bare 503, same as a typo. Both servers now get
COMPOSE_PROFILES as ENABLED_PROFILES and answer with a page naming the
command to add it. It is written from the translate-name hook, not from
fixups: "/" reaches PHP through DirectoryIndex, and the internal
redirect throws away a body written that late -- the request ends as an
empty 200 on a directory.

Verified against a running stack on Apache and nginx, with the pty
driver answering the two new questions. Both new CI steps were falsified
once: the page by blanking ENABLED_PROFILES, the migration by removing
the call from need_env.
Two steps asserted COMPOSE_PROFILES exactly and were written before
versions lived on that line. The first install of a scripted run also
accepts the mail catcher, so the light-install check compares what is
there rather than the whole line.

Both were run verbatim from a clean copy this time -- the gap that let
them through was checking only the steps the running stack could reach.
@zelti
zelti merged commit 9fd97bc into main Aug 24, 2026
4 checks passed
@zelti
zelti deleted the feat/php-versions-selectable branch August 24, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant