Fixes
bin/cake annotate all -rno longer silently strips manual@property-readlines for virtual accessors inherited from a trait, parent class, or abstract base. The tokenizer-based scan inEntityAnnotator::buildVirtualPropertyHintTypeMap()only saw_get*methods declared in the entity's own file body, so inherited accessors looked unaccounted-for and the--removepass dropped them. A complementary reflection-based scan now fills the inheritance gap: methods whose source file differs from the entity's own file are picked up via reflection, with the type resolved from the docblock@return(preferred — keeps generics, unions, FQCNs), then the PHP return type hint, thenmixed. The existing tokenizer path stays the source of truth for in-class methods. No public API change.
Improvements
-
New
'strict'tier forconcreteEntitiesInParam, mirroring thegenericsInParamtri-state pattern (false | true | 'strict'). On top oftrue, strict mode adds explicit method doc-blocks fordelete(),deleteOrFail(),deleteMany(),deleteManyOrFail(), andloadInto()typed with the concrete entity class, and narrows iterable params onpatchEntities/saveMany/saveManyOrFail/deleteMany/deleteManyOrFailtoiterable<TEntity>even whengenericsInParamis left at the defaultfalse. This gives PHPStan enough signal to rejectTable::delete($order)against anInvoicesTableat static-analysis time, mirroring the runtime guard discussed in cakephp/cakephp#19428. BothDocBlockHelper(bake template) andModelAnnotatorshare the new branch so freshly-baked and re-annotated output stay aligned. Method order follows the existing builder convention (delete/deleteOrFailbeforedeleteMany/deleteManyOrFail,loadIntolast). Fully opt-in — existingtrueusers see no change; association methods (link,unlink,replaceLinks, …) are intentionally out of scope. -
Generated table doc-blocks now emit
@extendsfirst, aligning with the class-level tag order proposed in php-collective/code-sniffer#59 (template, extends, implements, property, property-read, property-write, method, mixin). Applies to fresh annotations via theaddNewDocBlockpath; the append-to-existing path is unchanged — full reordering of legacy doc-blocks is left to the sniff fixer to avoid duplicating its work. -
TestClassAnnotatorTaskis now aPathAwareClassAnnotatorTaskInterfaceconsumer (declarestests/TestCaseviascanPaths()), and the dedicatedtests/TestCase/walk insideClassesCommand::execute()is removed. The last remaining "special" path is folded into the unified path-aware mechanism introduced in 2.17.0; per-taskshouldRun()gating is preserved so the same files are visited and the same tasks fire. Third-party tasks that declare overlapping roots now collapse via the shared dedup map instead of double-walking. Behavior is unchanged for users who keep the default task list.
Full Changelog: 2.17.0...2.18.0