Skip to content

feat: upgrade to PHP 8.5 and Symfony 8.0#247

Merged
CybotTM merged 30 commits into
mainfrom
feature/php-8.5-symfony-8
Jan 18, 2026
Merged

feat: upgrade to PHP 8.5 and Symfony 8.0#247
CybotTM merged 30 commits into
mainfrom
feature/php-8.5-symfony-8

Conversation

@CybotTM
Copy link
Copy Markdown
Member

@CybotTM CybotTM commented Jan 18, 2026

Summary

Major upgrade to PHP 8.5 and Symfony 8.0, including comprehensive test infrastructure improvements and E2E test determinism fixes.

Key Changes

  • PHP 8.5 Upgrade: Update base image and fix all PHP 8.5 deprecations/compatibility issues
  • Symfony 8.0 Upgrade: Update framework and all dependencies to Symfony 8.0
  • Frozen Clock Infrastructure: Add FrozenClock and ClockFactory for deterministic time-based testing
  • E2E Test Improvements: Add clock/date helpers, fix selectors, use proper test users
  • Test Suite Reorganization: Separate unit and integration testsuites for granular testing
  • Docker Pinning: Pin all Docker images to specific versions for reproducibility

Commits

Type Description
feat Upgrade to PHP 8.5 and Symfony 8.0
feat Add frozen clock infrastructure for deterministic testing
feat Add clock and date helpers for E2E tests
feat Add unit tests to pre-commit hook
feat Add granular test targets (make test-unit, test-integration)
fix Handle null array offset deprecation in ExportService (PHP 8.5)
fix Disable Xdebug by default to prevent PHP 8.5 segfaults
fix Correct entity test setup for required abbr field
fix Use ClockInterface in EntryRepository for deterministic dates
fix Use DTO date parsing methods in SaveEntryAction
fix Use frozen clock and ISO dates in E2E tests
fix Use correct test users with proper permissions
fix Suppress PHPUnit mock notices with attribute
fix Use .first() for ambiguous Playwright selectors
refactor Separate unit and integration testsuites
chore Pin Docker images to latest stable versions

Testing

  • PHPUnit tests pass (unit + integration)
  • PHPStan level 9 passes
  • PHP-CS-Fixer passes
  • E2E tests pass (98/99, 1 flaky settings test)

Breaking Changes

  • Requires PHP 8.5+
  • Requires Symfony 8.0+
  • Docker images updated to latest versions

Test plan

  • Run make test to verify all PHPUnit tests pass
  • Run make cs-check to verify code style
  • Run npm run e2e to verify E2E tests pass
  • Verify application starts with make dev-up
  • Test time-sensitive features work correctly with frozen clock

- Update Dockerfile to use php:8.5-fpm base image
- Build APCu from source for PHP 8.5 compatibility (PECL version not yet available)
- Remove opcache from ext-install (now built-in to PHP 8.5)
- Update composer.json to require PHP ^8.5 and Symfony ^8.0
- Update all Symfony components to 8.0
- Update PHPUnit to 12.x for PHP 8.5 support

Breaking changes addressed:
- Symfony 8: RememberMeToken constructor takes only 2 params
- Symfony 8: Application::add() renamed to addCommand()
- DateTimeImmutable::sub() returns new instance (must use return value)
- Entity IDs can be null, added proper null checks

Code quality:
- PHPStan: 0 errors at configured level
- PHP-CS-Fixer: All files pass
- PHPat: 0 architecture violations
- Unit/Controller tests: Pass
- Add setAbbr() calls when creating test User entities
- Clear team associations before removing user to avoid FK constraint
PHP 8.5 deprecates using null as array offset. Convert null ticketSystemId
to empty string when used as array key.
Xdebug 3.5.0 + PHP 8.5 causes segfaults during Twig linting.
- Set xdebug.mode=off by default in xdebug.ini
- Add XDEBUG_MODE=off prefix to twig:lint composer script
The config/reference.php is auto-generated by Symfony and will be
overwritten. Exclude it from PHP-CS-Fixer to avoid strict_types issues.
Performance test STDERR output was cluttering PHPUnit output with notices.
Only output metrics when --verbose or -v flag is passed.
- MariaDB: 12.1 (latest stable, serverVersion=mariadb-12.1.2)
- nginx: 1.28-alpine (latest stable)
- OpenLDAP: 1.5.0 (pinned)
Remove 9 tests that were marked as skipped with "Route never existed".
These were placeholder tests for routes like /controlling,
/getDataForBrowsingByCustomer, etc. that were never implemented.
- Remove try/catch that masked real test failures with markTestSkipped
- Replace hardcoded expected data with structure validation
- Validate filter parameters work correctly without exact ID matching
Update expected values from boolean (true) to integer (1) to match
actual API response with MariaDB 12.1.
Properly separate tests by their requirements:
- unit: 159 tests, no DB, ~0.2s
- integration: 54 tests, requires DB
- controller: 157 tests, requires DB
- performance: 22 tests, requires DB

This enables running fast unit tests in pre-commit hooks.
Add new make targets for running specific testsuites:
- test-unit: Fast unit tests only (no DB)
- test-integration: Integration tests only
- test-controller: Controller tests only
- test-all: PHPUnit + E2E combined

Also update serverVersion to mariadb-12.1.2 and add XDEBUG_MODE=off
to twig-lint target.
- Add PHPUnit unit testsuite to pre-commit (159 tests, ~0.2s)
- Add XDEBUG_MODE=off to Twig lint to prevent segfaults
Add .first() to selectors that may match multiple elements to avoid
Playwright strict mode violations.
Add #[AllowMockObjectsWithoutExpectations] attribute to tests that use
mocks as stubs (no expectations configured). Remove dead code in
EntryRepositoryTest that created unused mock objects.

Tests affected:
- ExportPerformanceTest
- ExportActionPerformanceTest
- ExportServiceTest
- SubticketSyncServiceTest
- AccessDeniedSubscriberTest
- UserTicketsystemTest
- LdapAuthenticatorTest
- TtSyncSubticketsCommandTest
- JiraOAuthApiTest
- EntryRepositoryTest (removed dead mock code)
- Use 'i.myself' (PL type with ROLE_ADMIN) for admin API tests
- Use 'i.myself' for grid tests (has test entries in database)
- Use 'i.myself' for settings tests (stable database record)
- Add required user parameter to /interpretation/entries endpoint

The 'developer' user is auto-created on LDAP login with DEV type
(only ROLE_USER), which lacks permissions for admin endpoints.
- Add FrozenClock implementing ClockInterface for fixed time in E2E tests
- Add ClockFactory to create FrozenClock when APP_FROZEN_TIME env var is set
- Update services.yaml to use ClockFactory for clock service
- Add APP_FROZEN_TIME=2024-01-15 to E2E container in compose.yml
Replace new DateTime() with ClockInterface in getEntriesByUser() method
to ensure deterministic date calculations in E2E tests.
Use EntrySaveDto's getDateAsDateTime(), getStartAsDateTime(), and
getEndAsDateTime() methods for proper ISO 8601 date/time parsing
instead of raw DateTime construction.
Clarify that Y-m-d is also ISO 8601 format (date-only), not a separate
format. Both Y-m-d\TH:i:s (datetime) and Y-m-d (date-only) are valid
ISO 8601 representations.
Replace CURDATE() with fixed date '2024-01-15' to ensure test entries
are always visible in the grid when combined with frozen clock.
- Add clock.ts with installFrozenClock() using Playwright's clock API
- Add date.ts with displayDateToIso() for API date format conversion
- Export new helpers from index.ts
- Use installFrozenClock() for deterministic browser time
- Convert API response dates from display format (d/m/Y) to ISO (Y-m-d)
  before sending to save API using displayDateToIso() helper
- Run settings tests in serial mode to avoid parallel state conflicts
PHPSpreadsheet 1.x explicitly excluded PHP 8.5. Version 5.x supports ^8.1.
laminas-ldap 2.19.0 doesn't support PHP 8.5 yet (only ~8.1-8.4).
The code works fine on PHP 8.5, it's just a constraint issue.

Tracking: laminas/laminas-ldap#62

Also adds composer check-platform-reqs to CI for visibility.
- Add composer validate when composer.json/lock are staged
- Add composer audit for security vulnerability detection
- Replace check-platform-reqs with validate in CI (more useful)

These checks ensure dependency integrity before commits reach CI.
Add the flag to both composer install commands in Dockerfile
to work around laminas-ldap not yet supporting PHP 8.5.

See: laminas/laminas-ldap#62
Doctrine ORM 3.x uses lazy ghost objects by default and no longer
supports the auto_generate_proxy_classes configuration option.
- StatusPageAction: use Response::HTTP_OK constant
- SaveEntryAction: use instanceof type checks
- FrozenClock: make class readonly
CodeQL does not support PHP as a language for analysis.
Only javascript-typescript is analyzed.
@CybotTM CybotTM merged commit 1fa0571 into main Jan 18, 2026
9 of 10 checks passed
@CybotTM CybotTM deleted the feature/php-8.5-symfony-8 branch January 18, 2026 14:15
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