Skip to content

Upgrade to Laravel 13 (PHP 8.3+, Symfony 7, PHPUnit 10)#888

Open
edwh wants to merge 4 commits into
developfrom
upgrade-laravel-13
Open

Upgrade to Laravel 13 (PHP 8.3+, Symfony 7, PHPUnit 10)#888
edwh wants to merge 4 commits into
developfrom
upgrade-laravel-13

Conversation

@edwh

@edwh edwh commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Split out from #862 (which bundled this with the map-of-groups feature). This PR is the framework upgrade alone, on top of current develop. The map feature is separate: #887 (stays on Laravel 10).

Framework / dependencies

  • laravel/framework ^10.48 → ^13.0, tinker ^2→^3, php ^8.1 → ^8.3
  • symfony/* ^6 → ^7, egulias/email-validator ^3 → ^4
  • phpunit/phpunit ^9.5 → ^10.5, mockery ^1.6, spatie/laravel-ignition ^2.8
  • owen-it/laravel-auditing ^13 → ^14, sentry/sentry-laravel ^3 → ^4
  • toin0u/geocoder-laravel ^4.6 → ^13, mariuzzo/laravel-js-localization ^2, debugbar ^4, dusk ^8
  • Removed: bkwld/croppa, laravelcollective/html, twbs/bootstrap (composer), osteel/openapi-httpfoundation-testing, nunomaduro/collision
  • Added patches: guzzle-promises-nullable, laravel-drip-l11

Compatibility changes

  • config/audit.php: auditing v14 resolverresolvers
  • config/geocoder.php: LaravelHttpClient adapter (geocoder-laravel v13)
  • config/sentry.php + new app/Support/SentryBeforeSend.php: before_send as a class callable (closures can't be config-cached)
  • phpunit.xml: PHPUnit 10 schema (tests/bootstrap.php, <source>, cacheDirectory)
  • Dropped DBAL getDoctrineSchemaManager() call (DBAL no longer bundled)
  • DeviceFactory: lazy event via closure (avoids eager FK creation)
  • Blade: replaced laravelcollective Form:: helpers with plain HTML
  • tests/TestCase.php: removed osteel OpenAPI response-validation (package removed); kept the global Geocoder mock and other develop test infra
  • UserController::postRegister: return the redirect on the fall-through path (L13 enforces the declared RedirectResponse return type)
  • Docker / Dockerfile.fly / docker_run.sh: PHP 8.4 base

Note on removed test coverage

Removing osteel/openapi-httpfoundation-testing drops the automatic OpenAPI response-schema validation that wrapped /api/v2 GET/POST/PATCH in tests (the package doesn't support PHPUnit 10). Matches the approach in #862. Can be revisited by adopting a PHPUnit-10-compatible validator later.

Verified locally (clean single-process run)

  • PHPUnit: 516 tests pass, 5402 assertions, 0 failures / 0 errors
  • Jest: 25 tests pass

🤖 Generated with Claude Code

edwh and others added 4 commits July 1, 2026 09:35
Split out from PR #862, which bundled this upgrade with the map-of-groups
feature. This PR is the framework upgrade ALONE, on top of current develop;
the map feature is a separate PR (#887) staying on Laravel 10.

Framework / dependencies:
- laravel/framework ^10.48 -> ^13.0, laravel/tinker ^2 -> ^3, php ^8.1 -> ^8.3
- symfony/* ^6 -> ^7, egulias/email-validator ^3 -> ^4
- phpunit/phpunit ^9.5 -> ^10.5, mockery ^1.6, spatie/laravel-ignition ^2.8
- owen-it/laravel-auditing ^13 -> ^14, sentry/sentry-laravel ^3 -> ^4
- toin0u/geocoder-laravel ^4.6 -> ^13, mariuzzo/laravel-js-localization ^2
- barryvdh/laravel-debugbar ^4, laravel/dusk ^8
- Removed: bkwld/croppa, laravelcollective/html, twbs/bootstrap (composer),
  osteel/openapi-httpfoundation-testing, nunomaduro/collision
- Added patches: guzzle-promises-nullable, laravel-drip-l11

Compatibility changes:
- config/audit.php: auditing v14 resolver -> resolvers
- config/geocoder.php: LaravelHttpClient adapter (geocoder-laravel v13)
- config/sentry.php + app/Support/SentryBeforeSend.php: before_send as a class
  callable (closures can't be config-cached)
- phpunit.xml: PHPUnit 10 schema (tests/bootstrap.php, <source>, cacheDirectory)
- Dropped DBAL getDoctrineSchemaManager() call (DBAL no longer bundled)
- DeviceFactory: lazy event via closure to avoid eager FK creation
- Blade: replaced laravelcollective Form:: helpers with plain HTML
- tests/TestCase.php: removed osteel OpenAPI response-validation (package gone);
  kept the global Geocoder mock and other develop test infra
- UserController::postRegister: return the redirect on the fall-through path
  (L13 enforces the declared RedirectResponse return type)
- Docker/Dockerfile.fly/docker_run.sh: PHP 8.4 base

Verified locally on a clean single-process run: PHPUnit 516 tests pass
(5402 assertions, 0 failures/errors), Jest 25 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e allowlist

geocoder-laravel v13 with auto_register_serializable_classes=true overwrites the
(unrestricted, null) cache.serializable_classes config with an allowlist of ONLY
its own provider model classes. That allowlist is applied by FileStore::unserialize
to the ENTIRE file cache, so any other cached object — notably the stdClass DB rows
cached by Fixometer::computeStats() (login/register stats on the home page) —
unserialises to __PHP_Incomplete_Class and every page reading those stats returns
HTTP 500.

The test suite didn't catch this because tests use the array cache driver (no
serialize round-trip); it only manifests over real HTTP with the file cache, which
is why CI failed at "Wait for services" (GET /index.php -> 500) while PHPUnit passed.

Set auto_register_serializable_classes=false to keep Laravel's default unrestricted
unserialize (as on Laravel 10). Geocoder result caching still works unrestricted.

Verified over HTTP: home/login/about/register all return 200 (were 500).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These two test files were empty (0 bytes) on develop. PHPUnit 9 tolerated them,
but PHPUnit 10 emits a test-runner warning ("Class X cannot be found in <file>")
when it scans an empty file that matches the test suffix, and the CI phpunit run
exits non-zero on such warnings — so the suite failed with 516 passing / 0
failures purely on those 2 warnings.

They contain no tests and are referenced nowhere, so delete them. Verified: a
CI-style phpunit run now reports no discovery warnings and exits 0 (skips alone
do not fail the run).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SonarCloud reliability rule. Here require_once is correct: it's the Composer
autoloader, its return value is unused, and single-inclusion is the intended
semantics. (Contrast the lang-array case in GroupFilterTranslationsTest, where
require_once would have been wrong.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

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