diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62630db5..df04d93d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,3 +82,6 @@ jobs: - name: Run PHP CodeSniffer run: vendor/bin/phpcs --report=checkstyle | cs2pr + + - name: Run PHPStan + run: vendor/bin/phpstan analyse -c phpstan.neon --error-format=checkstyle | cs2pr diff --git a/composer.json b/composer.json index 8179f397..8b10a1ac 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,11 @@ "mobiledetect/mobiledetectlib": "^4.8.03" }, "require-dev": { + "cakedc/cakephp-phpstan": "^4.0", "cakephp/bake": "^3.0.0", "cakephp/cakephp-codesniffer": "^5.0", "cakephp/debug_kit": "^5.0.0", + "dereuromark/cakephp-ide-helper": "dev-master", "josegonzalez/dotenv": "^4.0", "phpunit/phpunit": "^10.5.5 || ^11.1.3 || ^12.1" }, @@ -58,6 +60,10 @@ ], "cs-check": "phpcs --colors -p", "cs-fix": "phpcbf --colors -p", - "test": "phpunit --colors=always" + "test": "phpunit --colors=always", + "annotate": "bin/cake annotate all", + "illuminate": "bin/cake illuminate code", + "phpstan": "phpstan analyse", + "phpstan-baseline": "phpstan --generate-baseline" } } diff --git a/composer.lock b/composer.lock index ea318829..251d42d3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e5f4a98db5aff3fb593ad53b2b2adb53", + "content-hash": "b3630e9577c98cfef62a1adceda3fcb2", "packages": [ { "name": "admad/cakephp-social-auth", @@ -2354,6 +2354,63 @@ ], "time": "2026-01-06T22:56:00+00:00" }, + { + "name": "cakedc/cakephp-phpstan", + "version": "4.1.1", + "source": { + "type": "git", + "url": "https://github.com/CakeDC/cakephp-phpstan.git", + "reference": "4159d1c63ec5ea454835c66440d7f06a13b135a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CakeDC/cakephp-phpstan/zipball/4159d1c63ec5ea454835c66440d7f06a13b135a1", + "reference": "4159d1c63ec5ea454835c66440d7f06a13b135a1", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.0", + "php": ">=8.1.0", + "phpstan/phpstan": "^2.1.26" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^10.5 || ^11.5 || ^12.1" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "CakeDC\\PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakeDC", + "homepage": "https://www.cakedc.com", + "role": "Author" + } + ], + "description": "CakePHP plugin extension for PHPStan.", + "support": { + "issues": "https://github.com/CakeDC/cakephp-phpstan/issues", + "source": "https://github.com/CakeDC/cakephp-phpstan/tree/4.1.1" + }, + "time": "2025-11-13T13:34:51+00:00" + }, { "name": "cakephp/bake", "version": "3.6.3", @@ -3095,6 +3152,85 @@ ], "time": "2025-11-11T04:32:07+00:00" }, + { + "name": "dereuromark/cakephp-ide-helper", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/dereuromark/cakephp-ide-helper.git", + "reference": "316aad142793108ae0e154948c69512e8e4bc9d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dereuromark/cakephp-ide-helper/zipball/316aad142793108ae0e154948c69512e8e4bc9d5", + "reference": "316aad142793108ae0e154948c69512e8e4bc9d5", + "shasum": "" + }, + "require": { + "cakephp/bake": "^3.2.0", + "cakephp/cakephp": "^5.1.5", + "nikic/php-parser": "^5.7", + "php": ">=8.2", + "phpstan/phpdoc-parser": "^2.1.0", + "sebastian/diff": "^6.0 || ^7.0 || ^8.0", + "squizlabs/php_codesniffer": "^3.13 || ^4.0" + }, + "require-dev": { + "cakephp/migrations": "^4.5.1 || ^5.0", + "cakephp/plugin-installer": "^2.0.1", + "dereuromark/cakephp-shim": "^3.3.0", + "fig-r/psr2r-sniffer": "@stable", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^11.5 || ^12.1 || ^13.0" + }, + "default-branch": true, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "IdeHelper\\": "src/", + "IdeHelper\\Test\\Fixture\\": "tests/Fixture/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Scherer", + "homepage": "https://www.dereuromark.de", + "role": "Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/dereuromark/cakephp-ide-helper/graphs/contributors", + "role": "Developer" + } + ], + "description": "CakePHP IdeHelper Plugin to improve auto-completion", + "homepage": "https://github.com/dereuromark/cakephp-ide-helper/", + "keywords": [ + "annotations", + "autocomplete", + "cakephp", + "cli", + "dev", + "ide", + "phpdoc", + "phpstorm" + ], + "support": { + "issues": "https://github.com/dereuromark/cakephp-ide-helper/issues", + "source": "https://github.com/dereuromark/cakephp-ide-helper/" + }, + "funding": [ + { + "url": "https://github.com/dereuromark", + "type": "github" + } + ], + "time": "2026-04-07T11:31:42+00:00" + }, { "name": "doctrine/sql-formatter", "version": "1.5.4", @@ -3766,6 +3902,59 @@ }, "time": "2026-01-25T14:56:51+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.1.46", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a193923fc2d6325ef4e741cf3af8c3e8f54dbf25", + "reference": "a193923fc2d6325ef4e741cf3af8c3e8f54dbf25", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-04-01T09:25:14+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "12.5.3", @@ -4114,16 +4303,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.5.15", + "version": "12.5.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a" + "reference": "b2429f58ae75cae980b5bb9873abe4de6aac8b58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a", - "reference": "aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b2429f58ae75cae980b5bb9873abe4de6aac8b58", + "reference": "b2429f58ae75cae980b5bb9873abe4de6aac8b58", "shasum": "" }, "require": { @@ -4192,7 +4381,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.16" }, "funding": [ { @@ -4200,7 +4389,7 @@ "type": "other" } ], - "time": "2026-03-31T06:41:33+00:00" + "time": "2026-04-03T05:26:42+00:00" }, { "name": "react/promise", @@ -6875,7 +7064,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "dereuromark/cakephp-ide-helper": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/config/.env.ddev b/config/.env.ddev index 77c0323c..647bd438 100644 --- a/config/.env.ddev +++ b/config/.env.ddev @@ -36,5 +36,5 @@ export DATABASE_URL="mysql://db:db@db:3306/db" # Uncomment these to define logging configuration via environment variables. #export LOG_DEBUG_URL="file:///path/to/logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug" #export LOG_ERROR_URL="file:///path/to/logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error" -export DEBUG_KIT_SAFE_TLD="site" export APP_FULL_BASE_URL="https://plugins.cakephp.org.ddev.site" +export DEBUG_KIT_SAFE_TLD="site" diff --git a/config/app.php b/config/app.php index 36d8ba5a..766524a9 100644 --- a/config/app.php +++ b/config/app.php @@ -479,4 +479,11 @@ 'Migrations' => [ 'add_timestamps_use_datetime' => true, ], + + 'IdeHelper' => [ + 'tableBehaviors' => true, + 'arrayAsGenerics' => true, + 'objectAsGenerics' => true, + 'assocsAsGenerics' => true, + ], ]; diff --git a/config/plugins.php b/config/plugins.php index 82f147f2..17b70424 100644 --- a/config/plugins.php +++ b/config/plugins.php @@ -37,4 +37,5 @@ 'Tags', 'ADmad/SocialAuth', 'Authentication', + 'IdeHelper', ]; diff --git a/phpstan.neon b/phpstan.neon index fbe13926..261dc9d9 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,9 @@ +includes: + - vendor/cakedc/cakephp-phpstan/extension.neon + parameters: - level: 8 + level: 5 treatPhpDocTypesAsCertain: false - checkGenericClassInNonGenericObjectType: false bootstrapFiles: - config/bootstrap.php paths: diff --git a/src/Command/SyncPackagesCommand.php b/src/Command/SyncPackagesCommand.php index 377e88ca..31d002d6 100644 --- a/src/Command/SyncPackagesCommand.php +++ b/src/Command/SyncPackagesCommand.php @@ -127,6 +127,7 @@ public function execute(Arguments $args, ConsoleIo $io) } // Remove packages that were not touched + /** @var \Cake\ORM\ResultSet $toDeletePackages */ $toDeletePackages = $packagesTable->find()->where(['id NOT IN' => $touchedIds])->all(); foreach ($toDeletePackages as $package) { if (!$packagesTable->delete($package)) { @@ -241,7 +242,7 @@ private function hasExplicitCakePhpDependency(array $tags): bool * @param array $meta The meta array to adjust * @param string $packageConstraint The meta array which contains the current version strings * @param string $tagPrefix The prefix which should be used for the tag - * @param array> $versions The versions to check + * @param array> $versions The versions to check * @return array */ private function appendVersionTags( diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 2d90aa4a..a8ec2ddd 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -25,6 +25,8 @@ * will inherit them. * * @link https://book.cakephp.org/5/en/controllers.html#the-app-controller + * @property \Search\Controller\Component\SearchComponent $Search + * @property \Authentication\Controller\Component\AuthenticationComponent $Authentication */ class AppController extends Controller { diff --git a/src/Controller/ErrorController.php b/src/Controller/ErrorController.php index 6403b6e8..f4416c8c 100644 --- a/src/Controller/ErrorController.php +++ b/src/Controller/ErrorController.php @@ -25,6 +25,8 @@ */ class ErrorController extends AppController { + protected ?string $defaultTable = ''; + /** * Initialization hook method. * diff --git a/src/Controller/PackagesController.php b/src/Controller/PackagesController.php index d7962dd9..ec2acfc0 100644 --- a/src/Controller/PackagesController.php +++ b/src/Controller/PackagesController.php @@ -113,6 +113,7 @@ public function autocomplete(): Response ->withStringBody(json_encode([], JSON_THROW_ON_ERROR)); } + /** @var \Cake\ORM\ResultSet $packages */ $packages = $this->Packages ->find('autocomplete', search: $q) ->all(); @@ -174,8 +175,9 @@ protected function hasActiveFilterValue(mixed $value): bool } /** - * @param array $tags - * @return array + * @param array $tags + * @param string $prefix + * @return array */ protected function sortVersionTags(array $tags, string $prefix): array { diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php index eeebc564..0834c3b6 100644 --- a/src/Controller/PagesController.php +++ b/src/Controller/PagesController.php @@ -31,6 +31,8 @@ */ class PagesController extends AppController { + protected ?string $defaultTable = ''; + /** * @return void */ diff --git a/src/Event/AfterGithubIdentify.php b/src/Event/AfterGithubIdentify.php index 46b485df..a261818d 100644 --- a/src/Event/AfterGithubIdentify.php +++ b/src/Event/AfterGithubIdentify.php @@ -36,7 +36,7 @@ public function implementedEvents(): array */ public function afterIdentify(EventInterface $event, User $user): void { - $token = $user->social_profile->access_token?->getToken(); + $token = $user->social_profile->access_token->getToken(); if (!$token) { return; } diff --git a/src/Model/Entity/Package.php b/src/Model/Entity/Package.php index 0df2964a..d52098ac 100644 --- a/src/Model/Entity/Package.php +++ b/src/Model/Entity/Package.php @@ -17,12 +17,13 @@ * @property string|null $latest_stable_version * @property \Cake\I18n\Date|null $latest_stable_release_date * - * @property \Tags\Model\Entity\Tag[] $tags - * - * @property \Tags\Model\Entity\Tag[] $cake_php_tags + * @property array<\Tags\Model\Entity\Tag> $cake_php_tags * @property array> $cake_php_tag_groups - * @property \Tags\Model\Entity\Tag[] $php_tags + * @property array<\Tags\Model\Entity\Tag> $php_tags * @property array> $php_tag_groups + * @property array<\Tags\Model\Entity\Tagged> $tagged + * @property array<\Tags\Model\Entity\Tag> $tags + * @property \Tags\Model\Entity\Tagged $_joinData */ class Package extends Entity { @@ -42,6 +43,7 @@ class Package extends Entity /** * @return array<\Tags\Model\Entity\Tag> + * @see \App\Model\Entity\Package::$cake_php_tags */ protected function _getCakePhpTags(): array { @@ -50,6 +52,7 @@ protected function _getCakePhpTags(): array /** * @return array> + * @see \App\Model\Entity\Package::$cake_php_tag_groups */ protected function _getCakePhpTagGroups(): array { @@ -58,6 +61,7 @@ protected function _getCakePhpTagGroups(): array /** * @return array<\Tags\Model\Entity\Tag> + * @see \App\Model\Entity\Package::$php_tags */ protected function _getPhpTags(): array { @@ -66,6 +70,7 @@ protected function _getPhpTags(): array /** * @return array> + * @see \App\Model\Entity\Package::$php_tag_groups */ protected function _getPhpTagGroups(): array { @@ -98,12 +103,12 @@ protected function groupVersionTags(array $tags, string $prefix): array continue; } - $majorVersion = $matches[1]; + $majorVersion = intval($matches[1]); $groups[$majorVersion][] = $tag; } - uksort($groups, static function (string $left, string $right): int { - return version_compare($right, $left); + uksort($groups, static function (int $left, int $right): int { + return version_compare((string)$right, (string)$left); }); foreach ($groups as &$groupedTags) { @@ -118,4 +123,19 @@ protected function groupVersionTags(array $tags, string $prefix): array return $groups; } + + public const FIELD_ID = 'id'; + public const FIELD_PACKAGE = 'package'; + public const FIELD_DESCRIPTION = 'description'; + public const FIELD_REPO_URL = 'repo_url'; + public const FIELD_DOWNLOADS = 'downloads'; + public const FIELD_STARS = 'stars'; + public const FIELD_LATEST_STABLE_VERSION = 'latest_stable_version'; + public const FIELD_LATEST_STABLE_RELEASE_DATE = 'latest_stable_release_date'; + public const FIELD_CAKE_PHP_TAGS = 'cake_php_tags'; + public const FIELD_CAKE_PHP_TAG_GROUPS = 'cake_php_tag_groups'; + public const FIELD_PHP_TAGS = 'php_tags'; + public const FIELD_PHP_TAG_GROUPS = 'php_tag_groups'; + public const FIELD_TAGGED = 'tagged'; + public const FIELD_TAGS = 'tags'; } diff --git a/src/Model/Entity/User.php b/src/Model/Entity/User.php index 612f6e16..27135cd7 100644 --- a/src/Model/Entity/User.php +++ b/src/Model/Entity/User.php @@ -13,6 +13,7 @@ * @property string|null $last_name * @property string $email * @property string $username + * @property bool $is_cakephp_dev * @property \Cake\I18n\DateTime $created * @property \Cake\I18n\DateTime|null $modified * @@ -33,4 +34,14 @@ class User extends Entity '*' => true, 'id' => false, ]; + + public const FIELD_ID = 'id'; + public const FIELD_FIRST_NAME = 'first_name'; + public const FIELD_LAST_NAME = 'last_name'; + public const FIELD_EMAIL = 'email'; + public const FIELD_USERNAME = 'username'; + public const FIELD_CREATED = 'created'; + public const FIELD_MODIFIED = 'modified'; + public const FIELD_SOCIAL_PROFILE = 'social_profile'; + public const FIELD_IS_CAKEPHP_DEV = 'is_cakephp_dev'; } diff --git a/src/Model/Table/PackagesTable.php b/src/Model/Table/PackagesTable.php index d3435b62..3246852e 100644 --- a/src/Model/Table/PackagesTable.php +++ b/src/Model/Table/PackagesTable.php @@ -15,15 +15,20 @@ * @method \App\Model\Entity\Package newEntity(array $data, array $options = []) * @method array<\App\Model\Entity\Package> newEntities(array $data, array $options = []) * @method \App\Model\Entity\Package get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) - * @method \App\Model\Entity\Package findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\Package findOrCreate(\Cake\ORM\Query\SelectQuery|callable|array $search, ?callable $callback = null, array $options = []) * @method \App\Model\Entity\Package patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) * @method array<\App\Model\Entity\Package> patchEntities(iterable $entities, array $data, array $options = []) * @method \App\Model\Entity\Package|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) * @method \App\Model\Entity\Package saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) - * @method iterable<\App\Model\Entity\Package>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package>|false saveMany(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\Package>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package> saveManyOrFail(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\Package>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package>|false deleteMany(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\Package>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package> deleteManyOrFail(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package>|false saveMany(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package> saveManyOrFail(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package>|false deleteMany(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\Package> deleteManyOrFail(iterable $entities, array $options = []) + * @property \Cake\ORM\Association\HasMany<\Tags\Model\Table\TaggedTable> $Tagged + * @property \Cake\ORM\Association\BelongsToMany<\Tags\Model\Table\TagsTable> $Tags + * @mixin \Search\Model\Behavior\SearchBehavior + * @mixin \Tags\Model\Behavior\TagBehavior + * @extends \Cake\ORM\Table */ class PackagesTable extends Table { diff --git a/src/Model/Table/UsersTable.php b/src/Model/Table/UsersTable.php index dafd8cc1..82b5cd51 100644 --- a/src/Model/Table/UsersTable.php +++ b/src/Model/Table/UsersTable.php @@ -3,6 +3,7 @@ namespace App\Model\Table; +use ADmad\SocialAuth\Model\Entity\SocialProfile; use Cake\Datasource\EntityInterface; use Cake\Http\Session; use Cake\ORM\RulesChecker; @@ -17,16 +18,17 @@ * @method \App\Model\Entity\User newEntity(array $data, array $options = []) * @method array<\App\Model\Entity\User> newEntities(array $data, array $options = []) * @method \App\Model\Entity\User get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) - * @method \App\Model\Entity\User findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\User findOrCreate(\Cake\ORM\Query\SelectQuery|callable|array $search, ?callable $callback = null, array $options = []) * @method \App\Model\Entity\User patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) * @method array<\App\Model\Entity\User> patchEntities(iterable $entities, array $data, array $options = []) * @method \App\Model\Entity\User|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) * @method \App\Model\Entity\User saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) - * @method iterable<\App\Model\Entity\User>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\User>|false saveMany(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\User>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\User> saveManyOrFail(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\User>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\User>|false deleteMany(iterable $entities, array $options = []) - * @method iterable<\App\Model\Entity\User>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\User> deleteManyOrFail(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\User>|false saveMany(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\User> saveManyOrFail(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\User>|false deleteMany(iterable $entities, array $options = []) + * @method \Cake\Datasource\ResultSetInterface<\App\Model\Entity\User> deleteManyOrFail(iterable $entities, array $options = []) * @mixin \Cake\ORM\Behavior\TimestampBehavior + * @extends \Cake\ORM\Table */ class UsersTable extends Table { @@ -101,6 +103,7 @@ public function buildRules(RulesChecker $rules): RulesChecker */ public function getUser(EntityInterface $profile, Session $session): mixed { + assert($profile instanceof SocialProfile); // Make sure here that all the required fields are actually present if (!$profile->email) { throw new RuntimeException('Could not find email in social profile.'); diff --git a/src/View/AppView.php b/src/View/AppView.php index f9893d66..1b8296d8 100644 --- a/src/View/AppView.php +++ b/src/View/AppView.php @@ -23,6 +23,7 @@ * Your application's default view class * * @link https://book.cakephp.org/5/en/views.html#the-app-view + * @property \Authentication\View\Helper\IdentityHelper $Identity */ class AppView extends View { diff --git a/templates/Error/error500.php b/templates/Error/error500.php index d9c48a8a..db4a6925 100644 --- a/templates/Error/error500.php +++ b/templates/Error/error500.php @@ -3,6 +3,7 @@ * @var \App\View\AppView $this * @var string $message * @var string $url + * @var object $error */ use Cake\Core\Configure; use Cake\Error\Debugger; diff --git a/templates/Packages/index.php b/templates/Packages/index.php index 20660301..2a4e6fdc 100644 --- a/templates/Packages/index.php +++ b/templates/Packages/index.php @@ -2,7 +2,7 @@ /** * @var \App\View\AppView $this * @var iterable<\App\Model\Entity\Package> $featuredPackages - * @var iterable<\App\Model\Entity\Package> $packages + * @var array<\App\Model\Entity\Package>|\Cake\Collection\CollectionInterface<\App\Model\Entity\Package> $packages * @var iterable<\Tags\Model\Entity\Tag> $cakephpTags * @var iterable<\Tags\Model\Entity\Tag> $phpTags */ diff --git a/templates/email/html/default.php b/templates/email/html/default.php index 70a6cd44..bf4c1318 100644 --- a/templates/email/html/default.php +++ b/templates/email/html/default.php @@ -11,7 +11,7 @@ * @link https://cakephp.org CakePHP(tm) Project * @since 0.10.0 * @license https://opensource.org/licenses/mit-license.php MIT License - * @var \Cake\View\View $this + * @var \App\View\AppView $this * @var string $content */ diff --git a/templates/email/text/default.php b/templates/email/text/default.php index cb1f3784..bb8461e6 100644 --- a/templates/email/text/default.php +++ b/templates/email/text/default.php @@ -11,7 +11,7 @@ * @link https://cakephp.org CakePHP(tm) Project * @since 0.10.0 * @license https://opensource.org/licenses/mit-license.php MIT License - * @var \Cake\View\View $this + * @var \App\View\AppView $this * @var string $content */ diff --git a/tests/TestCase/Controller/PagesControllerTest.php b/tests/TestCase/Controller/PagesControllerTest.php index 43eac208..aca056a5 100644 --- a/tests/TestCase/Controller/PagesControllerTest.php +++ b/tests/TestCase/Controller/PagesControllerTest.php @@ -6,6 +6,9 @@ use Cake\TestSuite\IntegrationTestTrait; use Cake\TestSuite\TestCase; +/** + * @link \App\Controller\PagesController + */ class PagesControllerTest extends TestCase { use IntegrationTestTrait;