Issue #3618612: Raise PHPStan to level 3 with an entity mapping, because the analysis runs at level 0 and lets a wrong type through
Raises PHPStan from level 0 to level 3, and fixes everything the level reports. There is no baseline file: the run is clean.
Why it was affordable. entity_mapping.neon tells phpstan-drupal which class each entity type loads as, which takes the count from 448 to 178 on its own. Without it every $storage->load() is an EntityInterface and every concrete call on one is a finding. The mapping covers orchestra's eleven entity types plus four a submodule integrates with (kessai, audit_trail, domain, easy_email).
Most of the volume was one duplication. drainQueue() had been copied into 75 test classes, and its unguarded while ($item = $queue->claimItem()) accounted for 108 findings by itself. It is now DrainEngineQueueTrait, used by 94 classes, with processNextQueueItem() beside it for the tests that step through a run instead of letting it settle. That is where the net -671 lines come from.
What the level caught in the engine:
WorkflowInterface::getLayout()documentednodesandflowsonly, while the bpmn_io capture also writesnodeLabelsandflowLabels. The contract was wrong.DelegationForm::validateForm()declaredvoid, butContentEntityFormInterface::validateForm()returns the built entity. It now returns it from every exit.- Nine places read a plugin's configuration behind a
PluginFormInterfacecheck alone, which does not carrygetConfiguration(); they requireConfigurableInterfacetoo. - Two form-alter hooks called
getEntity()on a bareFormInterface, and two Views filters calledaddWhere(), which belongs to the SQL backend rather than every query plugin. - Neither action base declared the
execute($entity)signature every subclass implements, so the argument was invisible to callers. - Three storage helpers returned
EntityStorageInterface, hiding the entity type from analysis. They call the manager directly now.
Test doubles that bound an argument with with() use willReturnMap(), which is what a stub supports; with() on a stub is deprecated in PHPUnit 12.5.11.
Verification. phpstan analyse clean at level 3, phpcs clean (Drupal and DrupalPractice), and the whole kernel suite green locally, including a re-run of 28 classes against a rebuilt test root to rule out an environment flake.