Skip to content

Restore ORM 2 compatibility and fix the pipeline - #323

Merged
peter-gribanov merged 4 commits into
Happyr:2.xfrom
peter-gribanov:fix/workflows
Jul 28, 2026
Merged

peter-gribanov merged 4 commits into
Happyr:2.xfrom
peter-gribanov:fix/workflows

Conversation

@peter-gribanov

Copy link
Copy Markdown
Member

Follow-up to #322. Three separate concerns, one commit each — reviewing commit by commit is easier than reading the combined diff, since the CS Fixer sweep touches 31 files.

1. Restore backward compatibility with Doctrine ORM 2 (db48196)

#322 replaced the ORM constraint instead of widening it, which turned an additive feature into a BC break and would have forced a major release. This makes ORM 3 support additive, matching how Symfony 7 support shipped in v2.1.0:

v2.0.1  symfony/property-access: ^4.0 || ^5.2
v2.0.2  symfony/property-access: ^4.0 || ^5.2 || ^6.0
v2.1.0  symfony/property-access: ^4.0 || ^5.2 || ^6.0 || ^7.0

All three src/ changes from #322 turned out to be BC already:

Change Available since
Type::hasType() DBAL 2.9.0
enableResultCache() ORM 2.8.0
toIterable() (dropping the method_exists shim) ORM 2.8.0

Two things worth calling out:

  • The ORM floor is ^2.17, not ^2.5. Upgraded to Doctrine ORM 3 #322 changed the specs to double Doctrine\ORM\Query (necessary, since ORM 3 declares QueryBuilder::getQuery(): Query). That class was final up to and including ORM 2.16 and only became non-final in 2.17.0 — on ORM 2.8.0 the suite gives 15 broken examples with could not reflect class Doctrine\ORM\Query as it is marked final.
  • symfony/polyfill-php80 has to come back. src/Filter/Like.php calls str_starts_with(), str_ends_with() and str_contains(), which only exist on PHP 7.x through that polyfill.

The same commit fixes the three failing test jobs:

  • PHP 8.4 + highest / PHP 8.4 + lowest could not resolve at all — PHP 8.4 support only landed in phpspec ^8.0.
  • PHP 8.1 + lowest died with PHP Fatal error: '\static' is an invalid class name, because --prefer-lowest resolved prophecy 1.14.0 while support for the static return type only arrived in 1.15.0, and ORM 3 uses static on its fluent setters. phpspec 7.x only requires prophecy ^1.9, so the constraint has to be explicit.

Restoring the PHP 7.2–8.0 matrix rows is also required for this branch's protection to stay satisfiable — PHP 7.4 + highest + normal and PHP 8.0 + highest + normal are required status checks, and #322 deleted the jobs that report them.

2. Fix PHPStan findings (355c0b8)

Pre-existing and unrelated to ORM 3. The QA job installs whatever phpstan is current, so the analysis got stricter over time while the code stood still — on a clean 2.x, phpstan 1.12 reported 3 errors and phpstan 2.2 reported 8.

  • EntityRepository declares @template T of object, so passing it an unbounded T resolved to mixed. Bounding both templates fixes all three generics errors at once.
  • explode() never returns an empty array, so array_pop() always yields a string and the null check was dead.
  • substr() does not return false on PHP 8. Only the PHPDoc is narrowed — adding : string to the signature would break subclasses by covariance.
  • treatPhpDocTypesAsCertain: false silences two instanceof.alwaysTrue reports. Those guards are real — they catch untyped callers and throw InvalidArgumentException — so the check stays and the report goes.

One residual: phpstan still reports one generics error against ORM 2.17–2.19, where getClassMetadata() is annotated with @psalm-return and @psalm-template that PHPStan does not read (ORM 2.20 changed those to @template and @return). The QA job analyses the highest dependency set, so CI is unaffected.

3. Apply PHP CS Fixer (41eb296)

Also pre-existing. The @PhpCsFixer ruleset has grown rules since the last sweep: static_lambda, single_line_empty_body, no_extra_blank_lines, whitespace_after_comma_in_array, ordered_imports, phpdoc_separation and a few more. On a clean 2.x this reported 40 files; #322 had already brought it down to 31 by reformatting the tests it touched. No behaviour change, and running the fixer again reports nothing.

Verification

Ran locally on PHP 8.3:

  • Specs 527/527 on the full highest set (ORM 3.6.7 + DBAL 4.4.4 + phpspec 8.3.1 + prophecy 1.26.1 + property-access 7.4.8) and on the full lowest set (ORM 2.17.0 + DBAL 2.13.9 + phpspec 7.5.0 + prophecy 1.18.0 + property-access 4.4.9). Also green against ORM 2.19.0, 2.20.0 and 2.20.13 individually.
  • Dependency resolution across PHP 7.2.34 / 7.4.33 / 8.0.30 / 8.1.31 / 8.2.27 / 8.3.31 / 8.4.23 × lowest/highest — all combinations resolve. PHP ≤ 8.0 lands on ORM 2, PHP ≥ 8.1 highest lands on ORM 3, so both lines stay covered without reinstating the include: variants.
  • phpstan 2.2 reports no errors, php-cs-fixer 3.95 reports no violations.

With this in, the branch should be fully green and ORM 3 support can ship as v2.2.0 rather than a major.

PR Happyr#322 replaced the ORM constraint instead of widening it, which turned
an additive feature into a BC break and would have forced a major release.
Doctrine ORM 3 support is additive instead, matching how Symfony 7 support
shipped in v2.1.0.

All three src changes from Happyr#322 are already BC:

  - Type::hasType()        available since DBAL 2.9.0
  - enableResultCache()    available since ORM 2.8.0
  - toIterable()           available since ORM 2.8.0

The ORM floor is ^2.17 rather than ^2.5 because the specs now double
Doctrine\ORM\Query, which was final up to and including ORM 2.16 and only
became non-final in 2.17.0.

symfony/polyfill-php80 has to come back: src/Filter/Like.php calls
str_starts_with(), str_ends_with() and str_contains(), which only exist on
PHP 7.x through that polyfill.

Also fixes the three failing test jobs:

  - PHP 8.4 (highest and lowest) could not resolve at all, since PHP 8.4
    support only landed in phpspec ^8.0.
  - PHP 8.1 + lowest died with "'\static' is an invalid class name",
    because --prefer-lowest resolved prophecy 1.14.0 while support for the
    static return type only arrived in 1.15.0, and ORM 3 uses static on
    its fluent setters. phpspec 7.x only requires prophecy ^1.9, so the
    constraint has to be explicit.

Restoring the PHP 7.2-8.0 matrix rows is also required for the 2.x branch
protection to stay satisfiable: "PHP 7.4 + highest + normal" and
"PHP 8.0 + highest + normal" are required status checks, and Happyr#322 deleted
the jobs that report them.
These are pre-existing and unrelated to ORM 3: the QA job installs
whatever phpstan is current, so the analysis got stricter over time while
the code stood still. On a clean 2.x, phpstan 1.12 reported 3 errors and
phpstan 2.2 reported 8.

  - EntityRepository declares @template T of object, so passing it an
    unbounded T resolved to mixed. Bounding both templates fixes all three
    generics errors at once.
  - explode() never returns an empty array, so array_pop() always yields a
    string and the null check was dead.
  - substr() does not return false on PHP 8. Only the PHPDoc is narrowed;
    adding ": string" to the signature would break subclasses by
    covariance.
  - treatPhpDocTypesAsCertain: false silences two instanceof.alwaysTrue
    reports in QueryModifierCollection and ResultModifierCollection. Those
    guards are real - they catch untyped callers and throw
    InvalidArgumentException - so the check stays and the report goes.

phpstan 2.2 now reports no errors against ORM 3.6.7 and ORM 2.20.13. It
still reports one generics error against ORM 2.17-2.19, where
getClassMetadata() is annotated with @psalm-return and @psalm-template
that PHPStan does not read; ORM 2.20 changed those to @template and
@return. The QA job analyses the highest dependency set, so this does not
affect CI.
Also pre-existing and unrelated to ORM 3. The QA job installs whatever
php-cs-fixer is current, and the @PhpCsFixer ruleset has grown rules since
the last sweep: static_lambda, single_line_empty_body, no_extra_blank_lines,
whitespace_after_comma_in_array, ordered_imports, phpdoc_separation and a
few more. On a clean 2.x this reported 40 files; Happyr#322 had already brought
that down to 31 by reformatting the tests it touched.

No behaviour change. The specs still pass 527/527 and phpstan is still
clean. Running the fixer a second time reports nothing, so the tree is now
a fixed point of the current ruleset.
Records which two reports the setting silences, why the guards they point at
are load-bearing rather than dead code, and that replacing the setting with a
native variadic type changes InvalidArgumentException into TypeError and so
needs a major release.
@peter-gribanov
peter-gribanov merged commit 62885cf into Happyr:2.x Jul 28, 2026
18 checks passed
@peter-gribanov
peter-gribanov deleted the fix/workflows branch July 28, 2026 15:11
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