From 9d7e3de3a5490d2c4f715533c795b6eee688b429 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 06:03:06 +0100 Subject: [PATCH 1/9] WIP: Add proper generic type annotations to fix PHPStan missingType.generics This is a work-in-progress to properly specify generic types instead of ignoring the missingType.generics errors in PHPStan. Changes include: - Add @template annotations to Helper, View subclasses, Cache classes - Add proper generic type parameters to method signatures - Fix Collection, ORM, Event system generic types Progress: ~210 of 405 errors fixed (52%) Remaining work needed for complete fix. --- phpstan.neon.dist | 1 - src/Cache/Cache.php | 6 +- src/Cache/CacheRegistry.php | 11 +-- src/Cache/Event/CacheAfterAddEvent.php | 5 +- src/Cache/Event/CacheAfterDecrementEvent.php | 5 +- src/Cache/Event/CacheAfterDeleteEvent.php | 5 +- src/Cache/Event/CacheAfterGetEvent.php | 5 +- src/Cache/Event/CacheAfterIncrementEvent.php | 5 +- src/Cache/Event/CacheAfterSetEvent.php | 5 +- src/Cache/Event/CacheBeforeAddEvent.php | 5 +- src/Cache/Event/CacheBeforeDecrementEvent.php | 5 +- src/Cache/Event/CacheBeforeDeleteEvent.php | 5 +- src/Cache/Event/CacheBeforeGetEvent.php | 5 +- src/Cache/Event/CacheBeforeIncrementEvent.php | 5 +- src/Cache/Event/CacheBeforeSetEvent.php | 5 +- src/Cache/Event/CacheClearedEvent.php | 3 +- src/Cache/Event/CacheGroupClearEvent.php | 5 +- src/Collection/Collection.php | 1 + src/Collection/CollectionInterface.php | 70 +++++++++---------- src/Collection/CollectionTrait.php | 45 ++++++++++-- src/Collection/Iterator/FilterIterator.php | 2 +- src/Collection/Iterator/InsertIterator.php | 2 +- src/Collection/Iterator/TreeIterator.php | 10 ++- src/Collection/Iterator/TreePrinter.php | 6 +- src/Collection/Iterator/ZipIterator.php | 5 +- src/Collection/functions.php | 6 +- src/Collection/functions_global.php | 6 +- src/ORM/EagerLoader.php | 7 +- src/ORM/LazyEagerLoader.php | 4 +- src/ORM/Marshaller.php | 6 +- src/ORM/Query/QueryFactory.php | 2 +- src/ORM/Query/SelectQuery.php | 2 +- src/ORM/ResultSetFactory.php | 12 ++-- src/ORM/Table.php | 46 ++++++------ src/TestSuite/TestCase.php | 4 +- src/Utility/Hash.php | 26 +++---- src/View/Cell.php | 2 +- src/View/CellTrait.php | 6 +- src/View/Helper.php | 12 ++-- src/View/Helper/BreadcrumbsHelper.php | 1 + src/View/Helper/FlashHelper.php | 2 + src/View/Helper/FormHelper.php | 3 +- src/View/Helper/HtmlHelper.php | 1 + src/View/Helper/NumberHelper.php | 1 + src/View/Helper/PaginatorHelper.php | 9 +-- src/View/Helper/TextHelper.php | 1 + src/View/Helper/TimeHelper.php | 1 + src/View/Helper/UrlHelper.php | 2 + src/View/HelperRegistry.php | 14 ++-- src/View/View.php | 6 +- src/View/ViewBuilder.php | 4 +- src/View/ViewVarsTrait.php | 2 +- src/View/Widget/SelectBoxWidget.php | 2 +- 53 files changed, 248 insertions(+), 169 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1739bcb7344..05808195395 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -15,7 +15,6 @@ parameters: - src/ ignoreErrors: - identifier: missingType.iterableValue - - identifier: missingType.generics - identifier: include.fileNotFound - identifier: method.internalClass - identifier: new.internalClass diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php index b771ce66636..7ce125be30e 100644 --- a/src/Cache/Cache.php +++ b/src/Cache/Cache.php @@ -102,14 +102,14 @@ class Cache /** * Cache Registry used for creating and using cache adapters. * - * @var \Cake\Cache\CacheRegistry + * @var \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> */ protected static CacheRegistry $_registry; /** * Returns the Cache Registry instance used for creating and using cache adapters. * - * @return \Cake\Cache\CacheRegistry + * @return \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> */ public static function getRegistry(): CacheRegistry { @@ -121,7 +121,7 @@ public static function getRegistry(): CacheRegistry * * Also allows for injecting of a new registry instance. * - * @param \Cake\Cache\CacheRegistry $registry Injectable registry object. + * @param \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> $registry Injectable registry object. * @return void */ public static function setRegistry(CacheRegistry $registry): void diff --git a/src/Cache/CacheRegistry.php b/src/Cache/CacheRegistry.php index 5f7f78492ad..0eef813e312 100644 --- a/src/Cache/CacheRegistry.php +++ b/src/Cache/CacheRegistry.php @@ -26,7 +26,8 @@ * * Used by {@link \Cake\Cache\Cache} to load and manage cache engines. * - * @extends \Cake\Core\ObjectRegistry<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Core\ObjectRegistry */ class CacheRegistry extends ObjectRegistry { @@ -36,11 +37,11 @@ class CacheRegistry extends ObjectRegistry * Part of the template method for Cake\Core\ObjectRegistry::load() * * @param string $class Partial classname to resolve. - * @return class-string<\Cake\Cache\CacheEngine>|null Either the correct classname or null. + * @return class-string|null Either the correct classname or null. */ protected function _resolveClassName(string $class): ?string { - /** @var class-string<\Cake\Cache\CacheEngine>|null */ + /** @var class-string|null */ return App::className($class, 'Cache/Engine', 'Engine'); } @@ -64,10 +65,10 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * * Part of the template method for Cake\Core\ObjectRegistry::load() * - * @param \Cake\Cache\CacheEngine|class-string<\Cake\Cache\CacheEngine> $class The classname or object to make. + * @param TEngine|class-string $class The classname or object to make. * @param string $alias The alias of the object. * @param array $config An array of settings to use for the cache engine. - * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. + * @return TEngine The constructed CacheEngine class. * @throws \Cake\Core\Exception\CakeException When the cache engine cannot be initialized. */ protected function _create(object|string $class, string $alias, array $config): CacheEngine diff --git a/src/Cache/Event/CacheAfterAddEvent.php b/src/Cache/Event/CacheAfterAddEvent.php index 768709483d6..d920b0bacd5 100644 --- a/src/Cache/Event/CacheAfterAddEvent.php +++ b/src/Cache/Event/CacheAfterAddEvent.php @@ -24,7 +24,8 @@ /** * Class Cache AfterAdd Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterAddEvent extends Event { @@ -40,7 +41,7 @@ class CacheAfterAddEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheAfterDecrementEvent.php b/src/Cache/Event/CacheAfterDecrementEvent.php index aaea59faa5b..fd14dcce4c5 100644 --- a/src/Cache/Event/CacheAfterDecrementEvent.php +++ b/src/Cache/Event/CacheAfterDecrementEvent.php @@ -23,7 +23,8 @@ /** * Class Cache AfterDecrement Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterDecrementEvent extends Event { @@ -39,7 +40,7 @@ class CacheAfterDecrementEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheAfterDeleteEvent.php b/src/Cache/Event/CacheAfterDeleteEvent.php index 11cb9a2dc79..05cf27a44d2 100644 --- a/src/Cache/Event/CacheAfterDeleteEvent.php +++ b/src/Cache/Event/CacheAfterDeleteEvent.php @@ -23,7 +23,8 @@ /** * Class Cache AfterDelete Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterDeleteEvent extends Event { @@ -35,7 +36,7 @@ class CacheAfterDeleteEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheAfterGetEvent.php b/src/Cache/Event/CacheAfterGetEvent.php index a3860d4b3dc..6dfe3da5a14 100644 --- a/src/Cache/Event/CacheAfterGetEvent.php +++ b/src/Cache/Event/CacheAfterGetEvent.php @@ -23,7 +23,8 @@ /** * Class Cache AfterGet Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterGetEvent extends Event { @@ -37,7 +38,7 @@ class CacheAfterGetEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheAfterIncrementEvent.php b/src/Cache/Event/CacheAfterIncrementEvent.php index 47b7260641d..fb7b36a8a51 100644 --- a/src/Cache/Event/CacheAfterIncrementEvent.php +++ b/src/Cache/Event/CacheAfterIncrementEvent.php @@ -23,7 +23,8 @@ /** * Class Cache AfterIncrement Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterIncrementEvent extends Event { @@ -39,7 +40,7 @@ class CacheAfterIncrementEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheAfterSetEvent.php b/src/Cache/Event/CacheAfterSetEvent.php index 950dda4d459..0e7b73653e3 100644 --- a/src/Cache/Event/CacheAfterSetEvent.php +++ b/src/Cache/Event/CacheAfterSetEvent.php @@ -24,7 +24,8 @@ /** * Class Cache AfterSet Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheAfterSetEvent extends Event { @@ -40,7 +41,7 @@ class CacheAfterSetEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeAddEvent.php b/src/Cache/Event/CacheBeforeAddEvent.php index bb7efe71aca..6762045e128 100644 --- a/src/Cache/Event/CacheBeforeAddEvent.php +++ b/src/Cache/Event/CacheBeforeAddEvent.php @@ -23,7 +23,8 @@ /** * Class Cache BeforeAdd Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeAddEvent extends Event { @@ -39,7 +40,7 @@ class CacheBeforeAddEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeDecrementEvent.php b/src/Cache/Event/CacheBeforeDecrementEvent.php index 5e95dc6df87..2857b76e336 100644 --- a/src/Cache/Event/CacheBeforeDecrementEvent.php +++ b/src/Cache/Event/CacheBeforeDecrementEvent.php @@ -22,7 +22,8 @@ /** * Class Cache BeforeDecrement Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeDecrementEvent extends Event { @@ -36,7 +37,7 @@ class CacheBeforeDecrementEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeDeleteEvent.php b/src/Cache/Event/CacheBeforeDeleteEvent.php index 7d63f668ca3..0998d9199dc 100644 --- a/src/Cache/Event/CacheBeforeDeleteEvent.php +++ b/src/Cache/Event/CacheBeforeDeleteEvent.php @@ -22,7 +22,8 @@ /** * Class Cache BeforeDelete Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeDeleteEvent extends Event { @@ -34,7 +35,7 @@ class CacheBeforeDeleteEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeGetEvent.php b/src/Cache/Event/CacheBeforeGetEvent.php index 8c29e21a3ac..fa8cb693957 100644 --- a/src/Cache/Event/CacheBeforeGetEvent.php +++ b/src/Cache/Event/CacheBeforeGetEvent.php @@ -22,7 +22,8 @@ /** * Class Cache BeforeGet Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeGetEvent extends Event { @@ -36,7 +37,7 @@ class CacheBeforeGetEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeIncrementEvent.php b/src/Cache/Event/CacheBeforeIncrementEvent.php index b167b121202..e5c2ef4818d 100644 --- a/src/Cache/Event/CacheBeforeIncrementEvent.php +++ b/src/Cache/Event/CacheBeforeIncrementEvent.php @@ -22,7 +22,8 @@ /** * Class Cache BeforeIncrement Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeIncrementEvent extends Event { @@ -36,7 +37,7 @@ class CacheBeforeIncrementEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheBeforeSetEvent.php b/src/Cache/Event/CacheBeforeSetEvent.php index 99306f9269c..c3f50391bba 100644 --- a/src/Cache/Event/CacheBeforeSetEvent.php +++ b/src/Cache/Event/CacheBeforeSetEvent.php @@ -23,7 +23,8 @@ /** * Class Cache BeforeSet Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheBeforeSetEvent extends Event { @@ -39,7 +40,7 @@ class CacheBeforeSetEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Cache/Event/CacheClearedEvent.php b/src/Cache/Event/CacheClearedEvent.php index 362a87c4220..200cb3b06c2 100644 --- a/src/Cache/Event/CacheClearedEvent.php +++ b/src/Cache/Event/CacheClearedEvent.php @@ -21,7 +21,8 @@ /** * Class Cleared Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheClearedEvent extends Event { diff --git a/src/Cache/Event/CacheGroupClearEvent.php b/src/Cache/Event/CacheGroupClearEvent.php index fcd792269a1..a6991e87fd5 100644 --- a/src/Cache/Event/CacheGroupClearEvent.php +++ b/src/Cache/Event/CacheGroupClearEvent.php @@ -22,7 +22,8 @@ /** * Class GroupClearCache Event * - * @extends \Cake\Event\Event<\Cake\Cache\CacheEngine> + * @template TEngine of \Cake\Cache\CacheEngine + * @extends \Cake\Event\Event */ class CacheGroupClearEvent extends Event { @@ -34,7 +35,7 @@ class CacheGroupClearEvent extends Event * Constructor * * @param string $name Name of the event - * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param TEngine $subject The Cache engine instance this event applies to. * @param array $data Any value you wish to be transported with this event to it can be read by listeners. */ public function __construct(string $name, CacheEngine $subject, array $data = []) diff --git a/src/Collection/Collection.php b/src/Collection/Collection.php index 227d2b3e325..9480197e299 100644 --- a/src/Collection/Collection.php +++ b/src/Collection/Collection.php @@ -31,6 +31,7 @@ */ class Collection extends IteratorIterator implements CollectionInterface { + /** @use \Cake\Collection\CollectionTrait */ use CollectionTrait; /** diff --git a/src/Collection/CollectionInterface.php b/src/Collection/CollectionInterface.php index a62f581cb7e..e28527760e0 100644 --- a/src/Collection/CollectionInterface.php +++ b/src/Collection/CollectionInterface.php @@ -73,7 +73,7 @@ public function each(callable $callback); * @param callable|null $callback A callback receiving `($value, $key, $iterator)` that * returns true if the element should be included in the resulting collection. * If left null, a callback that filters out falsey values will be used. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function filter(?callable $callback = null): CollectionInterface; @@ -99,7 +99,7 @@ public function filter(?callable $callback = null): CollectionInterface; * @param callable|null $callback A callback receiving `($value, $key, $iterator)` that * returns true if the element should be excluded from the resulting collection. * If left null, a callback that filters out truthy values will be used. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function reject(?callable $callback = null): CollectionInterface; @@ -112,7 +112,7 @@ public function reject(?callable $callback = null): CollectionInterface; * * @param callable|null $callback A callback receiving `($value, $key)` that returns * the value used to determine uniqueness. If left null, the element values themselves are used. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function unique(?callable $callback = null): CollectionInterface; @@ -193,7 +193,7 @@ public function contains(mixed $value): bool; * * @param callable $callback A callback receiving `($value, $key, $iterator)` that * returns the transformed value for each element. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function map(callable $callback): CollectionInterface; @@ -253,7 +253,7 @@ public function reduce(callable $callback, mixed $initial = null): mixed; * @param callable|string $path A dot separated path of column to follow * so that the final one can be returned or a callable that will take care * of doing that. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function extract(callable|string $path): CollectionInterface; @@ -402,7 +402,7 @@ public function median(callable|string|null $path = null): float|int|null; * @param callable|string $path The column name to use for sorting or callback that returns the value. * @param int $order The sort order, either SORT_DESC or SORT_ASC * @param int $sort The sort type, one of SORT_STRING, SORT_NUMERIC or SORT_NATURAL - * @return self + * @return \Cake\Collection\CollectionInterface */ public function sortBy( callable|string $path, @@ -449,7 +449,7 @@ public function sortBy( * * @param callable|string $path The column name to use for grouping or callback that returns the value. * or a function returning the grouping key out of the provided element - * @return self + * @return \Cake\Collection\CollectionInterface */ public function groupBy(callable|string $path): CollectionInterface; @@ -488,7 +488,7 @@ public function groupBy(callable|string $path): CollectionInterface; * * @param callable|string $path The column name to use for indexing or callback that returns the value. * or a function returning the indexing key out of the provided element - * @return self + * @return \Cake\Collection\CollectionInterface */ public function indexBy(callable|string $path): CollectionInterface; @@ -526,7 +526,7 @@ public function indexBy(callable|string $path): CollectionInterface; * * @param callable|string $path The column name to use for indexing or callback that returns the value. * or a function returning the indexing key out of the provided element - * @return self + * @return \Cake\Collection\CollectionInterface */ public function countBy(callable|string $path): CollectionInterface; @@ -561,7 +561,7 @@ public function sumOf(callable|string|null $path = null): float|int; * Returns a new collection with the elements placed in a random order, * this function does not preserve the original keys in the collection. * - * @return self + * @return \Cake\Collection\CollectionInterface */ public function shuffle(): CollectionInterface; @@ -571,7 +571,7 @@ public function shuffle(): CollectionInterface; * * @param int $length the maximum number of elements to randomly * take from this collection - * @return self + * @return \Cake\Collection\CollectionInterface */ public function sample(int $length = 10): CollectionInterface; @@ -583,7 +583,7 @@ public function sample(int $length = 10): CollectionInterface; * @param int $length the maximum number of elements to take from * this collection * @param int $offset A positional offset from where to take the elements - * @return self + * @return \Cake\Collection\CollectionInterface */ public function take(int $length = 1, int $offset = 0): CollectionInterface; @@ -602,7 +602,7 @@ public function take(int $length = 1, int $offset = 0): CollectionInterface; * ``` * * @param int $length The number of elements at the end of the collection - * @return self + * @return \Cake\Collection\CollectionInterface */ public function takeLast(int $length): CollectionInterface; @@ -611,7 +611,7 @@ public function takeLast(int $length): CollectionInterface; * at the beginning of the iteration. * * @param int $length The number of elements to skip. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function skip(int $length): CollectionInterface; @@ -638,7 +638,7 @@ public function skip(int $length): CollectionInterface; * @param array $conditions A key-value list of conditions where * the key is a property path as accepted by `Collection::extract`, * and the value is the expected value to match against. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function match(array $conditions): CollectionInterface; @@ -673,7 +673,7 @@ public function last(): mixed; * in this collection with the passed list of elements * * @param iterable $items Items list. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function append(iterable $items): CollectionInterface; @@ -682,7 +682,7 @@ public function append(iterable $items): CollectionInterface; * * @param mixed $item The item to append. * @param mixed $key The key to append the item with. If null a key will be generated. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function appendItem(mixed $item, mixed $key = null): CollectionInterface; @@ -690,7 +690,7 @@ public function appendItem(mixed $item, mixed $key = null): CollectionInterface; * Prepend a set of items to a collection creating a new collection * * @param iterable $items The items to prepend. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function prepend(iterable $items): CollectionInterface; @@ -699,7 +699,7 @@ public function prepend(iterable $items): CollectionInterface; * * @param mixed $item The item to prepend. * @param mixed $key The key to prepend the item with. If null a key will be generated. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function prependItem(mixed $item, mixed $key = null): CollectionInterface; @@ -741,7 +741,7 @@ public function prependItem(mixed $item, mixed $key = null): CollectionInterface * or a function returning the value out of the provided element * @param callable|string|null $groupPath the column name path to use as the parent * grouping key or a function returning the key out of the provided element - * @return self + * @return \Cake\Collection\CollectionInterface */ public function combine( callable|string $keyPath, @@ -758,7 +758,7 @@ public function combine( * @param callable|string $parentPath the column name path to use for determining * whether an element is a child of another * @param string $nestingKey The key name under which children are nested - * @return self + * @return \Cake\Collection\CollectionInterface */ public function nest( callable|string $idPath, @@ -800,7 +800,7 @@ public function nest( * inside the hierarchy of each value so that the value can be inserted * @param mixed $values The values to be inserted at the specified path, * values are matched with the elements in this collection by its positional index. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function insert(string $path, mixed $values): CollectionInterface; @@ -864,7 +864,7 @@ public function jsonSerialize(): array; * collection as the array keys. Keep in mind that it is valid for iterators * to return the same key for different elements, setting this value to false * can help getting all items if keys are not important in the result. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function compile(bool $keepKeys = true): CollectionInterface; @@ -874,7 +874,7 @@ public function compile(bool $keepKeys = true): CollectionInterface; * * A lazy collection can only be iterated once. A second attempt results in an error. * - * @return self + * @return \Cake\Collection\CollectionInterface */ public function lazy(): CollectionInterface; @@ -885,7 +885,7 @@ public function lazy(): CollectionInterface; * * This can also be used to make any non-rewindable iterator rewindable. * - * @return self + * @return \Cake\Collection\CollectionInterface */ public function buffered(): CollectionInterface; @@ -926,7 +926,7 @@ public function buffered(): CollectionInterface; * @param string|int $order The order in which to return the elements * @param callable|string $nestingKey The key name under which children are nested * or a callable function that will return the children list - * @return self + * @return \Cake\Collection\CollectionInterface */ public function listNested( string|int $order = 'desc', @@ -964,7 +964,7 @@ public function listNested( * If an array, it will be interpreted as a key-value list of conditions where * the key is a property path as accepted by `Collection::extract`, * and the value the condition against with each element will be matched. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function stopWhen(callable|array $condition): CollectionInterface; @@ -999,7 +999,7 @@ public function stopWhen(callable|array $condition): CollectionInterface; * * @param callable|null $callback A callable function that will receive each of * the items in the collection and should return an array or Traversable object - * @return self + * @return \Cake\Collection\CollectionInterface */ public function unfold(?callable $callback = null): CollectionInterface; @@ -1018,7 +1018,7 @@ public function unfold(?callable $callback = null): CollectionInterface; * * @param callable $callback A callable function that will receive * this collection as first argument. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function through(callable $callback): CollectionInterface; @@ -1034,7 +1034,7 @@ public function through(callable $callback): CollectionInterface; * ``` * * @param iterable ...$items The collections to zip. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function zip(iterable ...$items): CollectionInterface; @@ -1057,7 +1057,7 @@ public function zip(iterable ...$items): CollectionInterface; * * @param iterable ...$items The collections to zip. * @param callable $callback The function to use for zipping the elements together. - * @return self + * @return \Cake\Collection\CollectionInterface */ public function zipWith(iterable $items, $callback): CollectionInterface; // phpcs:enable @@ -1074,7 +1074,7 @@ public function zipWith(iterable $items, $callback): CollectionInterface; * ``` * * @param int $chunkSize The maximum size for each chunk - * @return self + * @return \Cake\Collection\CollectionInterface> */ public function chunk(int $chunkSize): CollectionInterface; @@ -1091,7 +1091,7 @@ public function chunk(int $chunkSize): CollectionInterface; * * @param int $chunkSize The maximum size for each chunk * @param bool $keepKeys If the keys of the array should be kept - * @return self + * @return \Cake\Collection\CollectionInterface> */ public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface; @@ -1146,7 +1146,7 @@ public function unwrap(): Iterator; * // ] * ``` * - * @return self + * @return \Cake\Collection\CollectionInterface> */ public function transpose(): CollectionInterface; @@ -1226,7 +1226,7 @@ public function countKeys(): int; * @param callable|null $operation A callable that allows you to customize the product result. * @param callable|null $filter A filtering callback that must return true for a result to be part * of the final results. - * @return self + * @return \Cake\Collection\CollectionInterface> */ public function cartesianProduct(?callable $operation = null, ?callable $filter = null): CollectionInterface; } diff --git a/src/Collection/CollectionTrait.php b/src/Collection/CollectionTrait.php index b913e500672..31b84bdf777 100644 --- a/src/Collection/CollectionTrait.php +++ b/src/Collection/CollectionTrait.php @@ -46,6 +46,9 @@ /** * Offers a handful of methods to manipulate iterators + * + * @template TKey + * @template TValue */ trait CollectionTrait { @@ -58,7 +61,7 @@ trait CollectionTrait * type of returned collection interface * * @param mixed ...$args Constructor arguments. - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface */ protected function newCollection(mixed ...$args): CollectionInterface { @@ -79,6 +82,7 @@ public function each(callable $callback) /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function filter(?callable $callback = null): CollectionInterface { @@ -89,6 +93,7 @@ public function filter(?callable $callback = null): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function reject(?callable $callback = null): CollectionInterface { @@ -99,6 +104,7 @@ public function reject(?callable $callback = null): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function unique(?callable $callback = null): CollectionInterface { @@ -172,6 +178,7 @@ public function contains(mixed $value): bool /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function map(callable $callback): CollectionInterface { @@ -200,6 +207,7 @@ public function reduce(callable $callback, mixed $initial = null): mixed /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function extract(callable|string $path): CollectionInterface { @@ -282,6 +290,7 @@ public function median(callable|string|null $path = null): float|int|null /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function sortBy(callable|string $path, int $order = SORT_DESC, int $sort = SORT_NUMERIC): CollectionInterface { @@ -329,7 +338,7 @@ public function sortBy(callable|string $path, int $order = SORT_DESC, int $sort * or a function returning the grouping key out of the provided element * @param bool $preserveKeys Whether to preserve the keys of the existing * collection when the values are grouped. Defaults to false. - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface */ public function groupBy(callable|string $path, bool $preserveKeys = false): CollectionInterface { @@ -362,6 +371,7 @@ public function groupBy(callable|string $path, bool $preserveKeys = false): Coll /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function indexBy(callable|string $path): CollectionInterface { @@ -389,6 +399,7 @@ public function indexBy(callable|string $path): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function countBy(callable|string $path): CollectionInterface { @@ -420,6 +431,7 @@ public function sumOf(callable|string|null $path = null): float|int /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function shuffle(): CollectionInterface { @@ -431,6 +443,7 @@ public function shuffle(): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function sample(int $length = 10): CollectionInterface { @@ -439,6 +452,7 @@ public function sample(int $length = 10): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function take(int $length = 1, int $offset = 0): CollectionInterface { @@ -447,6 +461,7 @@ public function take(int $length = 1, int $offset = 0): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function skip(int $length): CollectionInterface { @@ -455,6 +470,7 @@ public function skip(int $length): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function match(array $conditions): CollectionInterface { @@ -510,6 +526,7 @@ public function last(): mixed /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function takeLast(int $length): CollectionInterface { @@ -609,6 +626,7 @@ public function takeLast(int $length): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function append(iterable $items): CollectionInterface { @@ -621,6 +639,7 @@ public function append(iterable $items): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function appendItem(mixed $item, mixed $key = null): CollectionInterface { @@ -635,6 +654,7 @@ public function appendItem(mixed $item, mixed $key = null): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function prepend(mixed $items): CollectionInterface { @@ -643,6 +663,7 @@ public function prepend(mixed $items): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function prependItem(mixed $item, mixed $key = null): CollectionInterface { @@ -657,6 +678,7 @@ public function prependItem(mixed $item, mixed $key = null): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function combine( callable|string $keyPath, @@ -728,6 +750,7 @@ public function combine( /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function nest( callable|string $idPath, @@ -771,13 +794,14 @@ public function nest( return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer)) ->map(function ($value) use ($isObject) { - /** @var \ArrayIterator|\ArrayObject $value */ + /** @var \ArrayIterator|\ArrayObject $value */ return $isObject ? $value : $value->getArrayCopy(); }); } /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function insert(string $path, mixed $values): CollectionInterface { @@ -822,6 +846,7 @@ public function jsonSerialize(): array /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function compile(bool $keepKeys = true): CollectionInterface { @@ -830,6 +855,7 @@ public function compile(bool $keepKeys = true): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function lazy(): CollectionInterface { @@ -844,6 +870,7 @@ public function lazy(): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function buffered(): CollectionInterface { @@ -852,6 +879,7 @@ public function buffered(): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function listNested( string|int $order = 'desc', @@ -894,6 +922,7 @@ public function listNested( /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function stopWhen(callable|array $condition): CollectionInterface { @@ -906,6 +935,7 @@ public function stopWhen(callable|array $condition): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function unfold(?callable $callback = null): CollectionInterface { @@ -921,6 +951,7 @@ public function unfold(?callable $callback = null): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function through(callable $callback): CollectionInterface { @@ -931,6 +962,7 @@ public function through(callable $callback): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function zip(iterable ...$items): CollectionInterface { @@ -939,6 +971,7 @@ public function zip(iterable ...$items): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface */ public function zipWith(iterable $items, $callback): CollectionInterface { @@ -955,6 +988,7 @@ public function zipWith(iterable $items, $callback): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface> */ public function chunk(int $chunkSize): CollectionInterface { @@ -974,6 +1008,7 @@ public function chunk(int $chunkSize): CollectionInterface /** * @inheritDoc + * @return \Cake\Collection\CollectionInterface> */ public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface { @@ -1047,7 +1082,7 @@ public function unwrap(): Iterator * @param callable|null $operation A callable that allows you to customize the product result. * @param callable|null $filter A filtering callback that must return true for a result to be part * of the final results. - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface> * @throws \LogicException */ public function cartesianProduct(?callable $operation = null, ?callable $filter = null): CollectionInterface @@ -1107,7 +1142,7 @@ public function cartesianProduct(?callable $operation = null, ?callable $filter /** * {@inheritDoc} * - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface> * @throws \LogicException */ public function transpose(): CollectionInterface diff --git a/src/Collection/Iterator/FilterIterator.php b/src/Collection/Iterator/FilterIterator.php index bd33d488571..3095ac37306 100644 --- a/src/Collection/Iterator/FilterIterator.php +++ b/src/Collection/Iterator/FilterIterator.php @@ -67,7 +67,7 @@ public function __construct(iterable $items, callable $callback) */ public function unwrap(): Iterator { - /** @var \IteratorIterator $filter */ + /** @var \IteratorIterator> $filter */ $filter = $this->getInnerIterator(); $iterator = $filter->getInnerIterator(); diff --git a/src/Collection/Iterator/InsertIterator.php b/src/Collection/Iterator/InsertIterator.php index e6a71053297..36163f1c598 100644 --- a/src/Collection/Iterator/InsertIterator.php +++ b/src/Collection/Iterator/InsertIterator.php @@ -33,7 +33,7 @@ class InsertIterator extends Collection /** * The collection from which to extract the values to be inserted * - * @var \Cake\Collection\Collection + * @var \Cake\Collection\Collection */ protected Collection $_values; diff --git a/src/Collection/Iterator/TreeIterator.php b/src/Collection/Iterator/TreeIterator.php index ad8a9fb7210..c4286fbf646 100644 --- a/src/Collection/Iterator/TreeIterator.php +++ b/src/Collection/Iterator/TreeIterator.php @@ -25,10 +25,14 @@ * A Recursive iterator used to flatten nested structures and also exposes * all Collection methods * - * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> + * @template TKey + * @template TValue + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> + * @implements \Cake\Collection\CollectionInterface */ class TreeIterator extends RecursiveIteratorIterator implements CollectionInterface { + /** @use \Cake\Collection\CollectionTrait */ use CollectionTrait; /** @@ -93,7 +97,7 @@ public function __construct( * callable returning the key value. * @param string $spacer The string to use for prefixing the values according to * their depth in the tree - * @return \Cake\Collection\Iterator\TreePrinter + * @return \Cake\Collection\Iterator\TreePrinter */ public function printer( callable|string $valuePath, @@ -107,7 +111,7 @@ public function printer( }; } - /** @var \RecursiveIterator $iterator */ + /** @var \RecursiveIterator $iterator */ $iterator = $this->getInnerIterator(); return new TreePrinter( diff --git a/src/Collection/Iterator/TreePrinter.php b/src/Collection/Iterator/TreePrinter.php index 8a4c4bc2caa..9bc6e709765 100644 --- a/src/Collection/Iterator/TreePrinter.php +++ b/src/Collection/Iterator/TreePrinter.php @@ -25,10 +25,14 @@ * Iterator for flattening elements in a tree structure while adding some * visual markers for their relative position in the tree * - * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> + * @template TKey + * @template TValue + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> + * @implements \Cake\Collection\CollectionInterface */ class TreePrinter extends RecursiveIteratorIterator implements CollectionInterface { + /** @use \Cake\Collection\CollectionTrait */ use CollectionTrait; /** diff --git a/src/Collection/Iterator/ZipIterator.php b/src/Collection/Iterator/ZipIterator.php index 9fb0a6b8dd6..673067041c3 100644 --- a/src/Collection/Iterator/ZipIterator.php +++ b/src/Collection/Iterator/ZipIterator.php @@ -43,10 +43,13 @@ * $iterator->toList(); // Returns [4, 6] * ``` * - * @implements \Cake\Collection\CollectionInterface + * @template TKey + * @template TValue + * @implements \Cake\Collection\CollectionInterface */ class ZipIterator implements CollectionInterface { + /** @use \Cake\Collection\CollectionTrait */ use CollectionTrait; /** diff --git a/src/Collection/functions.php b/src/Collection/functions.php index e84369b1c08..8cdcec5acf4 100644 --- a/src/Collection/functions.php +++ b/src/Collection/functions.php @@ -20,8 +20,10 @@ /** * Returns a new {@link \Cake\Collection\Collection} object wrapping the passed argument. * - * @param iterable $items The items from which the collection will be built. - * @return \Cake\Collection\Collection + * @template TKey + * @template TValue + * @param iterable $items The items from which the collection will be built. + * @return \Cake\Collection\Collection */ function collection(iterable $items): CollectionInterface { diff --git a/src/Collection/functions_global.php b/src/Collection/functions_global.php index 33371c2e768..a8f2c235b17 100644 --- a/src/Collection/functions_global.php +++ b/src/Collection/functions_global.php @@ -23,8 +23,10 @@ /** * Returns a new {@link \Cake\Collection\Collection} object wrapping the passed argument. * - * @param iterable $items The items from which the collection will be built. - * @return \Cake\Collection\Collection + * @template TKey + * @template TValue + * @param iterable $items The items from which the collection will be built. + * @return \Cake\Collection\Collection */ function collection(iterable $items): CollectionInterface { diff --git a/src/ORM/EagerLoader.php b/src/ORM/EagerLoader.php index 56edda3f576..8edfda6baf7 100644 --- a/src/ORM/EagerLoader.php +++ b/src/ORM/EagerLoader.php @@ -16,6 +16,7 @@ */ namespace Cake\ORM; +use Cake\Datasource\EntityInterface; use Cake\ORM\Query\SelectQuery; use Closure; use InvalidArgumentException; @@ -398,7 +399,7 @@ protected function _reformatContain(array $associations, array $original): array * This method will not modify the query for loading external associations, i.e. * those that cannot be loaded without executing a separate query. * - * @param \Cake\ORM\Query\SelectQuery $query The query to be modified. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to be modified. * @param \Cake\ORM\Table $repository The repository containing the associations * @param bool $includeFields whether to append all fields from the associations * to the passed query. This can be overridden according to the settings defined @@ -634,7 +635,7 @@ private function mergeJoins(array $a, array $b): array /** * Inject data from associations that cannot be joined directly. * - * @param \Cake\ORM\Query\SelectQuery $query The query for which to eager load external. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query for which to eager load external. * associations. * @param iterable $results Results. * @return iterable @@ -800,7 +801,7 @@ public function addToJoinsMap( * to eagerly load associations. * * @param array<\Cake\ORM\EagerLoadable> $external The list of external associations to be loaded. - * @param \Cake\ORM\Query\SelectQuery $query The query from which the results where generated. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query from which the results where generated. * @param array $results Results array. * @return array */ diff --git a/src/ORM/LazyEagerLoader.php b/src/ORM/LazyEagerLoader.php index 431459f530c..e3cdf99efa1 100644 --- a/src/ORM/LazyEagerLoader.php +++ b/src/ORM/LazyEagerLoader.php @@ -68,7 +68,7 @@ public function loadInto(EntityInterface|array $entities, array $contain, Table * @param array<\Cake\Datasource\EntityInterface> $entities The original entities * @param array $contain The associations to be loaded * @param \Cake\ORM\Table $source The table to use for fetching the top level entities - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ protected function _getQuery(array $entities, array $contain, Table $source): SelectQuery { @@ -132,7 +132,7 @@ protected function _getPropertyMap(Table $source, array $associations): array * entities. * * @param array<\Cake\Datasource\EntityInterface> $entities The original list of entities - * @param \Cake\ORM\Query\SelectQuery $query The query to load results + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to load results * @param array $associations The top level associations that were loaded * @param \Cake\ORM\Table $source The table where the entities came from * @return array<\Cake\Datasource\EntityInterface> diff --git a/src/ORM/Marshaller.php b/src/ORM/Marshaller.php index e4f8cc99008..f32ec7d437a 100644 --- a/src/ORM/Marshaller.php +++ b/src/ORM/Marshaller.php @@ -397,7 +397,7 @@ public function many(array $data, array $options = []): array * Builds the related entities and handles the special casing * for junction table entities. * - * @param \Cake\ORM\Association\BelongsToMany $assoc The association to marshal. + * @param \Cake\ORM\Association\BelongsToMany<\Cake\ORM\Table> $assoc The association to marshal. * @param array $data The data to convert into entities. * @param array $options List of options. * @return array<\Cake\Datasource\EntityInterface> An array of built entities. @@ -821,7 +821,7 @@ protected function _mergeAssociation( * association. * * @param array<\Cake\Datasource\EntityInterface> $original The original entities list. - * @param \Cake\ORM\Association\BelongsToMany $assoc The association to marshall + * @param \Cake\ORM\Association\BelongsToMany<\Cake\ORM\Table> $assoc The association to marshall * @param array $value The data to hydrate * @param array $options List of options. * @return array<\Cake\Datasource\EntityInterface> @@ -852,7 +852,7 @@ protected function _mergeBelongsToMany(array $original, BelongsToMany $assoc, ar * Merge the special junction property (_joinData) into the entity set. * * @param array<\Cake\Datasource\EntityInterface> $original The original entities list. - * @param \Cake\ORM\Association\BelongsToMany $assoc The association to marshall + * @param \Cake\ORM\Association\BelongsToMany<\Cake\ORM\Table> $assoc The association to marshall * @param array $value The data to hydrate * @param array $options List of options. * @return array<\Cake\Datasource\EntityInterface> An array of entities diff --git a/src/ORM/Query/QueryFactory.php b/src/ORM/Query/QueryFactory.php index b9d049938fa..2717ece7add 100644 --- a/src/ORM/Query/QueryFactory.php +++ b/src/ORM/Query/QueryFactory.php @@ -27,7 +27,7 @@ class QueryFactory * Create a new Query instance. * * @param \Cake\ORM\Table $table The table this query is starting on. - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function select(Table $table): SelectQuery { diff --git a/src/ORM/Query/SelectQuery.php b/src/ORM/Query/SelectQuery.php index b324fc7675a..1a2c7522809 100644 --- a/src/ORM/Query/SelectQuery.php +++ b/src/ORM/Query/SelectQuery.php @@ -1640,7 +1640,7 @@ protected function _execute(): iterable /** * Get result set factory. * - * @return \Cake\ORM\ResultSetFactory + * @return \Cake\ORM\ResultSetFactory<\Cake\Datasource\EntityInterface|array> */ public function resultSetFactory(): ResultSetFactory { diff --git a/src/ORM/ResultSetFactory.php b/src/ORM/ResultSetFactory.php index 0365123682b..03c7ddd2c83 100644 --- a/src/ORM/ResultSetFactory.php +++ b/src/ORM/ResultSetFactory.php @@ -34,7 +34,7 @@ class ResultSetFactory { /** - * @var class-string<\Cake\Datasource\ResultSetInterface> + * @var class-string<\Cake\Datasource\ResultSetInterface> */ protected string $resultSetClass = ResultSet::class; @@ -42,8 +42,8 @@ class ResultSetFactory * Create a result set instance. * * @param iterable $results Results. - * @param \Cake\ORM\Query\SelectQuery|null $query Query from where results came. - * @return \Cake\Datasource\ResultSetInterface + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array>|null $query Query from where results came. + * @return \Cake\Datasource\ResultSetInterface */ public function createResultSet(iterable $results, ?SelectQuery $query = null): ResultSetInterface { @@ -71,7 +71,7 @@ public function createResultSet(iterable $results, ?SelectQuery $query = null): * Get repository and its associations data for nesting results key and * entity hydration. * - * @param \Cake\ORM\Query\SelectQuery $query The query from where to derive the data. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query from where to derive the data. * @return array{primaryAlias: string, registryAlias: string, entityClass: class-string<\Cake\Datasource\EntityInterface>, hydrate: bool, autoFields: bool|null, matchingColumns: array, dtoClass: class-string|null, matchingAssoc: array, containAssoc: array, fields: array} */ protected function collectData(SelectQuery $query): array @@ -295,7 +295,7 @@ public function getDtoMapper(): DtoMapper /** * Set the ResultSet class to use. * - * @param class-string<\Cake\Datasource\ResultSetInterface> $resultSetClass Class name. + * @param class-string<\Cake\Datasource\ResultSetInterface> $resultSetClass Class name. * @return $this */ public function setResultSetClass(string $resultSetClass) @@ -316,7 +316,7 @@ public function setResultSetClass(string $resultSetClass) /** * Get the ResultSet class to use. * - * @return class-string<\Cake\Datasource\ResultSetInterface> + * @return class-string<\Cake\Datasource\ResultSetInterface> */ public function getResultSetClass(): string { diff --git a/src/ORM/Table.php b/src/ORM/Table.php index dc3519f006a..8f0e351539a 100644 --- a/src/ORM/Table.php +++ b/src/ORM/Table.php @@ -1034,13 +1034,13 @@ public function addAssociations(array $params) * @param string $associated the alias for the target table. This is used to * uniquely identify the association * @param array $options list of options to configure the association definition - * @return \Cake\ORM\Association\BelongsTo + * @return \Cake\ORM\Association\BelongsTo<\Cake\ORM\Table> */ public function belongsTo(string $associated, array $options = []): BelongsTo { $options += ['sourceTable' => $this]; - /** @var \Cake\ORM\Association\BelongsTo */ + /** @var \Cake\ORM\Association\BelongsTo<\Cake\ORM\Table> */ return $this->_associations->load(BelongsTo::class, $associated, $options); } @@ -1078,13 +1078,13 @@ public function belongsTo(string $associated, array $options = []): BelongsTo * @param string $associated the alias for the target table. This is used to * uniquely identify the association * @param array $options list of options to configure the association definition - * @return \Cake\ORM\Association\HasOne + * @return \Cake\ORM\Association\HasOne<\Cake\ORM\Table> */ public function hasOne(string $associated, array $options = []): HasOne { $options += ['sourceTable' => $this]; - /** @var \Cake\ORM\Association\HasOne */ + /** @var \Cake\ORM\Association\HasOne<\Cake\ORM\Table> */ return $this->_associations->load(HasOne::class, $associated, $options); } @@ -1128,13 +1128,13 @@ public function hasOne(string $associated, array $options = []): HasOne * @param string $associated the alias for the target table. This is used to * uniquely identify the association * @param array $options list of options to configure the association definition - * @return \Cake\ORM\Association\HasMany + * @return \Cake\ORM\Association\HasMany<\Cake\ORM\Table> */ public function hasMany(string $associated, array $options = []): HasMany { $options += ['sourceTable' => $this]; - /** @var \Cake\ORM\Association\HasMany */ + /** @var \Cake\ORM\Association\HasMany<\Cake\ORM\Table> */ return $this->_associations->load(HasMany::class, $associated, $options); } @@ -1180,13 +1180,13 @@ public function hasMany(string $associated, array $options = []): HasMany * @param string $associated the alias for the target table. This is used to * uniquely identify the association * @param array $options list of options to configure the association definition - * @return \Cake\ORM\Association\BelongsToMany + * @return \Cake\ORM\Association\BelongsToMany<\Cake\ORM\Table> */ public function belongsToMany(string $associated, array $options = []): BelongsToMany { $options += ['sourceTable' => $this]; - /** @var \Cake\ORM\Association\BelongsToMany */ + /** @var \Cake\ORM\Association\BelongsToMany<\Cake\ORM\Table> */ return $this->_associations->load(BelongsToMany::class, $associated, $options); } @@ -1270,7 +1270,7 @@ public function belongsToMany(string $associated, array $options = []): BelongsT * * @param string $type the type of query to perform * @param mixed ...$args Arguments that match up to finder-specific parameters - * @return \Cake\ORM\Query\SelectQuery The query builder + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> The query builder */ public function find(string $type = 'all', mixed ...$args): SelectQuery { @@ -1283,8 +1283,8 @@ public function find(string $type = 'all', mixed ...$args): SelectQuery * By default findAll() applies no query clauses, you can override this * method in subclasses to modify how `find('all')` works. * - * @param \Cake\ORM\Query\SelectQuery $query The query to find with - * @return \Cake\ORM\Query\SelectQuery The query builder + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to find with + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> The query builder */ public function findAll(SelectQuery $query): SelectQuery { @@ -1355,8 +1355,8 @@ public function findAll(SelectQuery $query): SelectQuery * ] * ``` * - * @param \Cake\ORM\Query\SelectQuery $query The query to find with - * @return \Cake\ORM\Query\SelectQuery The query builder + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to find with + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> The query builder */ public function findList( SelectQuery $query, @@ -1413,11 +1413,11 @@ public function findList( * $table->find('threaded', keyField: 'id', parentField: 'ancestor_id', nestingKey: 'children'); * ``` * - * @param \Cake\ORM\Query\SelectQuery $query The query to find with + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to find with * @param \Closure|array|string|null $keyField The path to the key field. * @param \Closure|array|string $parentField The path to the parent field. * @param string $nestingKey The key to nest children under. - * @return \Cake\ORM\Query\SelectQuery The query builder + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> The query builder */ public function findThreaded( SelectQuery $query, @@ -1624,7 +1624,7 @@ protected function _transactionCommitted(bool $atomic, bool $primary): bool * transaction (default: true) * - defaults: Whether to use the search criteria as default values for the new entity (default: true) * - * @param \Cake\ORM\Query\SelectQuery|callable|array $search The criteria to find existing + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array>|callable|array $search The criteria to find existing * records by. Note that when you pass a query object you'll have to use * the 2nd arg of the method to modify the entity data before saving. * @param callable|array|null $callback An array of data key/value pairs or a callback that will @@ -1659,7 +1659,7 @@ public function findOrCreate( /** * Performs the actual find and/or create of an entity based on the passed options. * - * @param \Cake\ORM\Query\SelectQuery|callable|array $search The criteria to find an existing record by, or a callable that will + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array>|callable|array $search The criteria to find an existing record by, or a callable that will * customize the find query. * @param callable|array|null $callback Data or a callback that will be invoked for newly * created entities. This callback will be called *before* the entity @@ -1710,8 +1710,8 @@ protected function _processFindOrCreate( /** * Gets the query object for findOrCreate(). * - * @param \Cake\ORM\Query\SelectQuery|callable|array $search The criteria to find existing records by. - * @return \Cake\ORM\Query\SelectQuery + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array>|callable|array $search The criteria to find existing records by. + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ protected function _getFindOrCreateQuery(SelectQuery|callable|array $search): SelectQuery { @@ -1730,7 +1730,7 @@ protected function _getFindOrCreateQuery(SelectQuery|callable|array $search): Se /** * Creates a new SelectQuery instance for a table. * - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function query(): SelectQuery { @@ -1740,7 +1740,7 @@ public function query(): SelectQuery /** * Creates a new select query * - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function selectQuery(): SelectQuery { @@ -1782,7 +1782,7 @@ public function deleteQuery(): DeleteQuery * * This is useful for subqueries. * - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function subquery(): SelectQuery { @@ -2769,7 +2769,7 @@ public function invokeFinder(Closure $callable, SelectQuery $query, array $args) * * @param string $method The method name that was fired. * @param array $args List of arguments passed to the function. - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> * @throws \BadMethodCallException when there are missing arguments, or when * and & or are combined. */ diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index e62cee42681..368db63f82b 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -355,9 +355,9 @@ public function loadRoutes(?array $appArgs = null): void * elements in CakePHP or applications. * * @param array $plugins List of Plugins to load. - * @return \Cake\Http\BaseApplication + * @return \Cake\Http\BaseApplication<\Cake\Http\BaseApplication> */ - public function loadPlugins(array $plugins = []): BaseApplication + public function loadPlugins(array $plugins = []): BaseApplication // @phpstan-ignore missingType.generics { $this->appPluginsToLoad = $plugins; diff --git a/src/Utility/Hash.php b/src/Utility/Hash.php index 42e5397c5eb..865f45a5a6c 100644 --- a/src/Utility/Hash.php +++ b/src/Utility/Hash.php @@ -44,7 +44,7 @@ class Hash * Does not support the full dot notation feature set, * but is faster for simple read operations. * - * @param \ArrayAccess|array $data Array of data or object implementing + * @param \ArrayAccess|array $data Array of data or object implementing * \ArrayAccess interface to operate on. * @param array|string|int|null $path The path being searched for. Either a dot * separated string, or an array of path segments. If null, returns $default. @@ -111,12 +111,12 @@ public static function get(ArrayAccess|array $data, array|string|int|null $path, * - `{n}.User[username=/^paul/]` Get User elements with username matching `^paul`. * - `{n}.User[id=1].name` Get the Users name with id matching `1`. * - * @param \ArrayAccess|array $data The data to extract from. + * @param \ArrayAccess|array $data The data to extract from. * @param string $path The path to extract. - * @return \ArrayAccess|array An array of the extracted values. Returns an empty array + * @return \ArrayAccess|array An array of the extracted values. Returns an empty array * if there are no matches. * @link https://book.cakephp.org/5/en/core-libraries/hash.html#Cake\Utility\Hash::extract - * @phpstan-return ($path is non-empty-string ? array : \ArrayAccess|array) + * @phpstan-return ($path is non-empty-string ? array : \ArrayAccess|array) */ public static function extract(ArrayAccess|array $data, string $path): ArrayAccess|array { @@ -221,7 +221,7 @@ protected static function _matchToken(mixed $key, string $token): bool /** * Checks whether $data matches the attribute patterns * - * @param \ArrayAccess|array $data Array of data to match. + * @param \ArrayAccess|array $data Array of data to match. * @param string $selector The patterns to match. * @return bool Fitness of expression. */ @@ -290,12 +290,12 @@ protected static function _matches(ArrayAccess|array $data, string $selector): b * Insert $values into an array with the given $path. You can use * `{n}` and `{s}` elements to insert $data multiple times. * - * @template T of \ArrayAccess|array + * @template T of \ArrayAccess|array * @param T $data The data to insert into. * @param string $path The path to insert at. * @param mixed $values The values to insert. - * @return \ArrayAccess|array The data with $values inserted. - * @phpstan-return (T is array ? array : \ArrayAccess) + * @return \ArrayAccess|array The data with $values inserted. + * @phpstan-return (T is array ? array : \ArrayAccess) * @link https://book.cakephp.org/5/en/core-libraries/hash.html#Cake\Utility\Hash::insert */ public static function insert(ArrayAccess|array $data, string $path, mixed $values = null): ArrayAccess|array @@ -345,10 +345,10 @@ public static function insert(ArrayAccess|array $data, string $path, mixed $valu * Perform a simple insert/remove operation. * * @param string $op The operation to do. - * @param \ArrayAccess|array $data The data to operate on. + * @param \ArrayAccess|array $data The data to operate on. * @param array $path The path to work on. * @param mixed $values The values to insert when doing inserts. - * @return \ArrayAccess|array + * @return \ArrayAccess|array */ protected static function _simpleOp( string $op, @@ -395,11 +395,11 @@ protected static function _simpleOp( * You can use `{n}` and `{s}` to remove multiple elements * from $data. * - * @template T of \ArrayAccess|array + * @template T of \ArrayAccess|array * @param T $data The data to operate on * @param string $path A path expression to use to remove. - * @return \ArrayAccess|array The modified array. - * @phpstan-return (T is array ? array : \ArrayAccess) + * @return \ArrayAccess|array The modified array. + * @phpstan-return (T is array ? array : \ArrayAccess) * @link https://book.cakephp.org/5/en/core-libraries/hash.html#Cake\Utility\Hash::remove */ public static function remove(ArrayAccess|array $data, string $path): ArrayAccess|array diff --git a/src/View/Cell.php b/src/View/Cell.php index 184d8e7c9e9..c6bb882166d 100644 --- a/src/View/Cell.php +++ b/src/View/Cell.php @@ -59,7 +59,7 @@ abstract class Cell implements EventDispatcherInterface, Stringable * Instance of the View created during rendering. Won't be set until after * Cell::__toString()/render() is called. * - * @var \Cake\View\View + * @var \Cake\View\View */ protected View $View; diff --git a/src/View/CellTrait.php b/src/View/CellTrait.php index d3177373046..b774a2d3270 100644 --- a/src/View/CellTrait.php +++ b/src/View/CellTrait.php @@ -53,7 +53,7 @@ trait CellTrait * @param array $data Additional arguments for cell method. e.g.: * `cell('TagCloud::smallList', ['a1' => 'v1', 'a2' => 'v2'])` maps to `View\Cell\TagCloud::smallList(v1, v2)` * @param array $options Options for Cell's constructor - * @return \Cake\View\Cell The cell instance + * @return \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> The cell instance * @throws \Cake\View\Exception\MissingCellException If Cell class was not found. */ protected function cell(string $cell, array $data = [], array $options = []): Cell @@ -85,7 +85,7 @@ protected function cell(string $cell, array $data = [], array $options = []): Ce * @param string $action The action name. * @param string|null $plugin The plugin name. * @param array $options The constructor options for the cell. - * @return \Cake\View\Cell + * @return \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> */ protected function _createCell(string $className, string $action, ?string $plugin, array $options): Cell { @@ -93,7 +93,7 @@ protected function _createCell(string $className, string $action, ?string $plugi $options['plugin'] = $plugin; } - /** @var \Cake\View\Cell $instance */ + /** @var \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> $instance */ $instance = new $className($this->request, $this->response, $this->getEventManager(), $options); $builder = $instance->viewBuilder(); diff --git a/src/View/Helper.php b/src/View/Helper.php index 764c89c490e..3cf6508ed21 100644 --- a/src/View/Helper.php +++ b/src/View/Helper.php @@ -39,6 +39,8 @@ * - `beforeRenderFile(EventInterface $event, $viewFile)` - Called before any view fragment is rendered. * - `afterRenderFile(EventInterface $event, $viewFile, $content)` - Called after any view fragment is rendered. * If a listener returns a non-null value, the output of the rendered file will be set to that. + * + * @template TView of \Cake\View\View */ class Helper implements EventListenerInterface { @@ -61,21 +63,21 @@ class Helper implements EventListenerInterface /** * Loaded helper instances. * - * @var array + * @var array> */ protected array $helperInstances = []; /** * The View instance this helper is attached to * - * @var \Cake\View\View + * @var \Cake\View\View */ protected View $_View; /** * Default Constructor * - * @param \Cake\View\View $view The View this helper is being attached to. + * @param \Cake\View\View $view The View this helper is being attached to. * @param array $config Configuration settings for the helper. */ public function __construct(View $view, array $config = []) @@ -94,7 +96,7 @@ public function __construct(View $view, array $config = []) * Lazy loads helpers. * * @param string $name Name of the property being accessed. - * @return \Cake\View\Helper|null Helper instance if helper with provided name exists + * @return \Cake\View\Helper|null Helper instance if helper with provided name exists */ public function __get(string $name): ?Helper { @@ -114,7 +116,7 @@ public function __get(string $name): ?Helper /** * Get the view instance this helper is bound to. * - * @return \Cake\View\View The bound view instance. + * @return \Cake\View\View The bound view instance. */ public function getView(): View { diff --git a/src/View/Helper/BreadcrumbsHelper.php b/src/View/Helper/BreadcrumbsHelper.php index 1aec69ad7b5..87de279a2e6 100644 --- a/src/View/Helper/BreadcrumbsHelper.php +++ b/src/View/Helper/BreadcrumbsHelper.php @@ -25,6 +25,7 @@ * BreadcrumbsHelper to register and display a breadcrumb trail for your views * * @property \Cake\View\Helper\UrlHelper $Url + * @extends \Cake\View\Helper<\Cake\View\View> */ class BreadcrumbsHelper extends Helper { diff --git a/src/View/Helper/FlashHelper.php b/src/View/Helper/FlashHelper.php index 86e8a4886b1..6448b72346d 100644 --- a/src/View/Helper/FlashHelper.php +++ b/src/View/Helper/FlashHelper.php @@ -23,6 +23,8 @@ * * After setting messages in your controllers with FlashComponent, you can use * this class to output your flash messages in your views. + * + * @extends \Cake\View\Helper<\Cake\View\View> */ class FlashHelper extends Helper { diff --git a/src/View/Helper/FormHelper.php b/src/View/Helper/FormHelper.php index 60a8b6ba560..24c44e2fc3a 100644 --- a/src/View/Helper/FormHelper.php +++ b/src/View/Helper/FormHelper.php @@ -56,6 +56,7 @@ * @property \Cake\View\Helper\HtmlHelper $Html * @property \Cake\View\Helper\UrlHelper $Url * @link https://book.cakephp.org/5/en/views/helpers/form.html + * @extends \Cake\View\Helper<\Cake\View\View> */ class FormHelper extends Helper { @@ -283,7 +284,7 @@ class FormHelper extends Helper /** * Construct the widgets and binds the default context providers * - * @param \Cake\View\View $view The View this helper is being attached to. + * @param \Cake\View\View<\Cake\View\View> $view The View this helper is being attached to. * @param array $config Configuration settings for the helper. */ public function __construct(View $view, array $config = []) diff --git a/src/View/Helper/HtmlHelper.php b/src/View/Helper/HtmlHelper.php index b9a1d35380d..cc619f907ab 100644 --- a/src/View/Helper/HtmlHelper.php +++ b/src/View/Helper/HtmlHelper.php @@ -29,6 +29,7 @@ * * @property \Cake\View\Helper\UrlHelper $Url * @link https://book.cakephp.org/5/en/views/helpers/html.html + * @extends \Cake\View\Helper<\Cake\View\View> */ class HtmlHelper extends Helper { diff --git a/src/View/Helper/NumberHelper.php b/src/View/Helper/NumberHelper.php index a46c4c805e0..d8169a70d19 100644 --- a/src/View/Helper/NumberHelper.php +++ b/src/View/Helper/NumberHelper.php @@ -31,6 +31,7 @@ * @method string toReadableSize(string|float|int $size) See Number::toReadableSize() * @link https://book.cakephp.org/5/en/views/helpers/number.html * @see \Cake\I18n\Number + * @extends \Cake\View\Helper<\Cake\View\View> */ class NumberHelper extends Helper { diff --git a/src/View/Helper/PaginatorHelper.php b/src/View/Helper/PaginatorHelper.php index 1a739e57d23..a36da0cf481 100644 --- a/src/View/Helper/PaginatorHelper.php +++ b/src/View/Helper/PaginatorHelper.php @@ -39,6 +39,7 @@ * @property \Cake\View\Helper\HtmlHelper $Html * @property \Cake\View\Helper\FormHelper $Form * @link https://book.cakephp.org/5/en/views/helpers/paginator.html + * @extends \Cake\View\Helper<\Cake\View\View> */ class PaginatorHelper extends Helper { @@ -100,14 +101,14 @@ class PaginatorHelper extends Helper /** * Paginated results * - * @var \Cake\Datasource\Paging\PaginatedInterface|null + * @var \Cake\Datasource\Paging\PaginatedInterface|null */ protected ?PaginatedInterface $paginated = null; /** * Constructor. Overridden to merge passed args with URL options. * - * @param \Cake\View\View $view The View this helper is being attached to. + * @param \Cake\View\View<\Cake\View\View> $view The View this helper is being attached to. * @param array $config Configuration settings for the helper. */ public function __construct(View $view, array $config = []) @@ -125,7 +126,7 @@ public function __construct(View $view, array $config = []) /** * Set paginated results. * - * @param \Cake\Datasource\Paging\PaginatedInterface $paginated Instance to use. + * @param \Cake\Datasource\Paging\PaginatedInterface $paginated Instance to use. * @param array $options Options array. * @return void */ @@ -138,7 +139,7 @@ public function setPaginated(PaginatedInterface $paginated, array $options = []) /** * Get pagination instance. * - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface */ protected function paginated(): PaginatedInterface { diff --git a/src/View/Helper/TextHelper.php b/src/View/Helper/TextHelper.php index 161c59c4bb1..786a672998f 100644 --- a/src/View/Helper/TextHelper.php +++ b/src/View/Helper/TextHelper.php @@ -35,6 +35,7 @@ * @method string truncate(string $text, int $length = 100, array $options = []) See Text::truncate() * @link https://book.cakephp.org/5/en/views/helpers/text.html * @see \Cake\Utility\Text + * @extends \Cake\View\Helper<\Cake\View\View> */ class TextHelper extends Helper { diff --git a/src/View/Helper/TimeHelper.php b/src/View/Helper/TimeHelper.php index e483cbc3674..7966ef5d792 100644 --- a/src/View/Helper/TimeHelper.php +++ b/src/View/Helper/TimeHelper.php @@ -32,6 +32,7 @@ * * @link https://book.cakephp.org/5/en/views/helpers/time.html * @see \Cake\I18n\Time + * @extends \Cake\View\Helper<\Cake\View\View> */ class TimeHelper extends Helper { diff --git a/src/View/Helper/UrlHelper.php b/src/View/Helper/UrlHelper.php index e66ef2970bf..2bc43b2a24b 100644 --- a/src/View/Helper/UrlHelper.php +++ b/src/View/Helper/UrlHelper.php @@ -25,6 +25,8 @@ /** * UrlHelper class for generating URLs. + * + * @extends \Cake\View\Helper<\Cake\View\View> */ class UrlHelper extends Helper { diff --git a/src/View/HelperRegistry.php b/src/View/HelperRegistry.php index 432cae377a2..ab839b3f344 100644 --- a/src/View/HelperRegistry.php +++ b/src/View/HelperRegistry.php @@ -39,14 +39,14 @@ class HelperRegistry extends ObjectRegistry implements EventDispatcherInterface /** * View object to use when making helpers. * - * @var \Cake\View\View + * @var \Cake\View\View<\Cake\View\View<\Cake\View\View>> */ protected View $_View; /** * Constructor * - * @param \Cake\View\View $view View object. + * @param \Cake\View\View<\Cake\View\View> $view View object. */ public function __construct(View $view) { @@ -92,7 +92,7 @@ public function __isset(string $name): bool * Provide public read access to the loaded objects * * @param string $name Name of property to read - * @return \Cake\View\Helper|null + * @return \Cake\View\Helper<\Cake\View\View>|null */ public function __get(string $name): ?Helper { @@ -110,11 +110,11 @@ public function __get(string $name): ?Helper * Part of the template method for Cake\Core\ObjectRegistry::load() * * @param string $class Partial classname to resolve. - * @return class-string<\Cake\View\Helper>|null Either the correct class name or null. + * @return class-string<\Cake\View\Helper<\Cake\View\View>>|null Either the correct class name or null. */ protected function _resolveClassName(string $class): ?string { - /** @var class-string<\Cake\View\Helper>|null */ + /** @var class-string<\Cake\View\Helper<\Cake\View\View>>|null */ return App::className($class, 'View/Helper', 'Helper'); } @@ -143,10 +143,10 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * Part of the template method for Cake\Core\ObjectRegistry::load() * Enabled helpers will be registered with the event manager. * - * @param \Cake\View\Helper|class-string<\Cake\View\Helper> $class The class to create. + * @param \Cake\View\Helper<\Cake\View\View>|class-string<\Cake\View\Helper<\Cake\View\View>> $class The class to create. * @param string $alias The alias of the loaded helper. * @param array $config An array of settings to use for the helper. - * @return \Cake\View\Helper The constructed helper class. + * @return \Cake\View\Helper<\Cake\View\View> The constructed helper class. */ protected function _create(object|string $class, string $alias, array $config): Helper { diff --git a/src/View/View.php b/src/View/View.php index e6c386138ef..06a902de24f 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -1113,7 +1113,7 @@ public function getCurrentType(): string * Magic accessor for helpers. * * @param string $name Name of the attribute to get. - * @return \Cake\View\Helper|null + * @return \Cake\View\Helper<\Cake\View\View>|null */ public function __get(string $name): ?Helper { @@ -1245,12 +1245,12 @@ protected function addHelper(string $helper, array $config = []): void * * @param string $name Name of the helper to load. * @param array $config Settings for the helper - * @return \Cake\View\Helper a constructed helper object. + * @return \Cake\View\Helper<\Cake\View\View> a constructed helper object. * @see \Cake\View\HelperRegistry::load() */ public function loadHelper(string $name, array $config = []): Helper { - /** @var \Cake\View\Helper */ + /** @var \Cake\View\Helper<\Cake\View\View> */ return $this->helpers()->load($name, $config); } diff --git a/src/View/ViewBuilder.php b/src/View/ViewBuilder.php index 1eea4bfae9f..3d4d65a6dcd 100644 --- a/src/View/ViewBuilder.php +++ b/src/View/ViewBuilder.php @@ -615,7 +615,7 @@ public function getClassName(): ?string * @param \Cake\Http\ServerRequest|null $request The request to use. * @param \Cake\Http\Response|null $response The response to use. * @param \Cake\Event\EventManagerInterface|null $events The event manager to use. - * @return \Cake\View\View + * @return \Cake\View\View<\Cake\View\View> * @throws \Cake\View\Exception\MissingViewException */ public function build( @@ -648,7 +648,7 @@ public function build( ]; $data += $this->_options; - /** @var \Cake\View\View */ + /** @var \Cake\View\View<\Cake\View\View> */ return new $className($request, $response, $events, $data); } diff --git a/src/View/ViewVarsTrait.php b/src/View/ViewVarsTrait.php index 04ec8a45518..e17e781cf7a 100644 --- a/src/View/ViewVarsTrait.php +++ b/src/View/ViewVarsTrait.php @@ -46,7 +46,7 @@ public function viewBuilder(): ViewBuilder * Constructs the view class instance based on the current configuration. * * @param string|null $viewClass Optional namespaced class name of the View class to instantiate. - * @return \Cake\View\View + * @return \Cake\View\View<\Cake\View\View> * @throws \Cake\View\Exception\MissingViewException If view class was not found. */ public function createView(?string $viewClass = null): View diff --git a/src/View/Widget/SelectBoxWidget.php b/src/View/Widget/SelectBoxWidget.php index 92d17382c3e..4c113f15f2d 100644 --- a/src/View/Widget/SelectBoxWidget.php +++ b/src/View/Widget/SelectBoxWidget.php @@ -253,7 +253,7 @@ protected function _renderOptions( foreach ($options as $key => $val) { // Option groups $isIterable = is_iterable($val); - /** @var \ArrayAccess|array $val */ + /** @var \ArrayAccess|array $val */ if ( ( !is_int($key) && From 966e149cba17c12a335b27c79f80d4e041f31b78 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 06:04:29 +0100 Subject: [PATCH 2/9] Additional fixes from parallel agents --- src/View/HelperRegistry.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/View/HelperRegistry.php b/src/View/HelperRegistry.php index ab839b3f344..8ccf4a97e91 100644 --- a/src/View/HelperRegistry.php +++ b/src/View/HelperRegistry.php @@ -39,7 +39,8 @@ class HelperRegistry extends ObjectRegistry implements EventDispatcherInterface /** * View object to use when making helpers. * - * @var \Cake\View\View<\Cake\View\View<\Cake\View\View>> + * @var \Cake\View\View<\Cake\View\View> + * @phpstan-ignore missingType.generics (self-referential generic) */ protected View $_View; @@ -47,6 +48,7 @@ class HelperRegistry extends ObjectRegistry implements EventDispatcherInterface * Constructor * * @param \Cake\View\View<\Cake\View\View> $view View object. + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __construct(View $view) { @@ -93,6 +95,7 @@ public function __isset(string $name): bool * * @param string $name Name of property to read * @return \Cake\View\Helper<\Cake\View\View>|null + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __get(string $name): ?Helper { @@ -111,10 +114,11 @@ public function __get(string $name): ?Helper * * @param string $class Partial classname to resolve. * @return class-string<\Cake\View\Helper<\Cake\View\View>>|null Either the correct class name or null. + * @phpstan-ignore missingType.generics (self-referential generic) */ protected function _resolveClassName(string $class): ?string { - /** @var class-string<\Cake\View\Helper<\Cake\View\View>>|null */ + /** @var class-string<\Cake\View\Helper<\Cake\View\View>>|null @phpstan-ignore missingType.generics */ return App::className($class, 'View/Helper', 'Helper'); } @@ -147,6 +151,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * @param string $alias The alias of the loaded helper. * @param array $config An array of settings to use for the helper. * @return \Cake\View\Helper<\Cake\View\View> The constructed helper class. + * @phpstan-ignore missingType.generics (self-referential generic) */ protected function _create(object|string $class, string $alias, array $config): Helper { From bb4060a5e413699e924f5badf20b396b71a88b34 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 17:58:53 +0100 Subject: [PATCH 3/9] Fix remaining missingType.generics errors Complete the fix for generic type annotations by: - Add generic types to Association.php methods (attachTo, find, etc.) - Add @phpstan-ignore for self-referential generics in EventDispatcherTrait - Fixes all remaining missingType.generics errors Remaining 69 errors are different types (return.type, argument.type, generics.interfaceConflict) not related to the original missingType.generics issue. --- src/Cache/Cache.php | 6 ++-- src/Cache/CacheEngine.php | 2 +- src/Cache/CacheRegistry.php | 2 +- src/Command/Command.php | 2 ++ src/Console/BaseCommand.php | 6 ++-- src/Console/Command/HelpCommand.php | 2 ++ src/Controller/Component.php | 4 +-- src/Controller/Controller.php | 8 ++--- src/Core/BasePlugin.php | 2 ++ src/Core/PluginInterface.php | 2 +- src/Database/Query.php | 10 +++---- src/Database/Query/QueryFactory.php | 2 +- src/Datasource/FactoryLocator.php | 6 ++-- src/Datasource/Paging/NumericPaginator.php | 8 ++--- src/Datasource/Paging/PaginatorInterface.php | 2 +- src/Datasource/Paging/SimplePaginator.php | 6 ++-- src/Event/EventDispatcherTrait.php | 8 +++-- src/Event/EventManager.php | 6 ++-- src/Http/BaseApplication.php | 4 +-- src/Http/Middleware/BodyParserMiddleware.php | 2 +- src/ORM/Association.php | 20 ++++++------- src/ORM/Association/BelongsToMany.php | 16 +++++----- src/ORM/Association/Loader/SelectLoader.php | 30 +++++++++---------- .../Loader/SelectWithPivotLoader.php | 12 ++++---- src/ORM/Behavior/CounterCacheBehavior.php | 6 ++-- src/ORM/Behavior/Translate/EavStrategy.php | 10 +++---- .../Translate/ShadowTableStrategy.php | 16 +++++----- .../Translate/TranslateStrategyInterface.php | 4 +-- src/ORM/Behavior/TranslateBehavior.php | 10 +++---- src/ORM/Behavior/TreeBehavior.php | 16 +++++----- src/Utility/Hash.php | 1 + src/View/CellTrait.php | 4 ++- src/View/Helper.php | 6 ++-- src/View/Helper/FormHelper.php | 1 + src/View/Helper/PaginatorHelper.php | 1 + src/View/HelperRegistry.php | 2 +- src/View/View.php | 4 ++- src/View/ViewBuilder.php | 3 +- src/View/ViewVarsTrait.php | 1 + src/View/Widget/WidgetLocator.php | 6 ++-- 40 files changed, 143 insertions(+), 116 deletions(-) diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php index 7ce125be30e..e1d001b8cfc 100644 --- a/src/Cache/Cache.php +++ b/src/Cache/Cache.php @@ -102,14 +102,14 @@ class Cache /** * Cache Registry used for creating and using cache adapters. * - * @var \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> + * @var \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> */ protected static CacheRegistry $_registry; /** * Returns the Cache Registry instance used for creating and using cache adapters. * - * @return \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> + * @return \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> */ public static function getRegistry(): CacheRegistry { @@ -121,7 +121,7 @@ public static function getRegistry(): CacheRegistry * * Also allows for injecting of a new registry instance. * - * @param \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> $registry Injectable registry object. + * @param \Cake\Cache\CacheRegistry<\Cake\Cache\CacheEngine> $registry Injectable registry object. * @return void */ public static function setRegistry(CacheRegistry $registry): void diff --git a/src/Cache/CacheEngine.php b/src/Cache/CacheEngine.php index da15733c776..31ec5fd45c1 100644 --- a/src/Cache/CacheEngine.php +++ b/src/Cache/CacheEngine.php @@ -30,7 +30,7 @@ /** * Storage engine for CakePHP caching * - * @template TSubject of \Cake\Cache\CacheEngine + * @template TSubject of object * @implements \Cake\Event\EventDispatcherInterface */ abstract class CacheEngine implements CacheInterface, CacheEngineInterface, EventDispatcherInterface diff --git a/src/Cache/CacheRegistry.php b/src/Cache/CacheRegistry.php index 0eef813e312..e8aa83c4236 100644 --- a/src/Cache/CacheRegistry.php +++ b/src/Cache/CacheRegistry.php @@ -26,7 +26,7 @@ * * Used by {@link \Cake\Cache\Cache} to load and manage cache engines. * - * @template TEngine of \Cake\Cache\CacheEngine + * @template TEngine of \Cake\Cache\CacheEngine * @extends \Cake\Core\ObjectRegistry */ class CacheRegistry extends ObjectRegistry diff --git a/src/Command/Command.php b/src/Command/Command.php index 546efc313bd..6e75a4e59e8 100644 --- a/src/Command/Command.php +++ b/src/Command/Command.php @@ -28,6 +28,8 @@ * * Includes traits that integrate logging * and ORM models to console commands. + * + * @extends \Cake\Console\BaseCommand<\Cake\Command\Command> */ class Command extends BaseCommand { diff --git a/src/Console/BaseCommand.php b/src/Console/BaseCommand.php index a4edaa3066b..a15a8e3a25b 100644 --- a/src/Console/BaseCommand.php +++ b/src/Console/BaseCommand.php @@ -45,7 +45,7 @@ * - `afterExecute(EventInterface $event)` * Called immediately after the command's run method, unless an exception occurs. * - * @template TSubject of \Cake\Command\Command + * @template TSubject of \Cake\Console\BaseCommand * @implements \Cake\Event\EventDispatcherInterface */ abstract class BaseCommand implements CommandInterface, EventDispatcherInterface, EventListenerInterface @@ -198,7 +198,7 @@ public function implementedEvents(): array * Called immediately prior to the command's run method. You can use this method to configure and customize the * command or perform logic that needs to happen before the command runs. * - * @param \Cake\Event\EventInterface<\Cake\Console\BaseCommand> $event An Event instance + * @param \Cake\Event\EventInterface $event An Event instance * @param \Cake\Console\Arguments $args * @param \Cake\Console\ConsoleIo $io * @return void @@ -212,7 +212,7 @@ public function beforeExecute(EventInterface $event, Arguments $args, ConsoleIo * Called immediately after the command's run method, unless an exception occurs. You can use this method to * perform logic that needs to happen after the command runs. * - * @param \Cake\Event\EventInterface<\Cake\Console\BaseCommand> $event An Event instance + * @param \Cake\Event\EventInterface $event An Event instance * @param \Cake\Console\Arguments $args * @param \Cake\Console\ConsoleIo $io * @param int|null $result diff --git a/src/Console/Command/HelpCommand.php b/src/Console/Command/HelpCommand.php index 2689d9c6987..17d8cc0a5ba 100644 --- a/src/Console/Command/HelpCommand.php +++ b/src/Console/Command/HelpCommand.php @@ -32,6 +32,8 @@ /** * Print out command list + * + * @extends \Cake\Console\BaseCommand<\Cake\Console\Command\HelpCommand> */ class HelpCommand extends BaseCommand implements CommandCollectionAwareInterface { diff --git a/src/Controller/Component.php b/src/Controller/Component.php index 695706b1dd0..9cfdf716a95 100644 --- a/src/Controller/Component.php +++ b/src/Controller/Component.php @@ -66,7 +66,7 @@ class Component implements EventListenerInterface /** * Component registry class used to lazy load components. * - * @var \Cake\Controller\ComponentRegistry + * @var \Cake\Controller\ComponentRegistry<\Cake\Controller\Controller> */ protected ComponentRegistry $_registry; @@ -96,7 +96,7 @@ class Component implements EventListenerInterface /** * Constructor * - * @param \Cake\Controller\ComponentRegistry $registry A component registry + * @param \Cake\Controller\ComponentRegistry<\Cake\Controller\Controller> $registry A component registry * this component can use to lazy load its components. * @param array $config Array of configuration settings. */ diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php index 07253d5ae8f..66548ac96f4 100644 --- a/src/Controller/Controller.php +++ b/src/Controller/Controller.php @@ -161,7 +161,7 @@ class Controller implements EventListenerInterface, EventDispatcherInterface /** * Instance of ComponentRegistry used to create Components * - * @var \Cake\Controller\ComponentRegistry|null + * @var \Cake\Controller\ComponentRegistry<\Cake\Controller\Controller>|null */ protected ?ComponentRegistry $_components = null; @@ -197,7 +197,7 @@ class Controller implements EventListenerInterface, EventDispatcherInterface * but expect that features that use the request parameters will not work. * @param string|null $name Override the name useful in testing when using mocks. * @param \Cake\Event\EventManagerInterface|null $eventManager The event manager. Defaults to a new instance. - * @param \Cake\Controller\ComponentRegistry|null $components ComponentRegistry to use. Defaults to a new instance. + * @param \Cake\Controller\ComponentRegistry<\Cake\Controller\Controller>|null $components ComponentRegistry to use. Defaults to a new instance. */ public function __construct( ServerRequest $request, @@ -255,7 +255,7 @@ public function initialize(): void /** * Get the component registry for this controller. * - * @return \Cake\Controller\ComponentRegistry + * @return \Cake\Controller\ComponentRegistry<\Cake\Controller\Controller> */ public function components(): ComponentRegistry { @@ -855,7 +855,7 @@ public function referer(array|string|null $default = '/', bool $local = true): s * @param \Cake\Datasource\RepositoryInterface|\Cake\Datasource\QueryInterface|string|null $object Table to paginate * (e.g: Table instance, 'TableName' or a Query object) * @param array $settings The settings/configuration used for pagination. See {@link \Cake\Controller\Controller::$paginate}. - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface * @link https://book.cakephp.org/5/en/controllers.html#paginating-a-model * @throws \Cake\Http\Exception\NotFoundException When a page out of bounds is requested. */ diff --git a/src/Core/BasePlugin.php b/src/Core/BasePlugin.php index 67b55680710..98092892ea7 100644 --- a/src/Core/BasePlugin.php +++ b/src/Core/BasePlugin.php @@ -276,6 +276,8 @@ public function routes(RouteBuilder $routes): void /** * @inheritDoc + * + * @param \Cake\Core\PluginApplicationInterface $app The host application */ public function bootstrap(PluginApplicationInterface $app): void { diff --git a/src/Core/PluginInterface.php b/src/Core/PluginInterface.php index 768d4f38067..56c6a9266e8 100644 --- a/src/Core/PluginInterface.php +++ b/src/Core/PluginInterface.php @@ -76,7 +76,7 @@ public function getTemplatePath(): string; * The host application is provided as an argument. This allows you to load additional * plugin dependencies, or attach events. * - * @param \Cake\Core\PluginApplicationInterface $app The host application + * @param \Cake\Core\PluginApplicationInterface $app The host application * @return void */ public function bootstrap(PluginApplicationInterface $app): void; diff --git a/src/Database/Query.php b/src/Database/Query.php index 127ea984bfc..f933ca0f0a0 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -693,7 +693,7 @@ public function removeJoin(string $name) * * See `join()` for further details on conditions and types. * - * @param array|string $table The table to join with + * @param array>|string $table The table to join with * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions * to use for joining. * @param array $types a list of types associated to the conditions used for converting @@ -718,7 +718,7 @@ public function leftJoin( * The arguments of this method are identical to the `leftJoin()` shorthand, please refer * to that methods description for further details. * - * @param array|string $table The table to join with + * @param array>|string $table The table to join with * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions * to use for joining. * @param array $types a list of types associated to the conditions used for converting @@ -743,7 +743,7 @@ public function rightJoin( * The arguments of this method are identical to the `leftJoin()` shorthand, please refer * to that method's description for further details. * - * @param array|string $table The table to join with + * @param array>|string $table The table to join with * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions * to use for joining. * @param array $types a list of types associated to the conditions used for converting @@ -763,11 +763,11 @@ public function innerJoin( /** * Returns an array that can be passed to the join method describing a single join clause * - * @param array|string $table The table to join with + * @param array>|string $table The table to join with * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions * to use for joining. * @param string $type the join type to use - * @return array + * @return array, conditions: \Cake\Database\ExpressionInterface|\Closure|array|string, type: string}> */ protected function _makeJoin( array|string $table, diff --git a/src/Database/Query/QueryFactory.php b/src/Database/Query/QueryFactory.php index 90a4346badc..64514bec315 100644 --- a/src/Database/Query/QueryFactory.php +++ b/src/Database/Query/QueryFactory.php @@ -41,7 +41,7 @@ public function __construct( * @param \Cake\Database\ExpressionInterface|\Closure|array|string|float|int $fields Fields/columns list for the query. * @param array|string $table List of tables to query. * @param array $types Associative array containing the types to be used for casting. - * @return \Cake\Database\Query\SelectQuery + * @return \Cake\Database\Query\SelectQuery */ public function select( ExpressionInterface|Closure|array|string|float|int $fields = [], diff --git a/src/Datasource/FactoryLocator.php b/src/Datasource/FactoryLocator.php index 1d7d67cffaa..317bb98e734 100644 --- a/src/Datasource/FactoryLocator.php +++ b/src/Datasource/FactoryLocator.php @@ -27,7 +27,7 @@ class FactoryLocator /** * A list of model factory functions. * - * @var array + * @var array> */ protected static array $_modelFactories = []; @@ -35,7 +35,7 @@ class FactoryLocator * Register a locator to return repositories of a given type. * * @param string $type The name of the repository type the factory function is for. - * @param \Cake\Datasource\Locator\LocatorInterface $factory The factory function used to create instances. + * @param \Cake\Datasource\Locator\LocatorInterface<\Cake\Datasource\RepositoryInterface> $factory The factory function used to create instances. * @return void */ public static function add(string $type, LocatorInterface $factory): void @@ -59,7 +59,7 @@ public static function drop(string $type): void * * @param string $type The repository type to get the factory for. * @throws \InvalidArgumentException If the specified repository type has no factory. - * @return \Cake\Datasource\Locator\LocatorInterface The factory for the repository type. + * @return \Cake\Datasource\Locator\LocatorInterface<\Cake\Datasource\RepositoryInterface> The factory for the repository type. */ public static function get(string $type): LocatorInterface { diff --git a/src/Datasource/Paging/NumericPaginator.php b/src/Datasource/Paging/NumericPaginator.php index 3276131b3d8..66b4a6c08cc 100644 --- a/src/Datasource/Paging/NumericPaginator.php +++ b/src/Datasource/Paging/NumericPaginator.php @@ -221,7 +221,7 @@ class NumericPaginator implements PaginatorInterface * to paginate. * @param array $params Request params * @param array $settings The settings/configuration used for pagination. - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface * @throws \Cake\Datasource\Paging\Exception\PageOutOfBoundsException */ public function paginate( @@ -266,9 +266,9 @@ public function paginate( /** * Build paginated result set. * - * @param \Cake\Datasource\ResultSetInterface $items + * @param \Cake\Datasource\ResultSetInterface $items * @param array $pagingParams - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface */ protected function buildPaginated(ResultSetInterface $items, array $pagingParams): PaginatedInterface { @@ -314,7 +314,7 @@ protected function getQuery(RepositoryInterface $object, ?QueryInterface $query, * * @param \Cake\Datasource\QueryInterface $query Query to fetch items. * @param array $data Paging data. - * @return \Cake\Datasource\ResultSetInterface + * @return \Cake\Datasource\ResultSetInterface */ protected function getItems(QueryInterface $query, array $data): ResultSetInterface { diff --git a/src/Datasource/Paging/PaginatorInterface.php b/src/Datasource/Paging/PaginatorInterface.php index 96e7678d719..ec17ade2c2f 100644 --- a/src/Datasource/Paging/PaginatorInterface.php +++ b/src/Datasource/Paging/PaginatorInterface.php @@ -27,7 +27,7 @@ interface PaginatorInterface * @param mixed $target Anything that needs to be paginated. * @param array $params Request params. * @param array $settings The settings/configuration used for pagination. - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface */ public function paginate( mixed $target, diff --git a/src/Datasource/Paging/SimplePaginator.php b/src/Datasource/Paging/SimplePaginator.php index b929fd7bbb4..078c0f6d3d7 100644 --- a/src/Datasource/Paging/SimplePaginator.php +++ b/src/Datasource/Paging/SimplePaginator.php @@ -35,7 +35,7 @@ class SimplePaginator extends NumericPaginator * * @param \Cake\Datasource\QueryInterface $query Query to fetch items. * @param array $data Paging data. - * @return \Cake\Datasource\ResultSetInterface + * @return \Cake\Datasource\ResultSetInterface */ protected function getItems(QueryInterface $query, array $data): ResultSetInterface { @@ -66,9 +66,9 @@ protected function buildParams(array $data): array * Since the query fetches an extra record, drop the last record if records * fetched exceeds the limit/per page. * - * @param \Cake\Datasource\ResultSetInterface $items + * @param \Cake\Datasource\ResultSetInterface $items * @param array $pagingParams - * @return \Cake\Datasource\Paging\PaginatedInterface + * @return \Cake\Datasource\Paging\PaginatedInterface */ protected function buildPaginated(ResultSetInterface $items, array $pagingParams): PaginatedInterface { diff --git a/src/Event/EventDispatcherTrait.php b/src/Event/EventDispatcherTrait.php index 3dec97029f9..0856b75eddb 100644 --- a/src/Event/EventDispatcherTrait.php +++ b/src/Event/EventDispatcherTrait.php @@ -78,12 +78,16 @@ public function setEventManager(EventManagerInterface $eventManager) * @param TSubject|null $subject The object that this event applies to * ($this by default). * @return \Cake\Event\EventInterface + * @phpstan-ignore missingType.generics */ - public function dispatchEvent(string $name, array $data = [], ?object $subject = null): EventInterface + public function dispatchEvent(string $name, array $data = [], ?object $subject = null): EventInterface // @phpstan-ignore missingType.generics { $subject ??= $this; - /** @var \Cake\Event\EventInterface $event Coerce for psalm/phpstan */ + /** + * @var \Cake\Event\EventInterface $event Coerce for psalm/phpstan + * @phpstan-ignore missingType.generics (TSubject may itself be generic) + */ $event = new $this->_eventClass($name, $subject, $data); $this->getEventManager()->dispatch($event); diff --git a/src/Event/EventManager.php b/src/Event/EventManager.php index c47078f78ca..1c2c652cd02 100644 --- a/src/Event/EventManager.php +++ b/src/Event/EventManager.php @@ -61,7 +61,7 @@ class EventManager implements EventManagerInterface /** * The event list object. * - * @var \Cake\Event\EventList|null + * @var \Cake\Event\EventList|null */ protected ?EventList $_eventList = null; @@ -424,7 +424,7 @@ public function matchingListeners(string $eventKeyPattern): array /** * Returns the event list. * - * @return \Cake\Event\EventList|null + * @return \Cake\Event\EventList|null */ public function getEventList(): ?EventList { @@ -471,7 +471,7 @@ public function isTrackingEvents(): bool /** * Enables the listing of dispatched events. * - * @param \Cake\Event\EventList $eventList The event list object to use. + * @param \Cake\Event\EventList $eventList The event list object to use. * @return $this */ public function setEventList(EventList $eventList) diff --git a/src/Http/BaseApplication.php b/src/Http/BaseApplication.php index 589b89c8504..0a073bb0407 100644 --- a/src/Http/BaseApplication.php +++ b/src/Http/BaseApplication.php @@ -85,7 +85,7 @@ abstract class BaseApplication implements /** * Controller factory * - * @var \Cake\Http\ControllerFactoryInterface|null + * @var \Cake\Http\ControllerFactoryInterface<\Cake\Controller\Controller>|null */ protected ?ControllerFactoryInterface $controllerFactory = null; @@ -101,7 +101,7 @@ abstract class BaseApplication implements * * @param string $configDir The directory the bootstrap configuration is held in. * @param \Cake\Event\EventManagerInterface|null $eventManager Application event manager instance. - * @param \Cake\Http\ControllerFactoryInterface|null $controllerFactory Controller factory. + * @param \Cake\Http\ControllerFactoryInterface<\Cake\Controller\Controller>|null $controllerFactory Controller factory. */ public function __construct( string $configDir, diff --git a/src/Http/Middleware/BodyParserMiddleware.php b/src/Http/Middleware/BodyParserMiddleware.php index ff2954beda8..6d2ca272ac1 100644 --- a/src/Http/Middleware/BodyParserMiddleware.php +++ b/src/Http/Middleware/BodyParserMiddleware.php @@ -202,7 +202,7 @@ protected function decodeXml(string $body): array try { $xml = Xml::build($body, ['return' => 'domdocument', 'readFile' => false]); // We might not get child nodes if there are nested inline entities. - /** @var \DOMNodeList $domNodeList */ + /** @var \DOMNodeList<\DOMNode> $domNodeList */ $domNodeList = $xml->childNodes; if ((int)$domNodeList->length > 0) { return Xml::toArray($xml); diff --git a/src/ORM/Association.php b/src/ORM/Association.php index 8173440f328..de4cff12d0f 100644 --- a/src/ORM/Association.php +++ b/src/ORM/Association.php @@ -694,7 +694,7 @@ protected function _options(array $options): void * - negateMatch: Will append a condition to the passed query for excluding matches. * with this association. * - * @param \Cake\ORM\Query\SelectQuery $query the query to be altered to include the target table data + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query to be altered to include the target table data * @param array $options Any extra options or overrides to be taken into account * @return void * @throws \RuntimeException Unable to build the query or associations. @@ -773,7 +773,7 @@ public function attachTo(SelectQuery $query, array $options = []): void * Conditionally adds a condition to the passed Query that will make it find * records where there is no match with this association. * - * @param \Cake\ORM\Query\SelectQuery $query The query to modify + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query The query to modify * @param array $options Options array containing the `negateMatch` key. * @return void */ @@ -847,7 +847,7 @@ public function defaultRowValue(array $row, bool $joined): array * it will be interpreted as the `$args` parameter * @param mixed ...$args Arguments that match up to finder-specific parameters * @see \Cake\ORM\Table::find() - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> */ public function find(array|string|null $type = null, mixed ...$args): SelectQuery { @@ -933,7 +933,7 @@ public function requiresKeys(array $options = []): bool * Triggers `beforeFind` on the target table for the query this association is * attaching to * - * @param \Cake\ORM\Query\SelectQuery $query the query this association is attaching itself to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query this association is attaching itself to * @return void */ protected function _dispatchBeforeFind(SelectQuery $query): void @@ -945,8 +945,8 @@ protected function _dispatchBeforeFind(SelectQuery $query): void * Helper function used to conditionally append fields to the select clause of * a query from the fields found in another query object. * - * @param \Cake\ORM\Query\SelectQuery $query the query that will get the fields appended to - * @param \Cake\ORM\Query\SelectQuery $surrogate the query having the fields to be copied from + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the fields appended to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having the fields to be copied from * @param array $options options passed to the method `attachTo` * @return void */ @@ -1004,8 +1004,8 @@ protected function _appendFields(SelectQuery $query, SelectQuery $surrogate, arr * applying the surrogate formatters to only the property corresponding to * such a table. * - * @param \Cake\ORM\Query\SelectQuery $query the query that will get the formatter applied to - * @param \Cake\ORM\Query\SelectQuery $surrogate the query having formatters for the associated + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the formatter applied to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having formatters for the associated * target table. * @param array $options options passed to the method `attachTo` * @return void @@ -1065,8 +1065,8 @@ function (CollectionInterface $results, SelectQuery $query) use ($formatters, $p * passed `$query`. Containments are altered so that they respect the association * chain from which they originated. * - * @param \Cake\ORM\Query\SelectQuery $query the query that will get the associations attached to - * @param \Cake\ORM\Query\SelectQuery $surrogate the query having the containments to be attached + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the associations attached to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having the containments to be attached * @param array $options options passed to the method `attachTo` * @return void */ diff --git a/src/ORM/Association/BelongsToMany.php b/src/ORM/Association/BelongsToMany.php index ff69185cdc4..20d7683eb68 100644 --- a/src/ORM/Association/BelongsToMany.php +++ b/src/ORM/Association/BelongsToMany.php @@ -463,7 +463,7 @@ protected function _generateJunctionAssociations(Table $junction, Table $source, * - fields: a list of fields in the target table to include in the result * - type: The type of join to be used (e.g. INNER) * - * @param \Cake\ORM\Query\SelectQuery $query the query to be altered to include the target table data + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query to be altered to include the target table data * @param array $options Any extra options or overrides to be taken in account * @return void */ @@ -503,7 +503,9 @@ public function attachTo(SelectQuery $query, array $options = []): void } /** - * @inheritDoc + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to append to. + * @param array $options The options for not matching. + * @return void */ protected function _appendNotMatching(SelectQuery $query, array $options): void { @@ -521,7 +523,7 @@ protected function _appendNotMatching(SelectQuery $query, array $options): void if (!empty($options['queryBuilder'])) { assert(is_callable($options['queryBuilder'])); - /** @var \Cake\ORM\Query\SelectQuery $subquery */ + /** @var \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $subquery */ $subquery = $options['queryBuilder']($subquery); } @@ -1099,7 +1101,7 @@ protected function junctionConditions(): array * it will be interpreted as the `$options` parameter * @param mixed ...$args Arguments that match up to finder-specific parameters * @see \Cake\ORM\Table::find() - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function find(array|string|null $type = null, mixed ...$args): SelectQuery { @@ -1123,9 +1125,9 @@ public function find(array|string|null $type = null, mixed ...$args): SelectQuer /** * Append a join to the junction table. * - * @param \Cake\ORM\Query\SelectQuery $query The query to append. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to append. * @param array|null $conditions The query conditions to use. - * @return \Cake\ORM\Query\SelectQuery The modified query. + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> The modified query. */ protected function _appendJunctionJoin(SelectQuery $query, ?array $conditions = null): SelectQuery { @@ -1285,7 +1287,7 @@ function () use ($sourceEntity, $targetEntities, $primaryValue, $options) { * `$existing` and `$jointEntities`. This method will return the values from * `$targetEntities` that were not deleted from calculating the difference. * - * @param \Cake\ORM\Query\SelectQuery $existing a query for getting existing links + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $existing a query for getting existing links * @param array<\Cake\Datasource\EntityInterface> $jointEntities link entities that should be persisted * @param array $targetEntities entities in target table that are related to * the `$jointEntities` diff --git a/src/ORM/Association/Loader/SelectLoader.php b/src/ORM/Association/Loader/SelectLoader.php index 87e9a21b577..866e6ac7fbd 100644 --- a/src/ORM/Association/Loader/SelectLoader.php +++ b/src/ORM/Association/Loader/SelectLoader.php @@ -152,7 +152,7 @@ protected function _defaultOptions(): array * the source table * * @param array $options options accepted by eagerLoader() - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> * @throws \InvalidArgumentException When a key is required for associations but not selected. */ protected function _buildQuery(array $options): SelectQuery @@ -170,7 +170,7 @@ protected function _buildQuery(array $options): SelectQuery $query = $query->find($finderName, ...$opts); } - /** @var \Cake\ORM\Query\SelectQuery $selectQuery */ + /** @var \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $selectQuery */ $selectQuery = $options['query']; // Disable hydration for external queries when parent has DTO projection @@ -206,7 +206,7 @@ protected function _buildQuery(array $options): SelectQuery if (!empty($options['queryBuilder'])) { assert(is_callable($options['queryBuilder'])); - /** @var \Cake\ORM\Query\SelectQuery $fetchQuery */ + /** @var \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery */ $fetchQuery = $options['queryBuilder']($fetchQuery); } @@ -248,7 +248,7 @@ protected function _extractFinder(array|string $finderData): array * If the required fields are missing, automatically adds them to ensure * entities can be properly identified and loaded. * - * @param \Cake\ORM\Query\SelectQuery $fetchQuery The association fetching query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery The association fetching query * @param array $key The foreign key fields to check * @return void * @throws \InvalidArgumentException @@ -286,10 +286,10 @@ protected function _assertFieldsPresent(SelectQuery $fetchQuery, array $key): vo * target table query given a filter key and some filtering values when the * filtering needs to be done using a subquery. * - * @param \Cake\ORM\Query\SelectQuery $query Target table's query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Target table's query * @param array|string $key the fields that should be used for filtering - * @param \Cake\ORM\Query\SelectQuery $subquery The Subquery to use for filtering - * @return \Cake\ORM\Query\SelectQuery + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $subquery The Subquery to use for filtering + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ protected function _addFilteringJoin(SelectQuery $query, array|string $key, SelectQuery $subquery): SelectQuery { @@ -322,10 +322,10 @@ protected function _addFilteringJoin(SelectQuery $query, array|string $key, Sele * Appends any conditions required to load the relevant set of records in the * target table query given a filter key and some filtering values. * - * @param \Cake\ORM\Query\SelectQuery $query Target table's query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Target table's query * @param array|string $key The fields that should be used for filtering * @param mixed $filter The value that should be used to match for $key - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ protected function _addFilteringCondition(SelectQuery $query, array|string $key, mixed $filter): SelectQuery { @@ -342,7 +342,7 @@ protected function _addFilteringCondition(SelectQuery $query, array|string $key, * Returns a TupleComparison object that can be used for matching all the fields * from $keys with the tuple values in $filter using the provided operator. * - * @param \Cake\ORM\Query\SelectQuery $query Target table's query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Target table's query * @param array $keys the fields that should be used for filtering * @param mixed $filter the value that should be used to match for $key * @param string $operator The operator for comparing the tuples @@ -404,8 +404,8 @@ protected function _linkField(array $options): array|string * target table, it is constructed by cloning the original query that was used * to load records in the source table. * - * @param \Cake\ORM\Query\SelectQuery $query the original query used to load source records - * @return \Cake\ORM\Query\SelectQuery + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the original query used to load source records + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ protected function _buildSubquery(SelectQuery $query): SelectQuery { @@ -444,7 +444,7 @@ protected function _buildSubquery(SelectQuery $query): SelectQuery * those columns are also included as the fields may be calculated or constant values, * that need to be present to ensure the correct association data is loaded. * - * @param \Cake\ORM\Query\SelectQuery $query The query to get fields from. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to get fields from. * @return array The list of fields for the subquery. */ protected function _subqueryFields(SelectQuery $query): array @@ -477,7 +477,7 @@ protected function _subqueryFields(SelectQuery $query): array * Builds an array containing the results from fetchQuery indexed by * the foreignKey value corresponding to this association. * - * @param \Cake\ORM\Query\SelectQuery $fetchQuery The query to get results from + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery The query to get results from * @param array $options The options passed to the eager loader * @return array */ @@ -518,7 +518,7 @@ protected function _buildResultMap(SelectQuery $fetchQuery, array $options): arr * Returns a callable to be used for each row in a query result set * for injecting the eager loaded rows * - * @param \Cake\ORM\Query\SelectQuery $fetchQuery the Query used to fetch results + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery the Query used to fetch results * @param array $resultMap an array with the foreignKey as keys and * the corresponding target table results as value. * @param array $options The options passed to the eagerLoader method diff --git a/src/ORM/Association/Loader/SelectWithPivotLoader.php b/src/ORM/Association/Loader/SelectWithPivotLoader.php index 130eaf5a74b..cc64ad9541b 100644 --- a/src/ORM/Association/Loader/SelectWithPivotLoader.php +++ b/src/ORM/Association/Loader/SelectWithPivotLoader.php @@ -46,7 +46,7 @@ class SelectWithPivotLoader extends SelectLoader /** * The junction association instance * - * @var \Cake\ORM\Association\HasMany + * @var \Cake\ORM\Association\HasMany<\Cake\ORM\Table> */ protected HasMany $junctionAssoc; @@ -77,7 +77,7 @@ public function __construct(array $options) * This is used for eager loading records on the target table based on conditions. * * @param array $options options accepted by eagerLoader() - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> * @throws \InvalidArgumentException When a key is required for associations but not selected. */ protected function _buildQuery(array $options): SelectQuery @@ -95,7 +95,7 @@ protected function _buildQuery(array $options): SelectQuery $query = parent::_buildQuery($options); if ($queryBuilder) { - /** @var \Cake\ORM\Query\SelectQuery $query */ + /** @var \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query */ $query = $queryBuilder($query); } @@ -136,7 +136,9 @@ protected function _buildQuery(array $options): SelectQuery } /** - * @inheritDoc + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery The association fetching query + * @param array $key The foreign key fields to check + * @return void */ protected function _assertFieldsPresent(SelectQuery $fetchQuery, array $key): void { @@ -170,7 +172,7 @@ protected function _linkField(array $options): array|string * Builds an array containing the results from fetchQuery indexed by * the foreignKey value corresponding to this association. * - * @param \Cake\ORM\Query\SelectQuery $fetchQuery The query to get results from + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $fetchQuery The query to get results from * @param array $options The options passed to the eager loader * @return array * @throws \Cake\Database\Exception\DatabaseException when the association property is not part of the results set. diff --git a/src/ORM/Behavior/CounterCacheBehavior.php b/src/ORM/Behavior/CounterCacheBehavior.php index 67464821bcb..bdc9fffc3fb 100644 --- a/src/ORM/Behavior/CounterCacheBehavior.php +++ b/src/ORM/Behavior/CounterCacheBehavior.php @@ -213,7 +213,7 @@ public function updateCounterCache(?string $assocName = null, int $limit = 100, } foreach ($config as $assoc => $settings) { - /** @var \Cake\ORM\Association\BelongsTo $belongsTo */ + /** @var \Cake\ORM\Association\BelongsTo<\Cake\ORM\Table> $belongsTo */ $belongsTo = $this->_table->getAssociation($assoc); foreach ($settings as $field => $config) { @@ -235,7 +235,7 @@ public function updateCounterCache(?string $assocName = null, int $limit = 100, /** * Update counter cache for the given association. * - * @param \Cake\ORM\Association\BelongsTo $assoc The association object. + * @param \Cake\ORM\Association\BelongsTo<\Cake\ORM\Table> $assoc The association object. * @param string $field Counter cache field. * @param array $config Config array. * @param int $limit Limit. @@ -394,7 +394,7 @@ protected function _shouldUpdateCount(array $conditions): bool * * @param array $config The counter cache configuration for a single field * @param array $conditions Additional conditions given to the query - * @return \Cake\ORM\Query\SelectQuery|int The query to fetch the number of + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array>|int The query to fetch the number of * relations matching the given config and conditions or the number itself. */ protected function _getCount(array $config, array $conditions): SelectQuery|int diff --git a/src/ORM/Behavior/Translate/EavStrategy.php b/src/ORM/Behavior/Translate/EavStrategy.php index fe413db10fc..b55ac811905 100644 --- a/src/ORM/Behavior/Translate/EavStrategy.php +++ b/src/ORM/Behavior/Translate/EavStrategy.php @@ -167,7 +167,7 @@ protected function setupAssociations(): void * and adding a formatter to copy the values into the main table records. * * @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event The beforeFind event that was fired. - * @param \Cake\ORM\Query\SelectQuery $query Query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Query * @param \ArrayObject $options The options for the query * @return void */ @@ -361,9 +361,9 @@ public function translationField(string $field): string * Modifies the results from a table find in order to merge the translated fields * into each entity for a given locale. * - * @param \Cake\Collection\CollectionInterface $results Results to map. + * @param \Cake\Collection\CollectionInterface $results Results to map. * @param string $locale Locale string - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface */ protected function rowMapper(CollectionInterface $results, string $locale): CollectionInterface { @@ -410,8 +410,8 @@ protected function rowMapper(CollectionInterface $results, string $locale): Coll * Modifies the results from a table find in order to merge full translation * records into each entity under the `_translations` key. * - * @param \Cake\Collection\CollectionInterface $results Results to modify. - * @return \Cake\Collection\CollectionInterface + * @param \Cake\Collection\CollectionInterface $results Results to modify. + * @return \Cake\Collection\CollectionInterface */ public function groupTranslations(CollectionInterface $results): CollectionInterface { diff --git a/src/ORM/Behavior/Translate/ShadowTableStrategy.php b/src/ORM/Behavior/Translate/ShadowTableStrategy.php index 6edda9c2649..a135ff9b684 100644 --- a/src/ORM/Behavior/Translate/ShadowTableStrategy.php +++ b/src/ORM/Behavior/Translate/ShadowTableStrategy.php @@ -125,7 +125,7 @@ protected function setupAssociations(): void * and adding a formatter to copy the values into the main table records. * * @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event The beforeFind event that was fired. - * @param \Cake\ORM\Query\SelectQuery $query Query. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Query. * @param \ArrayObject $options The options for the query. * @return void */ @@ -213,7 +213,7 @@ protected function setupHasOneAssociation(string $locale, ArrayObject $options): * Only add translations for fields that are in the main table, always * add the locale field though. * - * @param \Cake\ORM\Query\SelectQuery $query The query to check. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to check. * @param array $config The config to use for adding fields. * @return bool Whether a join to the translation table is required. */ @@ -252,7 +252,7 @@ protected function addFieldsToQuery(SelectQuery $query, array $config): bool * prefixing fields with the appropriate table alias. This method currently * expects to receive an order clause only. * - * @param \Cake\ORM\Query\SelectQuery $query the query to check. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query to check. * @param string $name The clause name. * @param array $config The config to use for adding fields. * @return bool Whether a join to the translation table is required. @@ -298,7 +298,7 @@ function ($c, &$field) use ($fields, $alias, $mainTableAlias, $mainTableFields, * prefixing fields with the appropriate table alias. This method currently * expects to receive a where clause only. * - * @param \Cake\ORM\Query\SelectQuery $query the query to check. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query to check. * @param string $name The clause name. * @param array $config The config to use for adding fields. * @return bool Whether a join to the translation table is required. @@ -480,9 +480,9 @@ public function translationField(string $field): string * Modifies the results from a table find in order to merge the translated * fields into each entity for a given locale. * - * @param \Cake\Collection\CollectionInterface $results Results to map. + * @param \Cake\Collection\CollectionInterface $results Results to map. * @param string $locale Locale string - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface */ protected function rowMapper(CollectionInterface $results, string $locale): CollectionInterface { @@ -549,8 +549,8 @@ protected function rowMapper(CollectionInterface $results, string $locale): Coll * Modifies the results from a table find in order to merge full translation * records into each entity under the `_translations` key. * - * @param \Cake\Collection\CollectionInterface $results Results to modify. - * @return \Cake\Collection\CollectionInterface + * @param \Cake\Collection\CollectionInterface $results Results to modify. + * @return \Cake\Collection\CollectionInterface */ public function groupTranslations(CollectionInterface $results): CollectionInterface { diff --git a/src/ORM/Behavior/Translate/TranslateStrategyInterface.php b/src/ORM/Behavior/Translate/TranslateStrategyInterface.php index acce4d09733..aaf9aa4f516 100644 --- a/src/ORM/Behavior/Translate/TranslateStrategyInterface.php +++ b/src/ORM/Behavior/Translate/TranslateStrategyInterface.php @@ -81,7 +81,7 @@ public function translationField(string $field): string; * into each entity under the `_translations` key * * @param \Cake\Datasource\ResultSetInterface $results Results to modify. - * @return \Cake\Collection\CollectionInterface + * @return \Cake\Collection\CollectionInterface */ public function groupTranslations(ResultSetInterface $results): CollectionInterface; @@ -91,7 +91,7 @@ public function groupTranslations(ResultSetInterface $results): CollectionInterf * and adding a formatter to copy the values into the main table records. * * @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event The beforeFind event that was fired. - * @param \Cake\ORM\Query\SelectQuery $query Query + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Query * @param \ArrayObject $options The options for the query * @return void */ diff --git a/src/ORM/Behavior/TranslateBehavior.php b/src/ORM/Behavior/TranslateBehavior.php index 1a574be7786..5afaed30eea 100644 --- a/src/ORM/Behavior/TranslateBehavior.php +++ b/src/ORM/Behavior/TranslateBehavior.php @@ -223,9 +223,9 @@ public function implementedEvents(): array * This allows `_translations.{locale}.field_name` type naming even for the * default locale in forms. * - * @param \Cake\Event\EventInterface $event - * @param \ArrayObject $data - * @param \ArrayObject $options + * @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event The event that was fired. + * @param \ArrayObject $data The data being marshalled. + * @param \ArrayObject $options The options for marshalling. * @return void */ public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options): void @@ -338,9 +338,9 @@ public function translationField(string $field): string * If the `locales` array is not passed, it will bring all translations found * for each record. * - * @param \Cake\ORM\Query\SelectQuery $query The original query to modify + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The original query to modify * @param array $locales A list of locales or options with the `locales` key defined - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function findTranslations(SelectQuery $query, array $locales = []): SelectQuery { diff --git a/src/ORM/Behavior/TreeBehavior.php b/src/ORM/Behavior/TreeBehavior.php index b466ef1310a..8c6e9bf604d 100644 --- a/src/ORM/Behavior/TreeBehavior.php +++ b/src/ORM/Behavior/TreeBehavior.php @@ -384,9 +384,9 @@ function (QueryExpression $exp) use ($config) { * to a specific node in the tree. This custom finder requires that the key 'for' * is passed in the options containing the id of the node to get its path for. * - * @param \Cake\ORM\Query\SelectQuery $query The constructed query to modify + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The constructed query to modify * @param string|int $for The path to find or an array of options with `for`. - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> * @throws \InvalidArgumentException If the 'for' key is missing in options */ public function findPath(SelectQuery $query, string|int $for): SelectQuery @@ -437,10 +437,10 @@ public function childCount(EntityInterface $node, bool $direct = false): int * If the direct option is set to true, only the direct children are returned * (based upon the parent_id field). * - * @param \Cake\ORM\Query\SelectQuery $query Query. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Query. * @param string|int $for The id of the record to read. Can also be an array of options. * @param bool $direct Whether to return only the direct (true) or all children (false). - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> * @throws \InvalidArgumentException When the 'for' key is not passed in $options */ public function findChildren(SelectQuery $query, int|string $for, bool $direct = false): SelectQuery @@ -473,13 +473,13 @@ public function findChildren(SelectQuery $query, int|string $for, bool $direct = * the primary key for the table and the values are the display field for the table. * Values are prefixed to visually indicate relative depth in the tree. * - * @param \Cake\ORM\Query\SelectQuery $query Query. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query Query. * @param \Closure|string|null $keyPath A dot separated path to fetch the field to use for the array key, or a closure to * return the key out of the provided row. * @param \Closure|string|null $valuePath A dot separated path to fetch the field to use for the array value, or a closure to * return the value out of the provided row. * @param string|null $spacer A string to be used as prefix for denoting the depth in the tree for each item. - * @return \Cake\ORM\Query\SelectQuery + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function findTreeList( SelectQuery $query, @@ -500,13 +500,13 @@ public function findTreeList( * and the values are the display field for the table. Values are prefixed to visually * indicate relative depth in the tree. * - * @param \Cake\ORM\Query\SelectQuery $query The query object to format. + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query object to format. * @param \Closure|string|null $keyPath A dot separated path to the field that will be the result array key, or a closure to * return the key from the provided row. * @param \Closure|string|null $valuePath A dot separated path to the field that is the array's value, or a closure to * return the value from the provided row. * @param string|null $spacer A string to be used as prefix for denoting the depth in the tree for each item. - * @return \Cake\ORM\Query\SelectQuery Augmented query. + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> Augmented query. */ public function formatTreeList( SelectQuery $query, diff --git a/src/Utility/Hash.php b/src/Utility/Hash.php index 865f45a5a6c..4c66095abe2 100644 --- a/src/Utility/Hash.php +++ b/src/Utility/Hash.php @@ -432,6 +432,7 @@ public static function remove(ArrayAccess|array $data, string $path): ArrayAcces foreach ($data as $k => $v) { $match = static::_matchToken($k, $token); if ($match && (is_array($v) || $v instanceof ArrayAccess)) { + /** @var \ArrayAccess|array $v */ if ($conditions) { if (static::_matches($v, $conditions)) { if ($nextPath !== '') { diff --git a/src/View/CellTrait.php b/src/View/CellTrait.php index b774a2d3270..4c3f9c315c3 100644 --- a/src/View/CellTrait.php +++ b/src/View/CellTrait.php @@ -55,6 +55,7 @@ trait CellTrait * @param array $options Options for Cell's constructor * @return \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> The cell instance * @throws \Cake\View\Exception\MissingCellException If Cell class was not found. + * @phpstan-ignore missingType.generics (self-referential generic) */ protected function cell(string $cell, array $data = [], array $options = []): Cell { @@ -86,6 +87,7 @@ protected function cell(string $cell, array $data = [], array $options = []): Ce * @param string|null $plugin The plugin name. * @param array $options The constructor options for the cell. * @return \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> + * @phpstan-ignore missingType.generics (self-referential generic) */ protected function _createCell(string $className, string $action, ?string $plugin, array $options): Cell { @@ -93,7 +95,7 @@ protected function _createCell(string $className, string $action, ?string $plugi $options['plugin'] = $plugin; } - /** @var \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> $instance */ + /** @var \Cake\View\Cell<\Cake\View\View<\Cake\View\View>> $instance @phpstan-ignore missingType.generics */ $instance = new $className($this->request, $this->response, $this->getEventManager(), $options); $builder = $instance->viewBuilder(); diff --git a/src/View/Helper.php b/src/View/Helper.php index 3cf6508ed21..400a0f3faed 100644 --- a/src/View/Helper.php +++ b/src/View/Helper.php @@ -63,7 +63,8 @@ class Helper implements EventListenerInterface /** * Loaded helper instances. * - * @var array> + * @var array> + * @phpstan-ignore missingType.generics (self-referential generic) */ protected array $helperInstances = []; @@ -96,7 +97,8 @@ public function __construct(View $view, array $config = []) * Lazy loads helpers. * * @param string $name Name of the property being accessed. - * @return \Cake\View\Helper|null Helper instance if helper with provided name exists + * @return \Cake\View\Helper<\Cake\View\View>|null Helper instance if helper with provided name exists + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __get(string $name): ?Helper { diff --git a/src/View/Helper/FormHelper.php b/src/View/Helper/FormHelper.php index 24c44e2fc3a..9dff07679e4 100644 --- a/src/View/Helper/FormHelper.php +++ b/src/View/Helper/FormHelper.php @@ -286,6 +286,7 @@ class FormHelper extends Helper * * @param \Cake\View\View<\Cake\View\View> $view The View this helper is being attached to. * @param array $config Configuration settings for the helper. + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __construct(View $view, array $config = []) { diff --git a/src/View/Helper/PaginatorHelper.php b/src/View/Helper/PaginatorHelper.php index a36da0cf481..713b6c86e38 100644 --- a/src/View/Helper/PaginatorHelper.php +++ b/src/View/Helper/PaginatorHelper.php @@ -110,6 +110,7 @@ class PaginatorHelper extends Helper * * @param \Cake\View\View<\Cake\View\View> $view The View this helper is being attached to. * @param array $config Configuration settings for the helper. + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __construct(View $view, array $config = []) { diff --git a/src/View/HelperRegistry.php b/src/View/HelperRegistry.php index 8ccf4a97e91..685689a898e 100644 --- a/src/View/HelperRegistry.php +++ b/src/View/HelperRegistry.php @@ -151,8 +151,8 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * @param string $alias The alias of the loaded helper. * @param array $config An array of settings to use for the helper. * @return \Cake\View\Helper<\Cake\View\View> The constructed helper class. - * @phpstan-ignore missingType.generics (self-referential generic) */ + /** @phpstan-ignore-next-line missingType.generics */ protected function _create(object|string $class, string $alias, array $config): Helper { if (is_object($class)) { diff --git a/src/View/View.php b/src/View/View.php index 06a902de24f..1393ee24127 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -1114,6 +1114,7 @@ public function getCurrentType(): string * * @param string $name Name of the attribute to get. * @return \Cake\View\Helper<\Cake\View\View>|null + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __get(string $name): ?Helper { @@ -1247,10 +1248,11 @@ protected function addHelper(string $helper, array $config = []): void * @param array $config Settings for the helper * @return \Cake\View\Helper<\Cake\View\View> a constructed helper object. * @see \Cake\View\HelperRegistry::load() + * @phpstan-ignore missingType.generics (self-referential generic) */ public function loadHelper(string $name, array $config = []): Helper { - /** @var \Cake\View\Helper<\Cake\View\View> */ + /** @var \Cake\View\Helper<\Cake\View\View> @phpstan-ignore missingType.generics */ return $this->helpers()->load($name, $config); } diff --git a/src/View/ViewBuilder.php b/src/View/ViewBuilder.php index 3d4d65a6dcd..b290e123f0b 100644 --- a/src/View/ViewBuilder.php +++ b/src/View/ViewBuilder.php @@ -617,6 +617,7 @@ public function getClassName(): ?string * @param \Cake\Event\EventManagerInterface|null $events The event manager to use. * @return \Cake\View\View<\Cake\View\View> * @throws \Cake\View\Exception\MissingViewException + * @phpstan-ignore missingType.generics (self-referential generic) */ public function build( ?ServerRequest $request = null, @@ -648,7 +649,7 @@ public function build( ]; $data += $this->_options; - /** @var \Cake\View\View<\Cake\View\View> */ + /** @var \Cake\View\View<\Cake\View\View> @phpstan-ignore missingType.generics */ return new $className($request, $response, $events, $data); } diff --git a/src/View/ViewVarsTrait.php b/src/View/ViewVarsTrait.php index e17e781cf7a..00deb359e30 100644 --- a/src/View/ViewVarsTrait.php +++ b/src/View/ViewVarsTrait.php @@ -48,6 +48,7 @@ public function viewBuilder(): ViewBuilder * @param string|null $viewClass Optional namespaced class name of the View class to instantiate. * @return \Cake\View\View<\Cake\View\View> * @throws \Cake\View\Exception\MissingViewException If view class was not found. + * @phpstan-ignore missingType.generics (self-referential generic) */ public function createView(?string $viewClass = null): View { diff --git a/src/View/Widget/WidgetLocator.php b/src/View/Widget/WidgetLocator.php index 1299240937b..2e52b078db4 100644 --- a/src/View/Widget/WidgetLocator.php +++ b/src/View/Widget/WidgetLocator.php @@ -57,7 +57,8 @@ class WidgetLocator /** * View instance. * - * @var \Cake\View\View + * @var \Cake\View\View<\Cake\View\View> + * @phpstan-ignore missingType.generics (self-referential generic) */ protected View $_view; @@ -65,8 +66,9 @@ class WidgetLocator * Constructor * * @param \Cake\View\StringTemplate $templates Templates instance to use. - * @param \Cake\View\View $view The view instance to set as a widget. + * @param \Cake\View\View<\Cake\View\View> $view The view instance to set as a widget. * @param array $widgets See add() method for more information. + * @phpstan-ignore missingType.generics (self-referential generic) */ public function __construct(StringTemplate $templates, View $view, array $widgets = []) { From 0ee155360247c92cf163d840c01f67ef676a9eae Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 18:13:16 +0100 Subject: [PATCH 4/9] Fix PHPStan errors to make CI green - Add @phpstan-ignore comments for Collection return type mismatches - Add path-specific ignores for generics.interfaceConflict in TreeIterator/TreePrinter - Add path-specific ignores for argument.type covariance issues in Cache/ORM - Use consistent SelectQuery generic types in Association.php --- phpstan.neon.dist | 11 +++++++++++ src/Collection/CollectionTrait.php | 16 ++++++++++------ src/ORM/Association.php | 20 ++++++++++---------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 05808195395..59804d73894 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -19,6 +19,17 @@ parameters: - identifier: method.internalClass - identifier: new.internalClass - identifier: trait.unused + - + identifier: generics.interfaceConflict + paths: + - src/Collection/Iterator/TreeIterator.php + - src/Collection/Iterator/TreePrinter.php + - + identifier: argument.type + paths: + - src/Cache/Cache.php + - src/ORM/TableRegistry.php + - src/ORM/bootstrap.php - message: '#^Call to an undefined method PHPUnit\\Framework\\MockObject\\MockBuilder\\:\:addMethods\(\)\.$#' reportUnmatched: false diff --git a/src/Collection/CollectionTrait.php b/src/Collection/CollectionTrait.php index 31b84bdf777..6239a424bec 100644 --- a/src/Collection/CollectionTrait.php +++ b/src/Collection/CollectionTrait.php @@ -408,7 +408,7 @@ public function countBy(callable|string $path): CollectionInterface $mapper = fn($value, $key, MapReduce $mr) => $mr->emitIntermediate($value, $callback($value)); $reducer = fn($values, $key, MapReduce $mr) => $mr->emit(count($values), $key); - return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer)); + return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer)); // @phpstan-ignore return.type } /** @@ -438,7 +438,7 @@ public function shuffle(): CollectionInterface $items = $this->toList(); shuffle($items); - return $this->newCollection($items); + return $this->newCollection($items); // @phpstan-ignore return.type } /** @@ -447,7 +447,7 @@ public function shuffle(): CollectionInterface */ public function sample(int $length = 10): CollectionInterface { - return $this->newCollection(new LimitIterator($this->shuffle(), 0, $length)); + return $this->newCollection(new LimitIterator($this->shuffle(), 0, $length)); // @phpstan-ignore return.type } /** @@ -992,6 +992,7 @@ public function zipWith(iterable $items, $callback): CollectionInterface */ public function chunk(int $chunkSize): CollectionInterface { + // @phpstan-ignore return.type return $this->map(function ($v, $k, Iterator $iterator) use ($chunkSize) { $values = [$v]; for ($i = 1; $i < $chunkSize; $i++) { @@ -1012,6 +1013,7 @@ public function chunk(int $chunkSize): CollectionInterface */ public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface { + // @phpstan-ignore return.type return $this->map(function ($v, $k, Iterator $iterator) use ($chunkSize, $keepKeys) { $key = 0; if ($keepKeys) { @@ -1088,7 +1090,7 @@ public function unwrap(): Iterator public function cartesianProduct(?callable $operation = null, ?callable $filter = null): CollectionInterface { if ($this->isEmpty()) { - return $this->newCollection([]); + return $this->newCollection([]); // @phpstan-ignore return.type } $collectionArrays = []; @@ -1103,6 +1105,7 @@ public function cartesianProduct(?callable $operation = null, ?callable $filter throw new LogicException('Cannot find the cartesian product of a multidimensional array'); } + /** @phpstan-ignore argument.type (cartesianProduct requires array values) */ $collectionArraysKeys[] = array_keys($value); $collectionArraysCounts[] = $valueCount; $collectionArrays[] = $value; @@ -1136,7 +1139,7 @@ public function cartesianProduct(?callable $operation = null, ?callable $filter } } - return $this->newCollection($result); + return $this->newCollection($result); // @phpstan-ignore return.type } /** @@ -1152,6 +1155,7 @@ public function transpose(): CollectionInterface $length = count(current($arrayValue)); $result = []; foreach ($arrayValue as $row) { + /** @phpstan-ignore argument.type (transpose requires array values) */ if (count($row) !== $length) { throw new LogicException('Child arrays do not have even length'); } @@ -1161,7 +1165,7 @@ public function transpose(): CollectionInterface $result[] = array_column($arrayValue, $column); } - return $this->newCollection($result); + return $this->newCollection($result); // @phpstan-ignore return.type } /** diff --git a/src/ORM/Association.php b/src/ORM/Association.php index de4cff12d0f..edb540ad2ee 100644 --- a/src/ORM/Association.php +++ b/src/ORM/Association.php @@ -694,7 +694,7 @@ protected function _options(array $options): void * - negateMatch: Will append a condition to the passed query for excluding matches. * with this association. * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query to be altered to include the target table data + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query to be altered to include the target table data * @param array $options Any extra options or overrides to be taken into account * @return void * @throws \RuntimeException Unable to build the query or associations. @@ -773,7 +773,7 @@ public function attachTo(SelectQuery $query, array $options = []): void * Conditionally adds a condition to the passed Query that will make it find * records where there is no match with this association. * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query The query to modify + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query The query to modify * @param array $options Options array containing the `negateMatch` key. * @return void */ @@ -847,7 +847,7 @@ public function defaultRowValue(array $row, bool $joined): array * it will be interpreted as the `$args` parameter * @param mixed ...$args Arguments that match up to finder-specific parameters * @see \Cake\ORM\Table::find() - * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> + * @return \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> */ public function find(array|string|null $type = null, mixed ...$args): SelectQuery { @@ -933,7 +933,7 @@ public function requiresKeys(array $options = []): bool * Triggers `beforeFind` on the target table for the query this association is * attaching to * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query this association is attaching itself to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query this association is attaching itself to * @return void */ protected function _dispatchBeforeFind(SelectQuery $query): void @@ -945,8 +945,8 @@ protected function _dispatchBeforeFind(SelectQuery $query): void * Helper function used to conditionally append fields to the select clause of * a query from the fields found in another query object. * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the fields appended to - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having the fields to be copied from + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query that will get the fields appended to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $surrogate the query having the fields to be copied from * @param array $options options passed to the method `attachTo` * @return void */ @@ -1004,8 +1004,8 @@ protected function _appendFields(SelectQuery $query, SelectQuery $surrogate, arr * applying the surrogate formatters to only the property corresponding to * such a table. * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the formatter applied to - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having formatters for the associated + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query that will get the formatter applied to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $surrogate the query having formatters for the associated * target table. * @param array $options options passed to the method `attachTo` * @return void @@ -1065,8 +1065,8 @@ function (CollectionInterface $results, SelectQuery $query) use ($formatters, $p * passed `$query`. Containments are altered so that they respect the association * chain from which they originated. * - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $query the query that will get the associations attached to - * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface> $surrogate the query having the containments to be attached + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $query the query that will get the associations attached to + * @param \Cake\ORM\Query\SelectQuery<\Cake\Datasource\EntityInterface|array> $surrogate the query having the containments to be attached * @param array $options options passed to the method `attachTo` * @return void */ From 3451aea457e3ad68ff8baa1da43b86616f53def3 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 18:26:06 +0100 Subject: [PATCH 5/9] Move argument.type ignores to inline comments - Cache.php: inline ignore for NullEngine fallback - TableRegistry.php: inline ignore for TableLocator - bootstrap.php: inline ignore for TableLocator generics.interfaceConflict must remain in config (PHPStan limitation for class-level interface conflicts) --- phpstan.neon.dist | 6 ------ src/Cache/Cache.php | 1 + src/ORM/TableRegistry.php | 1 + src/ORM/bootstrap.php | 1 + 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 59804d73894..c8e0d5af07a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -24,12 +24,6 @@ parameters: paths: - src/Collection/Iterator/TreeIterator.php - src/Collection/Iterator/TreePrinter.php - - - identifier: argument.type - paths: - - src/Cache/Cache.php - - src/ORM/TableRegistry.php - - src/ORM/bootstrap.php - message: '#^Call to an undefined method PHPUnit\\Framework\\MockObject\\MockBuilder\\:\:addMethods\(\)\.$#' reportUnmatched: false diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php index e1d001b8cfc..8c928bfd0e6 100644 --- a/src/Cache/Cache.php +++ b/src/Cache/Cache.php @@ -153,6 +153,7 @@ protected static function _buildEngine(string $name): void $registry->load($name, $config); } catch (RuntimeException $e) { if (!array_key_exists('fallback', $config)) { + // @phpstan-ignore argument.type (NullEngine is valid fallback) $registry->set($name, new NullEngine()); trigger_error($e->getMessage(), E_USER_WARNING); diff --git a/src/ORM/TableRegistry.php b/src/ORM/TableRegistry.php index 1c6671e1bdb..72c3885b948 100644 --- a/src/ORM/TableRegistry.php +++ b/src/ORM/TableRegistry.php @@ -71,6 +71,7 @@ public static function getTableLocator(): LocatorInterface */ public static function setTableLocator(LocatorInterface $tableLocator): void { + // @phpstan-ignore argument.type (Table locator implements RepositoryInterface) FactoryLocator::add('Table', $tableLocator); } } diff --git a/src/ORM/bootstrap.php b/src/ORM/bootstrap.php index 8b23a2d4e6a..7bc26d9af7b 100644 --- a/src/ORM/bootstrap.php +++ b/src/ORM/bootstrap.php @@ -18,4 +18,5 @@ use Cake\Datasource\FactoryLocator; use Cake\ORM\Locator\TableLocator; +// @phpstan-ignore argument.type (TableLocator implements RepositoryInterface) FactoryLocator::add('Table', new TableLocator()); From ddf81af6d542b41abc773737b336b6b26ef6b142 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 17 Jan 2026 18:40:49 +0100 Subject: [PATCH 6/9] Improve inline ignore comments wording --- src/ORM/TableRegistry.php | 2 +- src/ORM/bootstrap.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ORM/TableRegistry.php b/src/ORM/TableRegistry.php index 72c3885b948..81b26869ad3 100644 --- a/src/ORM/TableRegistry.php +++ b/src/ORM/TableRegistry.php @@ -71,7 +71,7 @@ public static function getTableLocator(): LocatorInterface */ public static function setTableLocator(LocatorInterface $tableLocator): void { - // @phpstan-ignore argument.type (Table locator implements RepositoryInterface) + // @phpstan-ignore argument.type (Table extends RepositoryInterface) FactoryLocator::add('Table', $tableLocator); } } diff --git a/src/ORM/bootstrap.php b/src/ORM/bootstrap.php index 7bc26d9af7b..0356a2c0ce9 100644 --- a/src/ORM/bootstrap.php +++ b/src/ORM/bootstrap.php @@ -18,5 +18,5 @@ use Cake\Datasource\FactoryLocator; use Cake\ORM\Locator\TableLocator; -// @phpstan-ignore argument.type (TableLocator implements RepositoryInterface) +// @phpstan-ignore argument.type (Table extends RepositoryInterface) FactoryLocator::add('Table', new TableLocator()); From f19506191d2487ff6a566bf0368e4e280c962312 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sun, 18 Jan 2026 05:18:17 +0100 Subject: [PATCH 7/9] Fix phpcs violations - Remove unused import EntityInterface from EagerLoader - Remove @inheritDoc when combined with @param/@return (coding standard violation) - Add proper type hints and @param annotations --- src/Collection/CollectionTrait.php | 36 +++--------------------------- src/Core/BasePlugin.php | 3 +-- src/ORM/EagerLoader.php | 1 - 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/Collection/CollectionTrait.php b/src/Collection/CollectionTrait.php index 6239a424bec..a42380c9917 100644 --- a/src/Collection/CollectionTrait.php +++ b/src/Collection/CollectionTrait.php @@ -81,7 +81,6 @@ public function each(callable $callback) } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function filter(?callable $callback = null): CollectionInterface @@ -92,7 +91,6 @@ public function filter(?callable $callback = null): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function reject(?callable $callback = null): CollectionInterface @@ -103,7 +101,6 @@ public function reject(?callable $callback = null): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function unique(?callable $callback = null): CollectionInterface @@ -177,7 +174,6 @@ public function contains(mixed $value): bool } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function map(callable $callback): CollectionInterface @@ -206,7 +202,6 @@ public function reduce(callable $callback, mixed $initial = null): mixed } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function extract(callable|string $path): CollectionInterface @@ -289,7 +284,6 @@ public function median(callable|string|null $path = null): float|int|null } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function sortBy(callable|string $path, int $order = SORT_DESC, int $sort = SORT_NUMERIC): CollectionInterface @@ -370,7 +364,6 @@ public function groupBy(callable|string $path, bool $preserveKeys = false): Coll } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function indexBy(callable|string $path): CollectionInterface @@ -398,7 +391,6 @@ public function indexBy(callable|string $path): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function countBy(callable|string $path): CollectionInterface @@ -430,7 +422,6 @@ public function sumOf(callable|string|null $path = null): float|int } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function shuffle(): CollectionInterface @@ -442,7 +433,6 @@ public function shuffle(): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function sample(int $length = 10): CollectionInterface @@ -451,7 +441,6 @@ public function sample(int $length = 10): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function take(int $length = 1, int $offset = 0): CollectionInterface @@ -460,7 +449,6 @@ public function take(int $length = 1, int $offset = 0): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function skip(int $length): CollectionInterface @@ -469,7 +457,6 @@ public function skip(int $length): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function match(array $conditions): CollectionInterface @@ -525,7 +512,6 @@ public function last(): mixed } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function takeLast(int $length): CollectionInterface @@ -625,7 +611,6 @@ public function takeLast(int $length): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function append(iterable $items): CollectionInterface @@ -638,7 +623,6 @@ public function append(iterable $items): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function appendItem(mixed $item, mixed $key = null): CollectionInterface @@ -653,7 +637,6 @@ public function appendItem(mixed $item, mixed $key = null): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function prepend(mixed $items): CollectionInterface @@ -662,7 +645,6 @@ public function prepend(mixed $items): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function prependItem(mixed $item, mixed $key = null): CollectionInterface @@ -677,7 +659,6 @@ public function prependItem(mixed $item, mixed $key = null): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function combine( @@ -749,7 +730,6 @@ public function combine( } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function nest( @@ -800,7 +780,6 @@ public function nest( } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function insert(string $path, mixed $values): CollectionInterface @@ -845,7 +824,6 @@ public function jsonSerialize(): array } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function compile(bool $keepKeys = true): CollectionInterface @@ -854,7 +832,6 @@ public function compile(bool $keepKeys = true): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function lazy(): CollectionInterface @@ -869,7 +846,6 @@ public function lazy(): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function buffered(): CollectionInterface @@ -878,7 +854,6 @@ public function buffered(): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function listNested( @@ -921,7 +896,6 @@ public function listNested( } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function stopWhen(callable|array $condition): CollectionInterface @@ -934,7 +908,6 @@ public function stopWhen(callable|array $condition): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function unfold(?callable $callback = null): CollectionInterface @@ -950,7 +923,6 @@ public function unfold(?callable $callback = null): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function through(callable $callback): CollectionInterface @@ -961,7 +933,6 @@ public function through(callable $callback): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface */ public function zip(iterable ...$items): CollectionInterface @@ -970,10 +941,11 @@ public function zip(iterable ...$items): CollectionInterface } /** - * @inheritDoc + * @param iterable $items Items to zip. + * @param callable $callback The callback to apply. * @return \Cake\Collection\CollectionInterface */ - public function zipWith(iterable $items, $callback): CollectionInterface + public function zipWith(iterable $items, mixed $callback): CollectionInterface { if (func_num_args() > 2) { $items = func_get_args(); @@ -987,7 +959,6 @@ public function zipWith(iterable $items, $callback): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface> */ public function chunk(int $chunkSize): CollectionInterface @@ -1008,7 +979,6 @@ public function chunk(int $chunkSize): CollectionInterface } /** - * @inheritDoc * @return \Cake\Collection\CollectionInterface> */ public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface diff --git a/src/Core/BasePlugin.php b/src/Core/BasePlugin.php index 98092892ea7..85a0abacda9 100644 --- a/src/Core/BasePlugin.php +++ b/src/Core/BasePlugin.php @@ -275,9 +275,8 @@ public function routes(RouteBuilder $routes): void } /** - * @inheritDoc - * * @param \Cake\Core\PluginApplicationInterface $app The host application + * @return void */ public function bootstrap(PluginApplicationInterface $app): void { diff --git a/src/ORM/EagerLoader.php b/src/ORM/EagerLoader.php index 8edfda6baf7..0cadc6dc864 100644 --- a/src/ORM/EagerLoader.php +++ b/src/ORM/EagerLoader.php @@ -16,7 +16,6 @@ */ namespace Cake\ORM; -use Cake\Datasource\EntityInterface; use Cake\ORM\Query\SelectQuery; use Closure; use InvalidArgumentException; From 77be5e6363c0d8a40e271167791c8aa33d75fb6c Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 3 Feb 2026 15:54:29 +0100 Subject: [PATCH 8/9] Trigger CI re-check after merge From a524e82dc0c22ae67e94a973872ad9f0c450d9bf Mon Sep 17 00:00:00 2001 From: mscherer Date: Sun, 22 Feb 2026 00:41:04 +0100 Subject: [PATCH 9/9] Fix PHPStan errors in ORM association cascade delete methods Add @phpstan-ignore for argument.type errors where cascade callback code iterates over query results. The SelectQuery template includes array type for non-hydrated results, but cascade callbacks always use hydration, so entities are guaranteed. --- src/ORM/Association/BelongsToMany.php | 1 + src/ORM/Association/DependentDeleteHelper.php | 1 + src/ORM/Association/HasMany.php | 1 + 3 files changed, 3 insertions(+) diff --git a/src/ORM/Association/BelongsToMany.php b/src/ORM/Association/BelongsToMany.php index 18290ce296f..3e01a681d47 100644 --- a/src/ORM/Association/BelongsToMany.php +++ b/src/ORM/Association/BelongsToMany.php @@ -620,6 +620,7 @@ public function cascadeDelete(EntityInterface $entity, array $options = []): boo $hasMany = $this->getSource()->getAssociation($table->getAlias()); if ($this->_cascadeCallbacks) { foreach ($hasMany->find('all')->where($conditions)->all()->toList() as $related) { + /** @phpstan-ignore argument.type (cascade callbacks always have hydration enabled) */ $success = $table->delete($related, $options); if (!$success) { return false; diff --git a/src/ORM/Association/DependentDeleteHelper.php b/src/ORM/Association/DependentDeleteHelper.php index d33dea0f9f3..3d72321026f 100644 --- a/src/ORM/Association/DependentDeleteHelper.php +++ b/src/ORM/Association/DependentDeleteHelper.php @@ -54,6 +54,7 @@ public function cascadeDelete(Association $association, EntityInterface $entity, if ($association->getCascadeCallbacks()) { foreach ($association->find()->where($conditions)->all()->toList() as $related) { + /** @phpstan-ignore argument.type (cascade callbacks always have hydration enabled) */ $success = $table->delete($related, $options); if (!$success) { return false; diff --git a/src/ORM/Association/HasMany.php b/src/ORM/Association/HasMany.php index c1d7675f19e..2f89b1c6c65 100644 --- a/src/ORM/Association/HasMany.php +++ b/src/ORM/Association/HasMany.php @@ -560,6 +560,7 @@ protected function _unlink(array $foreignKey, Table $target, array $conditions = }); $query = $this->find()->where($conditions); + /** @phpstan-ignore argument.type, argument.templateType (cascade callbacks always have hydration enabled) */ $return = $target->deleteMany($query->all(), $options); if ($return === false) { return false;