From 1f939edfa07ae534767beb22ca993ba889d9e5b2 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Feb 2026 19:12:18 +0530 Subject: [PATCH 1/3] Bump up phpstan to level 8 --- .editorconfig | 6 ++++++ phpstan.neon | 16 +++++++--------- src/BakePlugin.php | 7 +++---- src/CodeGen/CodeParser.php | 18 +++++++++++++++--- src/CodeGen/ColumnTypeExtractor.php | 18 +++++++++++++++--- src/Command/BakeCommand.php | 8 +++++++- src/Command/CommandCommand.php | 2 +- src/Command/ControllerCommand.php | 6 +++--- src/Command/FixtureAllCommand.php | 2 +- src/Command/FixtureCommand.php | 6 +++++- src/Command/ModelCommand.php | 19 +++++++++++++------ src/Command/PluginCommand.php | 20 +++++++++++++------- src/Command/TemplateCommand.php | 13 ++++++++++--- src/Command/TestCommand.php | 17 ++++++++++------- src/Utility/CommonOptionsTrait.php | 10 ++++++---- src/Utility/Model/EnumParser.php | 12 +++++++----- src/Utility/SubsetSchemaCollection.php | 2 +- src/Utility/TemplateRenderer.php | 2 +- src/View/BakeView.php | 19 ++++++++----------- 19 files changed, 132 insertions(+), 71 deletions(-) diff --git a/.editorconfig b/.editorconfig index 382eeefd7..d26a83c10 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,12 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true +[*.neon] +indent_style = tab + +[*.neon.dist] +indent_style = tab + [*.yml] indent_size = 2 diff --git a/phpstan.neon b/phpstan.neon index 7f9e3084f..49655075a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,12 +2,10 @@ includes: - phpstan-baseline.neon parameters: - level: 6 - paths: - - src/ - bootstrapFiles: - - tests/bootstrap.php - ignoreErrors: - - identifier: missingType.iterableValue - - identifier: missingType.generics - - identifier: method.childReturnType + level: 8 + paths: + - src/ + bootstrapFiles: + - tests/bootstrap.php + ignoreErrors: + - identifier: missingType.iterableValue diff --git a/src/BakePlugin.php b/src/BakePlugin.php index 0b02eaad3..d4d225f66 100644 --- a/src/BakePlugin.php +++ b/src/BakePlugin.php @@ -26,7 +26,6 @@ use Cake\Http\BaseApplication; use DirectoryIterator; use ReflectionClass; -use ReflectionException; /** * Plugin class for bake @@ -140,11 +139,11 @@ protected function findInPath(string $namespace, string $path): array $class = $namespace . $item->getBasename('.php'); if (!$hasSubfolder) { - try { - $reflection = new ReflectionClass($class); - } catch (ReflectionException) { + if (!class_exists($class)) { continue; } + + $reflection = new ReflectionClass($class); if (!$reflection->isInstantiable() || !$reflection->isSubclassOf(BakeCommand::class)) { continue; } diff --git a/src/CodeGen/CodeParser.php b/src/CodeGen/CodeParser.php index c48c8eecb..9042f1bf9 100644 --- a/src/CodeGen/CodeParser.php +++ b/src/CodeGen/CodeParser.php @@ -81,7 +81,11 @@ public function parseFile(string $code): ?ParsedFile { $this->fileText = $code; try { - $this->traverser->traverse($this->parser->parse($code)); + $ast = $this->parser->parse($code); + if ($ast === null) { + return null; + } + $this->traverser->traverse($ast); } catch (Error $e) { throw new ParseException($e->getMessage(), null, $e); } @@ -172,7 +176,11 @@ public function enterNode(Node $node) throw new ParseException('Multiple constants per line are not supported, update your file'); } - $name = (string)current($constant->consts)->name; + $const = current($constant->consts); + if ($const === false) { + continue; + } + $name = (string)$const->name; $constants[$name] = $this->getNodeCode($constant); } @@ -182,7 +190,11 @@ public function enterNode(Node $node) throw new ParseException('Multiple properties per line are not supported, update your file'); } - $name = (string)current($property->props)->name; + $prop = current($property->props); + if ($prop === false) { + continue; + } + $name = (string)$prop->name; $properties[$name] = $this->getNodeCode($property); } diff --git a/src/CodeGen/ColumnTypeExtractor.php b/src/CodeGen/ColumnTypeExtractor.php index 0c504cef6..9df1df081 100644 --- a/src/CodeGen/ColumnTypeExtractor.php +++ b/src/CodeGen/ColumnTypeExtractor.php @@ -73,6 +73,9 @@ public function extract(string $code): array // Wrap code in a dummy class if needed for parsing $wrappedCode = "parser->parse($wrappedCode); + if ($ast === null) { + return []; + } $traverser = new NodeTraverser(); $traverser->addVisitor($this); @@ -144,8 +147,13 @@ protected function processMethodCall(MethodCall $methodCall): void ) { // Extract the column name and type expression if (count($methodCall->args) >= 2) { - $columnArg = $methodCall->args[0]->value; - $typeArg = $methodCall->args[1]->value; + $columnArgNode = $methodCall->args[0]; + $typeArgNode = $methodCall->args[1]; + if (!$columnArgNode instanceof Node\Arg || !$typeArgNode instanceof Node\Arg) { + return; + } + $columnArg = $columnArgNode->value; + $typeArg = $typeArgNode->value; // Get column name $columnName = $this->getStringValue($columnArg); @@ -199,7 +207,11 @@ protected function getTypeExpression(Node $node): ?string if ($className === 'EnumType' || str_ends_with($className, '\\EnumType')) { if ($methodName === 'from' && count($node->args) > 0) { // Extract the enum class name - $arg = $node->args[0]->value; + $argNode = $node->args[0]; + if (!$argNode instanceof Node\Arg) { + return null; + } + $arg = $argNode->value; if ($arg instanceof Node\Expr\ClassConstFetch) { if ( $arg->class instanceof Node\Name && diff --git a/src/Command/BakeCommand.php b/src/Command/BakeCommand.php index 482e16c7e..f5ade6a23 100644 --- a/src/Command/BakeCommand.php +++ b/src/Command/BakeCommand.php @@ -112,6 +112,7 @@ protected function _getName(string $name): string */ protected function getPrefix(Arguments $args): string { + /** @var string|null $prefix */ $prefix = $args->getOption('prefix'); if (!$prefix) { return ''; @@ -225,7 +226,12 @@ protected function isValidColumnName(string $name): bool protected function parseFile(string $path): ?ParsedFile { if (file_exists($path)) { - return (new CodeParser())->parseFile(file_get_contents($path)); + $contents = file_get_contents($path); + if ($contents === false) { + return null; + } + + return (new CodeParser())->parseFile($contents); } return null; diff --git a/src/Command/CommandCommand.php b/src/Command/CommandCommand.php index 580508e19..54cc7ae53 100644 --- a/src/Command/CommandCommand.php +++ b/src/Command/CommandCommand.php @@ -69,7 +69,7 @@ public function templateData(Arguments $arguments): array $data['command_name'] = Inflector::underscore(str_replace( '.', ' ', - $arguments->getArgument('name'), + $arguments->getArgument('name') ?? '', )); return $data; diff --git a/src/Command/ControllerCommand.php b/src/Command/ControllerCommand.php index c78bc5df4..2b88cf0fa 100644 --- a/src/Command/ControllerCommand.php +++ b/src/Command/ControllerCommand.php @@ -84,7 +84,7 @@ public function bake(string $controllerName, Arguments $args, ConsoleIo $io): vo $actions = ['index', 'view', 'add', 'edit', 'delete']; } if ($args->getOption('actions')) { - $actions = array_map('trim', explode(',', $args->getOption('actions'))); + $actions = array_map('trim', explode(',', (string)$args->getOption('actions'))); $actions = array_filter($actions); } if (!$args->getOption('actions') && Plugin::isLoaded('Authentication') && $controllerName === 'Users') { @@ -221,7 +221,7 @@ public function getComponents(Arguments $args): array { $components = []; if ($args->getOption('components')) { - $components = explode(',', $args->getOption('components')); + $components = explode(',', (string)$args->getOption('components')); $components = array_values(array_filter(array_map('trim', $components))); } else { if (Plugin::isLoaded('Authorization')) { @@ -242,7 +242,7 @@ public function getHelpers(Arguments $args): array { $helpers = []; if ($args->getOption('helpers')) { - $helpers = explode(',', $args->getOption('helpers')); + $helpers = explode(',', (string)$args->getOption('helpers')); $helpers = array_values(array_filter(array_map('trim', $helpers))); } diff --git a/src/Command/FixtureAllCommand.php b/src/Command/FixtureAllCommand.php index 83de359c3..0b9b594d5 100644 --- a/src/Command/FixtureAllCommand.php +++ b/src/Command/FixtureAllCommand.php @@ -83,7 +83,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $this->extractCommonProperties($args); /** @var \Cake\Database\Connection $connection */ - $connection = ConnectionManager::get($args->getOption('connection') ?? 'default'); + $connection = ConnectionManager::get((string)($args->getOption('connection') ?: 'default')); $scanner = new TableScanner($connection); $fixture = new FixtureCommand(); diff --git a/src/Command/FixtureCommand.php b/src/Command/FixtureCommand.php index 94908eea9..5ccdec226 100644 --- a/src/Command/FixtureCommand.php +++ b/src/Command/FixtureCommand.php @@ -122,7 +122,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int return static::CODE_SUCCESS; } - $table = $args->getOption('table') ?? ''; + $table = (string)$args->getOption('table'); $model = $this->_camelize($name); $this->bake($model, $table, $args, $io); @@ -285,16 +285,19 @@ protected function _generateSchema(TableSchemaInterface $table): string { $cols = $indexes = $constraints = []; foreach ($table->columns() as $field) { + /** @var array $fieldData */ $fieldData = $table->getColumn($field); $properties = implode(', ', $this->_values($fieldData)); $cols[] = " '$field' => [$properties],"; } foreach ($table->indexes() as $index) { + /** @var array $fieldData */ $fieldData = $table->getIndex($index); $properties = implode(', ', $this->_values($fieldData)); $indexes[] = " '$index' => [$properties],"; } foreach ($table->constraints() as $index) { + /** @var array $fieldData */ $fieldData = $table->getConstraint($index); $properties = implode(', ', $this->_values($fieldData)); $constraints[] = " '$index' => [$properties],"; @@ -360,6 +363,7 @@ protected function _generateRecords(TableSchemaInterface $table, int $recordCoun for ($i = 0; $i < $recordCount; $i++) { $record = []; foreach ($table->columns() as $field) { + /** @var array $fieldInfo */ $fieldInfo = $table->getColumn($field); $insert = ''; switch ($fieldInfo['type']) { diff --git a/src/Command/ModelCommand.php b/src/Command/ModelCommand.php index 1fb504d4e..33ec59f5a 100644 --- a/src/Command/ModelCommand.php +++ b/src/Command/ModelCommand.php @@ -392,7 +392,8 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg if ($className && $className !== $tmpModelName) { $assoc['className'] = $className; } - if ($schema->getColumn($fieldName)['null'] === false) { + $columnInfo = $schema->getColumn($fieldName); + if ($columnInfo !== null && ($columnInfo['null'] ?? true) === false) { $assoc['joinType'] = 'INNER'; } } @@ -484,8 +485,9 @@ public function hasUniqueConstraintFor(TableSchemaInterface $schema, string $key foreach ($schema->constraints() as $constraint) { $constraintInfo = $schema->getConstraint($constraint); if ( - $constraintInfo['type'] === TableSchema::CONSTRAINT_UNIQUE && - $constraintInfo['columns'] === [$keyField] + $constraintInfo !== null && + ($constraintInfo['type'] ?? null) === TableSchema::CONSTRAINT_UNIQUE && + ($constraintInfo['columns'] ?? []) === [$keyField] ) { return true; } @@ -663,7 +665,7 @@ public function getDisplayField(Table $model, Arguments $args): array|string public function getPrimaryKey(Table $model, Arguments $args): array { if ($args->getOption('primary-key')) { - $fields = explode(',', $args->getOption('primary-key')); + $fields = explode(',', (string)$args->getOption('primary-key')); return array_values(array_filter(array_map('trim', $fields))); } @@ -702,6 +704,7 @@ public function getEntityPropertySchema(Table $model): array $schema = $model->getSchema(); foreach ($schema->columns() as $column) { + /** @var array $columnSchema */ $columnSchema = $schema->getColumn($column); $properties[$column] = [ @@ -757,7 +760,7 @@ public function getFields(Table $table, Arguments $args): array|false|null return false; } if ($args->getOption('fields')) { - $fields = explode(',', $args->getOption('fields')); + $fields = explode(',', (string)$args->getOption('fields')); return array_values(array_filter(array_map('trim', $fields))); } @@ -786,7 +789,7 @@ public function getHiddenFields(Table $model, Arguments $args): array return []; } if ($args->getOption('hidden')) { - $fields = explode(',', $args->getOption('hidden')); + $fields = explode(',', (string)$args->getOption('hidden')); return array_values(array_filter(array_map('trim', $fields))); } @@ -932,6 +935,7 @@ public function fieldValidation( } foreach ($schema->constraints() as $constraint) { + /** @var array $constraint */ $constraint = $schema->getConstraint($constraint); if (!in_array($fieldName, $constraint['columns'] ?? [], true) || count($constraint['columns']) > 1) { continue; @@ -1010,6 +1014,7 @@ public function getRules(Table $model, array $associations, Arguments $args): ar $uniqueConstraintsColumns = []; foreach ($schema->constraints() as $name) { + /** @var array $constraint */ $constraint = $schema->getConstraint($name); if ($constraint['type'] !== TableSchema::CONSTRAINT_UNIQUE) { continue; @@ -1476,6 +1481,7 @@ protected function possibleEnumFields(TableSchemaInterface $schema): array $fields = []; foreach ($schema->columns() as $column) { + /** @var array $columnSchema */ $columnSchema = $schema->getColumn($column); if (str_starts_with($columnSchema['type'], 'enum-')) { $fields[] = $column; @@ -1502,6 +1508,7 @@ protected function getEnumDefinitions(TableSchemaInterface $schema): array $enums = []; foreach ($schema->columns() as $column) { + /** @var array $columnSchema */ $columnSchema = $schema->getColumn($column); if ( !in_array($columnSchema['type'], ['string', 'integer', 'tinyinteger', 'smallinteger'], true) diff --git a/src/Command/PluginCommand.php b/src/Command/PluginCommand.php index 10b1b84d6..551d10de7 100644 --- a/src/Command/PluginCommand.php +++ b/src/Command/PluginCommand.php @@ -65,7 +65,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $plugin = implode('/', array_map([Inflector::class, 'camelize'], $parts)); if ($args->getOption('standalone-path')) { - $this->path = $args->getOption('standalone-path'); + $this->path = (string)$args->getOption('standalone-path'); $this->path = rtrim($this->path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $this->isVendor = true; @@ -105,7 +105,8 @@ public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool { if (!$this->isVendor) { $pathOptions = App::path('plugins'); - $this->path = current($pathOptions); + $currentPath = current($pathOptions); + $this->path = $currentPath !== false ? $currentPath : ''; if (count($pathOptions) > 1) { $this->findPath($pathOptions, $io); @@ -130,8 +131,13 @@ public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool } $composer = $this->findComposer($args, $io); + if ($composer === false) { + $io->error('Could not find composer executable.'); + $this->abort(); + } try { + /** @var non-empty-string $cwd */ $cwd = getcwd(); // Windows makes running multiple commands at once hard. @@ -200,7 +206,7 @@ protected function _generateFiles( $package = Inflector::dasherize($vendor) . '/' . Inflector::dasherize($name); $composerConfig = json_decode( - file_get_contents(ROOT . DS . 'composer.json'), + (string)file_get_contents(ROOT . DS . 'composer.json'), true, ); @@ -221,7 +227,7 @@ protected function _generateFiles( $paths = []; if ($args->hasOption('theme')) { - $paths[] = Plugin::templatePath($args->getOption('theme')); + $paths[] = Plugin::templatePath((string)$args->getOption('theme')); } $paths = array_merge($paths, Configure::read('App.paths.templates')); @@ -392,7 +398,7 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar * * @param \Cake\Console\Arguments $args The command arguments. * @param \Cake\Console\ConsoleIo $io The console io - * @return string|bool Either the path to composer or false if it cannot be found. + * @return string|false Either the path to composer or false if it cannot be found. */ public function findComposer(Arguments $args, ConsoleIo $io): string|bool { @@ -404,7 +410,7 @@ public function findComposer(Arguments $args, ConsoleIo $io): string|bool } } $composer = false; - $path = env('PATH'); + $path = (string)env('PATH'); if (!empty($path)) { $paths = explode(PATH_SEPARATOR, $path); $composer = $this->_searchPath($paths, $io); @@ -418,7 +424,7 @@ public function findComposer(Arguments $args, ConsoleIo $io): string|bool * * @param array $path The paths to search. * @param \Cake\Console\ConsoleIo $io The console io - * @return string|bool + * @return string|false */ protected function _searchPath(array $path, ConsoleIo $io): string|bool { diff --git a/src/Command/TemplateCommand.php b/src/Command/TemplateCommand.php index f467c1aa8..239eb5764 100644 --- a/src/Command/TemplateCommand.php +++ b/src/Command/TemplateCommand.php @@ -102,7 +102,15 @@ public function initialize(): void { parent::initialize(); - $this->path = current(App::path('templates')); + $templatePaths = App::path('templates'); + if ($templatePaths === []) { + throw new RuntimeException( + 'Could not read template paths. ' . + 'Ensure `App.paths.templates` is defined in your application configuration.', + ); + } + + $this->path = current($templatePaths); } /** @@ -132,8 +140,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $template = $args->getArgument('template'); $action = $args->getArgument('action'); - $controller = $args->getOption('controller'); - $this->controller($args, $name, $controller); + $this->controller($args, $name, (string)$args->getOption('controller')); $this->model($name); if ($template && $action === null) { diff --git a/src/Command/TestCommand.php b/src/Command/TestCommand.php index f48e99e26..0231bf88b 100644 --- a/src/Command/TestCommand.php +++ b/src/Command/TestCommand.php @@ -110,7 +110,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int return null; } - $type = $this->normalize($args->getArgument('type')); + $type = $this->normalize((string)$args->getArgument('type')); if ($args->getOption('all')) { $this->_bakeAll($type, $args, $io); @@ -122,7 +122,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int return null; } - $name = $args->getArgument('name'); + $name = (string)$args->getArgument('name'); $name = $this->_getName($name); $result = $this->bake($type, $name, $args, $io); @@ -225,8 +225,9 @@ protected function _getClassOptions(string $namespace): array foreach ($files as $fileObj) { if ($fileObj->isFile() && $fileObj->getFileName() !== 'Application.php') { // Build the namespace path relative to App directory + /** @var string $relativePath */ $relativePath = str_replace($base, '', $fileObj->getPath()); - $relativePath = trim(str_replace(DS, '\\', $relativePath), '\\'); + $relativePath = trim(str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath), '\\'); $className = substr($fileObj->getFileName(), 0, -4) ?: ''; if ($relativePath) { $classes[] = $relativePath . '\\' . $className; @@ -272,7 +273,7 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo $io->out(" bin/cake bake test class '{$className}'"); $io->out(''); $io->out('Or specify without the base namespace:'); - $io->out(' bin/cake bake test class YourNamespace\\ClassName'); + $io->out(' bin/cake bake test class YourNamespace\ClassName'); return static::CODE_ERROR; } @@ -299,12 +300,14 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo if ($hasFixtureFactories) { $io->info('Fixture Factories plugin detected - skipping fixture property generation.'); } elseif ($args->getOption('fixtures')) { - $fixtures = array_map('trim', explode(',', $args->getOption('fixtures'))); + $fixtures = array_map('trim', explode(',', (string)$args->getOption('fixtures'))); $this->_fixtures = array_filter($fixtures); } elseif ($this->typeCanDetectFixtures($type) && class_exists($fullClassName)) { $io->out('Bake is detecting possible fixtures...'); $testSubject = $this->buildTestSubject($type, $fullClassName); - $this->generateFixtureList($testSubject); + if ($testSubject instanceof Table || $testSubject instanceof Controller) { + $this->generateFixtureList($testSubject); + } } } @@ -493,7 +496,7 @@ public function mapType(string $type): string * Get methods declared in the class given. * No parent methods will be returned * - * @param string $className Name of class to look at. + * @param class-string $className Name of class to look at. * @return array Array of method names. * @throws \ReflectionException */ diff --git a/src/Utility/CommonOptionsTrait.php b/src/Utility/CommonOptionsTrait.php index fde67f954..b2a379f9c 100644 --- a/src/Utility/CommonOptionsTrait.php +++ b/src/Utility/CommonOptionsTrait.php @@ -62,7 +62,7 @@ protected function extractCommonProperties(Arguments $args): void // These properties should ideally not exist, but until ConsoleOptionParser // gets validation and transform logic they will have to stay. if ($args->hasOption('plugin')) { - $plugin = $args->getOption('plugin'); + $plugin = (string)$args->getOption('plugin'); $parts = explode('/', $plugin); $this->plugin = implode('/', array_map([$this, '_camelize'], $parts)); @@ -73,9 +73,11 @@ protected function extractCommonProperties(Arguments $args): void } } - $this->theme = $args->getOption('theme'); - $this->connection = $args->getOption('connection'); - $this->force = $args->getOption('force'); + $theme = $args->getOption('theme'); + $this->theme = is_string($theme) ? $theme : null; + $connection = $args->getOption('connection'); + $this->connection = is_string($connection) ? $connection : 'default'; + $this->force = (bool)$args->getOption('force'); } /** diff --git a/src/Utility/Model/EnumParser.php b/src/Utility/Model/EnumParser.php index e559fe03e..3cf32999b 100644 --- a/src/Utility/Model/EnumParser.php +++ b/src/Utility/Model/EnumParser.php @@ -23,9 +23,10 @@ public static function parseCases(?string $casesString, bool $int): array $definition = []; foreach ($enumCases as $k => $enumCase) { $case = $value = trim($enumCase); - if (str_contains($case, ':')) { - $value = trim(mb_substr($case, strpos($case, ':') + 1)); - $case = mb_substr($case, 0, strpos($case, ':')); + $pos = strpos($case, ':'); + if ($pos !== false) { + $value = trim(mb_substr($case, $pos + 1)); + $case = mb_substr($case, 0, $pos); } elseif ($int) { $value = $k; } @@ -52,8 +53,9 @@ public static function parseCases(?string $casesString, bool $int): array public static function parseDefinitionString(string $comment): string { $string = trim(mb_substr($comment, strpos($comment, '[enum]') + 6)); - if (str_contains($string, ';')) { - $string = trim(mb_substr($string, 0, strpos($string, ';'))); + $pos = strpos($string, ';'); + if ($pos !== false) { + $string = trim(mb_substr($string, 0, $pos)); } return $string; diff --git a/src/Utility/SubsetSchemaCollection.php b/src/Utility/SubsetSchemaCollection.php index ca1b83524..6f202c08d 100644 --- a/src/Utility/SubsetSchemaCollection.php +++ b/src/Utility/SubsetSchemaCollection.php @@ -60,7 +60,7 @@ public function getInnerCollection(): CollectionInterface /** * Get the list of tables in this schema collection. * - * @return list + * @return array */ public function listTables(): array { diff --git a/src/Utility/TemplateRenderer.php b/src/Utility/TemplateRenderer.php index d3f8eb633..42996b97a 100644 --- a/src/Utility/TemplateRenderer.php +++ b/src/Utility/TemplateRenderer.php @@ -59,7 +59,7 @@ public function __construct(?string $theme = null) /** * Get view instance * - * @return \Cake\View\View + * @return \Bake\View\BakeView * @triggers Bake.initialize $view */ public function getView(): View diff --git a/src/View/BakeView.php b/src/View/BakeView.php index 841865434..78928f10a 100644 --- a/src/View/BakeView.php +++ b/src/View/BakeView.php @@ -18,17 +18,12 @@ use Cake\Core\Configure; use Cake\Core\ConventionsTrait; -use Cake\Event\EventDispatcherTrait; use Cake\Event\EventInterface; use Cake\TwigView\View\TwigView; use function Cake\Core\pluginSplit; class BakeView extends TwigView { - /** - * @use \Cake\Event\EventDispatcherTrait<\Cake\View\View> - */ - use EventDispatcherTrait; use ConventionsTrait; /** @@ -81,6 +76,8 @@ public function initialize(): void */ public function render(?string $template = null, string|false|null $layout = null): string { + assert($template !== null, 'Template name must be provided.'); + $viewFileName = $this->_getTemplateFileName($template); [, $templateEventName] = pluginSplit($template); $templateEventName = str_replace(['/', '\\'], '.', $templateEventName); @@ -107,19 +104,19 @@ public function render(?string $template = null, string|false|null $layout = nul * * Use the Bake prefix for bake related view events * - * @template TSubject of \Cake\View\View * @param string $name Name of the event. * @param array $data Any value you wish to be transported with this event to * it can be read by listeners. - * - * @param TSubject|null $subject The object that this event applies to + * @param object|null $subject The object that this event applies to * ($this by default). - * @return \Cake\Event\EventInterface<\Cake\View\View> + * @return \Cake\Event\EventInterface + * @phpstan-ignore missingType.generics */ public function dispatchEvent(string $name, array $data = [], ?object $subject = null): EventInterface { - $name = preg_replace('/^View\./', 'Bake.', $name); + $name = (string)preg_replace('/^View\./', 'Bake.', $name); + /** @phpstan-ignore-next-line missingType.generics */ return parent::dispatchEvent($name, $data, $subject); } @@ -128,7 +125,7 @@ public function dispatchEvent(string $name, array $data = [], ?object $subject = * * @param ?string $plugin Optional plugin name to scan for view files. * @param bool $cached Set to false to force a refresh of view paths. Default true. - * @return list paths + * @return array paths */ protected function _paths(?string $plugin = null, bool $cached = true): array { From 09b28ce3783acbed343271cefd5cf70855d2ef3d Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Feb 2026 19:27:55 +0530 Subject: [PATCH 2/3] Fix phpunit notices --- tests/TestCase/Command/ModelCommandTest.php | 16 ++++++++-------- tests/TestCase/Command/PluginCommandTest.php | 4 ++-- tests/TestCase/Command/TemplateCommandTest.php | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/TestCase/Command/ModelCommandTest.php b/tests/TestCase/Command/ModelCommandTest.php index 74ff65100..0afceb9a4 100644 --- a/tests/TestCase/Command/ModelCommandTest.php +++ b/tests/TestCase/Command/ModelCommandTest.php @@ -295,7 +295,7 @@ public function testGetAssociations() $command->connection = 'test'; $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($items, $args, $io); $expected = [ @@ -341,7 +341,7 @@ public function testGetAssociationsNoFlag() $command->connection = 'test'; $arguments = new Arguments([], ['no-associations' => true], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $articles = $this->getTableLocator()->get('BakeArticle'); $this->assertEquals([], $command->getAssociations($articles, $arguments, $io)); } @@ -359,7 +359,7 @@ public function testGetAssociationsPlugin() $command->connection = 'test'; $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($items, $args, $io); $expected = [ 'belongsTo' => [ @@ -412,7 +412,7 @@ public function testGetAssociationsIgnoreUnderscoreIdIfNoDbTable() $command->connection = 'test'; $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($items, $args, $io); $expected = [ 'belongsTo' => [ @@ -461,7 +461,7 @@ public function testGetAssociationsAddAssociationIfTableExist() $command->connection = 'test'; $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($items, $args, $io); $expected = [ 'belongsTo' => [ @@ -514,7 +514,7 @@ public function testGetAssociationsAddAssociationIfNoTableExistButAliasIsAllowed $command->connection = 'test'; $args = new Arguments([], ['skip-relation-check' => true], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($items, $args, $io); $expected = [ 'belongsTo' => [ @@ -566,7 +566,7 @@ public function testGetAssociationsIgnoreUnderscoreId() ]); $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $command = new ModelCommand(); $command->connection = 'test'; @@ -592,7 +592,7 @@ public function testGetAssociationsConstraints() $command->connection = 'test'; $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getAssociations($model, $args, $io); $expected = [ diff --git a/tests/TestCase/Command/PluginCommandTest.php b/tests/TestCase/Command/PluginCommandTest.php index 03498fe28..0c6efcf3d 100644 --- a/tests/TestCase/Command/PluginCommandTest.php +++ b/tests/TestCase/Command/PluginCommandTest.php @@ -201,7 +201,7 @@ public function testMainUpdateComposer() */ public function testFindPathNonExistent() { - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $paths = App::path('plugins'); array_unshift($paths, '/fake/path'); @@ -224,7 +224,7 @@ public function testFindPathNonExistent() public function testFindPathEmpty() { $this->expectException(StopException::class); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $paths = ['/fake/path', '/fake/path2']; $command = new PluginCommand(); diff --git a/tests/TestCase/Command/TemplateCommandTest.php b/tests/TestCase/Command/TemplateCommandTest.php index e730bf0d4..846386e79 100644 --- a/tests/TestCase/Command/TemplateCommandTest.php +++ b/tests/TestCase/Command/TemplateCommandTest.php @@ -310,7 +310,7 @@ public function testGetContent() ]; $command = new TemplateCommand(); $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getContent($args, $io, 'view', $vars); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); } @@ -355,7 +355,7 @@ public function testGetContentAssociations() $command = new TemplateCommand(); $args = new Arguments([], [], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getContent($args, $io, 'view', $vars); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); } @@ -428,7 +428,7 @@ public function testGetContentWithRoutingPrefix() ]; $command = new TemplateCommand(); $args = new Arguments([], ['prefix' => 'Admin'], []); - $io = $this->createMock(ConsoleIo::class); + $io = $this->createStub(ConsoleIo::class); $result = $command->getContent($args, $io, 'view', $vars); $this->assertSameAsFile(__FUNCTION__ . '-view.php', $result); From f4175567d22a5912d0f6f86aec38217f911c968a Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Feb 2026 19:31:25 +0530 Subject: [PATCH 3/3] update phpstan version --- .phive/phars.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.phive/phars.xml b/.phive/phars.xml index 4d447d1a0..40973f754 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,4 +1,4 @@ - +