Skip to content

feat(laravel): boot without a database via dumped metadata#8290

Open
soyuka wants to merge 1 commit into
api-platform:4.3from
soyuka:feat/laravel-metadata-dump
Open

feat(laravel): boot without a database via dumped metadata#8290
soyuka wants to merge 1 commit into
api-platform:4.3from
soyuka:feat/laravel-metadata-dump

Conversation

@soyuka

@soyuka soyuka commented Jun 11, 2026

Copy link
Copy Markdown
Member

Problem

To expose an Eloquent model, API Platform reads its metadata (columns, types, relations, identifiers) from the live database schema (ModelMetadata::getColumns()). That introspection runs while the ResourceMetadataCollection is built, and that build happens at boot: src/Laravel/routes/api.php iterates every resource to register routes.

So the app cannot boot when no migrated database is reachable. This breaks common cacheless boots:

  • docker build (DB service not running);
  • composer install@php artisan package:discover;
  • static analysis (Larastan/PHPStan) in CI, which boots the app.

The existing metadata cache only short-circuits the DB read if it was already warmed — and warming needs a boot with the DB up; the configured store may also be redis/memcached (unavailable at build, not committable).

Refs #8131.

Solution

Let users pre-compute the resource metadata once, with the DB up, dump it to a single file that can be committed to git or baked into a Docker image, and serve metadata from that file at boot — bypassing the DB.

  • api-platform:metadata:dump {--path=} — resolves the path from --path or the api-platform.metadata_dump config, iterates ResourceNameCollectionFactoryInterface, builds each ResourceMetadataCollection (this is the step that hits the DB — run it with the DB up), and serializes the array<class-string, ResourceMetadataCollection> map to the file. It unwraps any active DumpedResourceCollectionMetadataFactory so it always rebuilds from the live source, never from a stale dump.
  • DumpedResourceCollectionMetadataFactory — decorator that loads the dumped map once and returns the dumped collection for known classes, delegating otherwise. Wired as the outermost resource metadata factory, so a dump hit short-circuits before the cache/Eloquent/DB factories are touched. Skipped when APP_DEBUG is true so local dev always recomputes fresh metadata (mirrors the existing array cache choice).
  • Configapi-platform.metadata_dump defaults to null (feature disabled); the user explicitly chooses a VCS/image-committable path.

Only the ResourceMetadataCollection is dumped: the boot-time DB hit happens entirely inside its build, so serving it from the file means the nested factories are never invoked at boot. Per-request paths still use the normal factories (DB available at request time).

Design notes

  • The factory is wired via a final ->extend() in ApiPlatformProvider::register() (after the Parameter/ObjectMapper extends) so it sits above the always-applied ParameterResourceMetadataCollectionFactory — genuinely outermost.
  • ResourceMetadataCollection is already serialized into the cache store by CacheResourceCollectionMetadataFactory today, so the object graph is serializable; the dump reuses that.

Tests

New tests (run without a database):

  • Tests/Unit/Metadata/DumpedResourceCollectionMetadataFactoryTest.php
  • Tests/Console/DumpMetadataCommandTest.php (includes re-dump-over-stale)
  • Tests/Metadata/DumpedMetadataBootTest.php (boots with a dump file + app.debug=false, asserts the dumped decorator serves metadata without DB introspection; asserts it is skipped when app.debug=true)
vendor/bin/phpunit Tests/Unit/Metadata/DumpedResourceCollectionMetadataFactoryTest.php Tests/Console/DumpMetadataCommandTest.php Tests/Metadata/DumpedMetadataBootTest.php
→ OK (8 tests, 24 assertions)

php-cs-fixer dry-run on changed files: 0 issues.

Note: the full Laravel suite currently errors on this machine due to a pre-existing environment issue (released api-platform/* packages lagging the monorepo source; CI links source via soyuka/pmu). Confirmed identical failures on a clean tree without these changes — not a regression.

Follow-up

Docs for the workaround/command: api-platform/docs#2294.

@soyuka soyuka force-pushed the feat/laravel-metadata-dump branch from d3dee6c to 602b7eb Compare June 11, 2026 15:15
@soyuka soyuka changed the base branch from main to 4.3 June 11, 2026 15:15
API Platform reads Eloquent model metadata from the live database schema
while building resource metadata. That build runs at boot (route
registration iterates every resource), so the app cannot boot when no
migrated database is reachable — breaking Docker image builds,
`composer install` (package:discover) and static analysis in CI.

Add `api-platform:metadata:dump`, which computes every resource's
ResourceMetadataCollection with the database up and serializes the map to a
file. A new DumpedResourceCollectionMetadataFactory is wired as the
outermost resource metadata factory: when a dump file is configured it
serves metadata from the file and short-circuits the database-reading
factories. The decorator is skipped when APP_DEBUG is true so local
development always recomputes fresh metadata.

The dump file can be committed to the repository or baked into a Docker
image, letting the app boot with no database connection.

Refs api-platform#8131
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