From 8eb8fe6a499cbd245e16eaf786ae3b3d42011061 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Sep 2026 17:49:00 +0530 Subject: [PATCH 1/6] Update for CakePHP 6 --- composer.json | 18 +- phpcs.xml | 4 +- rector.php | 205 ++++++++++++-- src/CodeGen/ClassBuilder.php | 5 +- src/CodeGen/CodeParser.php | 5 +- src/CodeGen/ColumnTypeExtractor.php | 39 +-- src/CodeGen/FileBuilder.php | 10 +- src/CodeGen/ImportHelper.php | 10 +- src/CodeGen/ParsedClass.php | 36 +-- src/CodeGen/ParsedFile.php | 34 +-- src/Command/AllCommand.php | 51 ++-- src/Command/BakeCommand.php | 49 ++-- src/Command/CellCommand.php | 25 +- src/Command/CommandCommand.php | 8 +- src/Command/ControllerAllCommand.php | 14 +- src/Command/ControllerCommand.php | 97 +++---- src/Command/EntryCommand.php | 51 ++-- src/Command/EnumCommand.php | 28 +- src/Command/FixtureAllCommand.php | 19 +- src/Command/FixtureCommand.php | 122 ++++----- src/Command/MailerCommand.php | 9 +- src/Command/ModelAllCommand.php | 13 +- src/Command/ModelCommand.php | 257 ++++++++---------- src/Command/PluginCommand.php | 134 ++++----- src/Command/SimpleBakeCommand.php | 49 ++-- src/Command/TemplateAllCommand.php | 16 +- src/Command/TemplateCommand.php | 133 ++++----- src/Command/TestCommand.php | 167 ++++++------ src/Utility/CommonOptionsTrait.php | 8 +- src/Utility/Model/EnumParser.php | 3 +- src/Utility/Process.php | 9 +- src/Utility/SubsetSchemaCollection.php | 21 +- src/Utility/TableScanner.php | 11 +- src/Utility/TemplateRenderer.php | 8 +- src/View/BakeView.php | 14 +- src/View/Helper/BakeHelper.php | 18 +- src/View/Helper/DocBlockHelper.php | 10 +- templates/bake/Command/command.twig | 6 +- templates/bake/Model/entity.twig | 8 +- templates/bake/View/cell.twig | 2 +- tests/TestCase/CodeGen/FileBuilderTest.php | 5 - tests/TestCase/Command/CellCommandTest.php | 8 +- tests/TestCase/Command/CommandCommandTest.php | 6 +- tests/TestCase/Command/CommandHelperTest.php | 6 +- .../Command/ControllerAllCommandTest.php | 2 +- .../Command/ControllerCommandTest.php | 32 ++- tests/TestCase/Command/EntryCommandTest.php | 4 +- tests/TestCase/Command/EnumCommandTest.php | 2 +- .../Command/FixtureAllCommandTest.php | 2 +- tests/TestCase/Command/FixtureCommandTest.php | 15 +- tests/TestCase/Command/MailerCommandTest.php | 6 +- .../Command/MiddlewareCommandTest.php | 6 +- .../ModelCommandAssociationDetectionTest.php | 18 +- tests/TestCase/Command/ModelCommandTest.php | 175 ++++++++---- tests/TestCase/Command/PluginCommandTest.php | 29 +- .../Command/SimpleBakeCommandTest.php | 6 +- .../Command/TemplateAllCommandTest.php | 2 +- .../TestCase/Command/TemplateCommandTest.php | 67 +++-- tests/TestCase/Command/TestCommandTest.php | 6 +- tests/TestCase/PluginTest.php | 4 +- tests/TestCase/TestCase.php | 2 +- .../TestCase/Utility/TemplateRendererTest.php | 6 +- tests/TestCase/View/BakeViewTest.php | 2 +- tests/TestCase/View/Helper/BakeHelperTest.php | 4 +- .../View/Helper/DocBlockHelperTest.php | 11 +- tests/comparisons/Cell/testBakePlugin.php | 2 +- tests/comparisons/Command/testBakePlugin.php | 6 +- .../Model/testBakeEntityCustomHidden.php | 2 +- .../Model/testBakeEntityFieldsDefaults.php | 2 +- .../Model/testBakeEntityFieldsWhiteList.php | 2 +- .../Model/testBakeEntityFullContext.php | 4 +- .../Model/testBakeEntityHidden.php | 2 +- .../Model/testBakeEntityWithPlugin.php | 4 +- .../Model/testBakeUpdateEntity.php | 4 +- .../test_app/App/Command/AppPolicyCommand.php | 5 +- .../App/Controller/ArticlesController.php | 2 +- .../App/Controller/ArticlesTagsController.php | 2 +- .../BakeArticlesBakeTagsController.php | 2 +- .../App/Controller/BakeAuthorsController.php | 2 +- .../App/Controller/BakeTagsController.php | 2 +- .../App/Controller/BakeUsersController.php | 2 +- .../App/Controller/BinaryTestsController.php | 2 +- .../test_app/App/Controller/CarController.php | 2 +- .../App/Controller/CarsController.php | 2 +- .../App/Controller/CategoriesController.php | 2 +- .../CategoriesProductsController.php | 2 +- .../Controller/CategoryThreadsController.php | 2 +- .../App/Controller/DatatypesController.php | 2 +- .../App/Controller/HiddenFieldsController.php | 2 +- .../App/Controller/InvitationsController.php | 2 +- .../App/Controller/NumberTreesController.php | 2 +- .../App/Controller/OldProductsController.php | 2 +- .../App/Controller/ProfilesController.php | 2 +- .../App/Controller/RelationsController.php | 2 +- .../App/Controller/RolesController.php | 2 +- .../SelfReferencingUniqueKeysController.php | 2 +- .../App/Controller/TagsController.php | 2 +- .../App/Controller/TodoItemsController.php | 2 +- .../TodoItemsTodoLabelsController.php | 2 +- .../App/Controller/TodoLabelsController.php | 2 +- .../Controller/TodoRemindersController.php | 2 +- .../App/Controller/TodoTasksController.php | 2 +- .../App/Controller/UniqueFieldsController.php | 2 +- .../test_app/App/Model/Entity/HiddenField.php | 2 +- .../BakeTest/src/Command/ZerglingCommand.php | 6 +- .../src/Controller/TestsController.php | 2 +- 106 files changed, 1147 insertions(+), 1104 deletions(-) diff --git a/composer.json b/composer.json index d08c73efd..2cde5550d 100644 --- a/composer.json +++ b/composer.json @@ -22,16 +22,16 @@ "source": "https://github.com/cakephp/bake" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "brick/varexporter": "^0.7.0", - "cakephp/cakephp": "^5.4", - "cakephp/twig-view": "^2.1", + "cakephp/cakephp": "^6.0", + "cakephp/twig-view": "^3.0", "nikic/php-parser": "^5.0.0" }, "require-dev": { - "cakephp/cakephp-codesniffer": "^5.0.0", - "cakephp/debug_kit": "^5.0.0", - "phpunit/phpunit": "^11.5.20 || ^12.2.4 || ^13.0" + "cakephp/cakephp-codesniffer": "^6.0", + "cakephp/debug_kit": "^6.0", + "phpunit/phpunit": "^12.2.4 || ^13.0" }, "autoload": { "psr-4": { @@ -71,10 +71,12 @@ "stan": "@phpstan", "stan-baseline": "tools/phpstan --generate-baseline", "stan-setup": "phive install", - "rector-setup": "cp composer.json composer.backup && composer require --dev rector/rector:\"~2.3.1\" && mv composer.backup composer.json", + "rector-setup": "cp composer.json composer.backup && composer require --dev rector/rector:\"~2.6.0\" && mv composer.backup composer.json", "rector-check": "vendor/bin/rector process --dry-run", "rector-fix": "vendor/bin/rector process", "test": "phpunit", "test-coverage": "phpunit --coverage-clover=clover.xml" - } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/phpcs.xml b/phpcs.xml index 16a351cd6..fec3925cb 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,12 +1,10 @@ - - src/ tests/ - + diff --git a/rector.php b/rector.php index 1aaa408d3..b1eb978f0 100644 --- a/rector.php +++ b/rector.php @@ -2,29 +2,95 @@ declare(strict_types=1); use Rector\Caching\ValueObject\Storage\FileCacheStorage; -use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector; +use Rector\CodeQuality\Rector\BooleanNot\NegatedAndsToPositiveOrsRector; +use Rector\CodeQuality\Rector\Catch_\ThrowWithPreviousExceptionRector; +use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector; +use Rector\CodeQuality\Rector\ClassMethod\ExplicitReturnNullRector; +use Rector\CodeQuality\Rector\ClassMethod\OptionalParametersAfterRequiredRector; +use Rector\CodeQuality\Rector\Equal\UseIdenticalOverEqualWithSameTypeRector; +use Rector\CodeQuality\Rector\Foreach_\ForeachToInArrayRector; use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector; -use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector; -use Rector\CodingStyle\Rector\Assign\SplitDoubleAssignRector; +use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector; +use Rector\CodeQuality\Rector\If_\ConsecutiveNullCompareReturnsToNullCoalesceQueueRector; +use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; +use Rector\CodeQuality\Rector\Include_\AbsolutizeRequireAndIncludePathRector; +use Rector\CodeQuality\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector; +use Rector\CodeQuality\Rector\Property\FixClassCaseSensitivityVarDocblockRector; use Rector\CodingStyle\Rector\Catch_\CatchExceptionNameMatchingTypeRector; +use Rector\CodingStyle\Rector\ClassLike\NewlineBetweenClassLikeStmtsRector; +use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector; -use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector; use Rector\CodingStyle\Rector\FuncCall\FunctionFirstClassCallableRector; +use Rector\CodingStyle\Rector\FuncCall\StrictArraySearchRector; +use Rector\CodingStyle\Rector\FuncCall\VersionCompareFuncCallToConstantRector; use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; use Rector\CodingStyle\Rector\String_\UseClassKeywordForClassNameResolutionRector; use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\Assign\RemoveDoubleAssignRector; +use Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector; +use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveDuplicatedReturnSelfDocblockRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveMixedDocblockOverruledByNativeTypeRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveNullTagValueNodeRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingClassMethodRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveReturnTagIncompatibleWithNativeTypeRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector; -use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUselessUnionReturnDocblockRector; +use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector; +use Rector\DeadCode\Rector\Expression\RemoveDeadStmtRector; +use Rector\DeadCode\Rector\For_\RemoveDeadIfForeachForRector; +use Rector\DeadCode\Rector\For_\RemoveDeadLoopRector; +use Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector; +use Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector; +use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; +use Rector\DeadCode\Rector\MethodCall\RemoveNullArgOnNullDefaultParamRector; +use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector; +use Rector\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector; +use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector; +use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveDeadInstanceOfAssertRector; +use Rector\DeadCode\Rector\Ternary\RemoveUselessTernaryRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; +use Rector\Php56\Rector\FuncCall\PowToExpRector; +use Rector\Php73\Rector\FuncCall\ArrayKeyFirstLastRector; +use Rector\Php73\Rector\FuncCall\SetCookieRector; +use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; +use Rector\Php73\Rector\String_\SensitiveHereNowDocRector; use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; -use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; -use Rector\Php80\Rector\Class_\StringableForToStringRector; +use Rector\Php74\Rector\Property\RestoreDefaultNullToNullableTypePropertyRector; +use Rector\Php80\Rector\FuncCall\ClassOnObjectRector; +use Rector\Php80\Rector\NotIdentical\MbStrContainsRector; +use Rector\Php81\Rector\Property\ReadOnlyPropertyRector; use Rector\Set\ValueObject\SetList; -use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; +use Rector\TypeDeclaration\Rector\ArrowFunction\AddArrowFunctionReturnTypeRector; +use Rector\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector; +use Rector\TypeDeclaration\Rector\Class_\TypedPropertyFromCreateMockAssignRector; +use Rector\TypeDeclaration\Rector\ClassMethod\AddParamStringTypeFromSprintfUseRector; +use Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeBasedOnPHPUnitDataProviderRector; +use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ArrayParamTypeByMethodCallTypeRector; +use Rector\TypeDeclaration\Rector\ClassMethod\BoolReturnTypeFromBooleanConstReturnsRector; use Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeByMethodCallTypeRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictFluentReturnRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector; -use Rector\TypeDeclaration\Rector\Function_\AddFunctionVoidReturnTypeWhereNoReturnRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ReturnUnionTypeRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ScalarParamTypeByMethodCallTypeRector; +use Rector\TypeDeclaration\Rector\ClassMethod\StrictArrayParamDimFetchRector; +use Rector\TypeDeclaration\Rector\Closure\AddClosureNeverReturnTypeRector; +use Rector\TypeDeclaration\Rector\Closure\ClosureReturnTypeFromAssertInstanceOfRector; +use Rector\TypeDeclaration\Rector\Closure\ClosureReturnTypeRector; +use Rector\TypeDeclaration\Rector\FunctionLike\AddClosureParamTypeForArrayMapRector; +use Rector\TypeDeclaration\Rector\FunctionLike\AddClosureParamTypeFromVariableCallRector; +use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector; +use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector; +use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictSetUpRector; +use Rector\TypeDeclaration\Rector\StmtsAwareInterface\SafeDeclareStrictTypesRector; +use Rector\TypeDeclaration\Rector\While_\WhileNullableToInstanceofRector; $cacheDir = getenv('RECTOR_CACHE_DIR') ?: sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'rector'; @@ -46,36 +112,115 @@ SetList::CODE_QUALITY, SetList::CODING_STYLE, SetList::DEAD_CODE, - SetList::EARLY_RETURN, - SetList::INSTANCEOF, SetList::TYPE_DECLARATION, ]) ->withSkip([ + __DIR__ . '/tests/test_app/templates', + __DIR__ . '/tests/test_app/Plugin/TestBake/templates', + __DIR__ . '/tests/test_app/Plugin/TestBakeTheme/templates', __DIR__ . '/tests/comparisons', - __DIR__ . '/tests/test_app', - ClassPropertyAssignToConstructorPromotionRector::class, + ThrowWithPreviousExceptionRector::class, + ExplicitReturnNullRector::class, + OptionalParametersAfterRequiredRector::class, + CompleteDynamicPropertiesRector::class, + ForeachToInArrayRector::class, + CompactToVariablesRector::class, + FlipTypeControlToUseExclusiveTypeRector::class, + ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, + SimplifyIfReturnBoolRector::class, + AbsolutizeRequireAndIncludePathRector::class, + IssetOnPropertyObjectToPropertyExistsRector::class, CatchExceptionNameMatchingTypeRector::class, - ClosureToArrowFunctionRector::class, + CatchExceptionNameMatchingTypeRector::class, + MakeInheritedMethodVisibilitySameAsParentRector::class, + NewlineBeforeNewAssignSetRector::class, + StrictArraySearchRector::class, + VersionCompareFuncCallToConstantRector::class, + FunctionFirstClassCallableRector::class, + NewlineAfterStatementRector::class, + UseClassKeywordForClassNameResolutionRector::class, + RemoveDoubleAssignRector::class, + RemoveUnusedVariableAssignRector::class, + RecastingRemovalRector::class, + RemoveEmptyClassMethodRector::class, + RemoveNullTagValueNodeRector::class, + RemoveUnusedConstructorParamRector::class, + RemoveUnusedPrivateMethodRector::class, + RemoveUselessParamTagRector::class, RemoveUselessReturnTagRector::class, + RemovePhpVersionIdCheckRector::class, + RemoveDeadStmtRector::class, + RemoveDeadIfForeachForRector::class, + RemoveDeadLoopRector::class, + RemoveAlwaysTrueIfConditionRector::class, + RemoveDeadInstanceOfRector::class, + UnwrapFutureCompatibleIfPhpVersionRector::class, + RemoveNullArgOnNullDefaultParamRector::class => [ + __DIR__ . '/tests/TestCase/Database/Expression/QueryExpressionTest.php', + ], + RemoveNonExistingVarAnnotationRector::class, + RemoveUselessVarTagRector::class, + PowToExpRector::class, + ArrayKeyFirstLastRector::class, + SetCookieRector::class, + StringifyStrNeedlesRector::class, + SensitiveHereNowDocRector::class, + ClosureToArrowFunctionRector::class, + ReadOnlyPropertyRector::class, + AddArrowFunctionReturnTypeRector::class, + BinaryOpNullableToInstanceofRector::class, + NewlineBetweenClassLikeStmtsRector::class, + AddParamStringTypeFromSprintfUseRector::class, + AddParamTypeBasedOnPHPUnitDataProviderRector::class, + AddVoidReturnTypeWhereNoReturnRector::class, + BoolReturnTypeFromBooleanConstReturnsRector::class, + ParamTypeByMethodCallTypeRector::class, + ReturnNeverTypeRector::class, + ReturnTypeFromMockObjectRector::class, ReturnTypeFromStrictFluentReturnRector::class, - NewlineAfterStatementRector::class, - StringClassNameToClassConstantRector::class, ReturnTypeFromStrictTypedCallRector::class, - ParamTypeByMethodCallTypeRector::class, - AddFunctionVoidReturnTypeWhereNoReturnRector::class, - StringableForToStringRector::class, - CompactToVariablesRector::class, - SplitDoubleAssignRector::class, - ChangeOrIfContinueToMultiContinueRector::class, - ExplicitBoolCompareRector::class, - NewlineBeforeNewAssignSetRector::class, - SimplifyEmptyCheckOnEmptyArrayRector::class, - DisallowedEmptyRuleFixerRector::class, - EncapsedStringsToSprintfRector::class, + ReturnUnionTypeRector::class, + StrictArrayParamDimFetchRector::class, + TypedPropertyFromCreateMockAssignRector::class, + AddClosureNeverReturnTypeRector::class, + ClosureReturnTypeRector::class, + TypedPropertyFromAssignsRector::class, + TypedPropertyFromStrictConstructorRector::class, + TypedPropertyFromStrictSetUpRector::class, + WhileNullableToInstanceofRector::class, + RestoreDefaultNullToNullableTypePropertyRector::class, - // these causes problems with the testsuite - UseClassKeywordForClassNameResolutionRector::class, - FunctionFirstClassCallableRector::class, + // Manual - only appliable for part of the code + UseIdenticalOverEqualWithSameTypeRector::class, + RemoveDeadStmtRector::class, + StringClassNameToClassConstantRector::class, + ArrayKeyFirstLastRector::class, + ClassOnObjectRector::class, + + // Newly aggressive in rector 2.4 - keep the bump behavior-neutral: + // adds declare(strict_types=1) to test fixtures/config (out of scope here), + SafeDeclareStrictTypesRector::class, + // and rewrites `$x ?: []` in ways that can change behavior on undefined/empty values. + RemoveUselessTernaryRector::class, + + // New in rector 2.5 - skipped to keep the version bump behavior-neutral. + // Together these touch ~226 files, mostly docblock removal. Whether to apply + // them is a separate decision from getting CI green again. + NegatedAndsToPositiveOrsRector::class, + FixClassCaseSensitivityVarDocblockRector::class, + RemoveDuplicatedReturnSelfDocblockRector::class, + RemoveMixedDocblockOverruledByNativeTypeRector::class, + RemoveParentDelegatingClassMethodRector::class, + RemoveReturnTagIncompatibleWithNativeTypeRector::class, + RemoveUselessUnionReturnDocblockRector::class, + RemoveDefaultValueFromAssignedPropertyRector::class, + RemoveDeadInstanceOfAssertRector::class, + MbStrContainsRector::class, + ArrayParamTypeByMethodCallTypeRector::class, + ScalarParamTypeByMethodCallTypeRector::class, + ClosureReturnTypeFromAssertInstanceOfRector::class, + AddClosureParamTypeForArrayMapRector::class, + AddClosureParamTypeFromVariableCallRector::class, ]); diff --git a/src/CodeGen/ClassBuilder.php b/src/CodeGen/ClassBuilder.php index 68e481e68..8bc28ef0d 100644 --- a/src/CodeGen/ClassBuilder.php +++ b/src/CodeGen/ClassBuilder.php @@ -18,14 +18,11 @@ class ClassBuilder { - protected ?ParsedClass $parsedClass; - /** * @param \Bake\CodeGen\ParsedClass $parsedClass Parsed class it already exists */ - public function __construct(?ParsedClass $parsedClass = null) + public function __construct(protected ?ParsedClass $parsedClass = null) { - $this->parsedClass = $parsedClass; } /** diff --git a/src/CodeGen/CodeParser.php b/src/CodeGen/CodeParser.php index 23abd5e01..071f0f9dc 100644 --- a/src/CodeGen/CodeParser.php +++ b/src/CodeGen/CodeParser.php @@ -16,6 +16,7 @@ */ namespace Bake\CodeGen; +use PhpParser\Comment\Doc; use PhpParser\Error; use PhpParser\Node; use PhpParser\Node\Identifier; @@ -60,7 +61,7 @@ class CodeParser extends NodeVisitorAbstract public function __construct() { $version = PhpVersion::fromComponents(8, 1); - $this->parser = (new ParserFactory())->createForVersion($version); + $this->parser = new ParserFactory()->createForVersion($version); $this->traverser = new NodeTraverser(); $this->traverser->addVisitor($this); } @@ -223,7 +224,7 @@ protected function getNodeCode(NodeAbstract $node): string { $code = ''; - $doc = $node->getDocComment() ? $node->getDocComment()->getText() : ''; + $doc = $node->getDocComment() instanceof Doc ? $node->getDocComment()->getText() : ''; if ($doc) { $code = static::INDENT . $doc . "\n"; } diff --git a/src/CodeGen/ColumnTypeExtractor.php b/src/CodeGen/ColumnTypeExtractor.php index 074cd530c..eaa88d8b3 100644 --- a/src/CodeGen/ColumnTypeExtractor.php +++ b/src/CodeGen/ColumnTypeExtractor.php @@ -18,8 +18,15 @@ use Exception; use PhpParser\Node; +use PhpParser\Node\Arg; +use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; +use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; @@ -49,11 +56,11 @@ class ColumnTypeExtractor extends NodeVisitorAbstract public function __construct() { $version = PhpVersion::fromComponents(8, 1); - $this->parser = (new ParserFactory())->createForVersion($version); + $this->parser = new ParserFactory()->createForVersion($version); } /** - * Extracts column type mappings from initialize method code + * Extracts column type mappings from existing Table class initialize methods * * @param string $code The initialize method code * @return array Map of column names to type expressions @@ -88,7 +95,7 @@ public function extract(string $code): array public function enterNode(Node $node) { // Check if we're entering the initialize method - if ($node instanceof Node\Stmt\ClassMethod && $node->name->name === 'initialize') { + if ($node instanceof ClassMethod && $node->name->name === 'initialize') { $this->inInitialize = true; return null; @@ -114,7 +121,7 @@ public function enterNode(Node $node) */ public function leaveNode(Node $node) { - if ($node instanceof Node\Stmt\ClassMethod && $node->name->name === 'initialize') { + if ($node instanceof ClassMethod && $node->name->name === 'initialize') { $this->inInitialize = false; } @@ -129,7 +136,7 @@ public function leaveNode(Node $node) */ protected function processMethodCall(MethodCall $methodCall): void { - $isSetColumnTypeCall = $methodCall->name instanceof Node\Identifier + $isSetColumnTypeCall = $methodCall->name instanceof Identifier && $methodCall->name->name === 'setColumnType'; $schemaCall = $methodCall->var; $isSchemaMethodCall = $schemaCall instanceof MethodCall; @@ -139,7 +146,7 @@ protected function processMethodCall(MethodCall $methodCall): void return; } - $isGetSchemaCall = $schemaCall->name instanceof Node\Identifier + $isGetSchemaCall = $schemaCall->name instanceof Identifier && $schemaCall->name->name === 'getSchema'; $isCalledOnThis = $schemaCall->var instanceof Variable && $schemaCall->var->name === 'this'; @@ -150,7 +157,7 @@ protected function processMethodCall(MethodCall $methodCall): void $columnArgNode = $methodCall->args[0]; $typeArgNode = $methodCall->args[1]; - if (!$columnArgNode instanceof Node\Arg || !$typeArgNode instanceof Node\Arg) { + if (!$columnArgNode instanceof Arg || !$typeArgNode instanceof Arg) { return; } @@ -176,7 +183,7 @@ protected function processMethodCall(MethodCall $methodCall): void */ protected function getStringValue(Node $node): ?string { - if ($node instanceof Node\Scalar\String_) { + if ($node instanceof String_) { return $node->value; } @@ -191,13 +198,13 @@ protected function getStringValue(Node $node): ?string */ protected function getTypeExpression(Node $node): ?string { - if ($node instanceof Node\Expr\StaticCall) { + if ($node instanceof StaticCall) { $staticCall = $node; $calledClass = $staticCall->class; $calledMethod = $staticCall->name; - $hasNamedClass = $calledClass instanceof Node\Name; - $hasIdentifierMethod = $calledMethod instanceof Node\Identifier; + $hasNamedClass = $calledClass instanceof Name; + $hasIdentifierMethod = $calledMethod instanceof Identifier; if (!$hasNamedClass || !$hasIdentifierMethod) { return null; } @@ -212,19 +219,19 @@ protected function getTypeExpression(Node $node): ?string } $argNode = $staticCall->args[0]; - if (!$argNode instanceof Node\Arg) { + if (!$argNode instanceof Arg) { return null; } $arg = $argNode->value; - if (!$arg instanceof Node\Expr\ClassConstFetch) { + if (!$arg instanceof ClassConstFetch) { return null; } $enumClassNode = $arg->class; $constantName = $arg->name; - $hasNamedEnumClass = $enumClassNode instanceof Node\Name; - $isClassConstant = $constantName instanceof Node\Identifier + $hasNamedEnumClass = $enumClassNode instanceof Name; + $isClassConstant = $constantName instanceof Identifier && $constantName->name === 'class'; if (!$hasNamedEnumClass || !$isClassConstant) { return null; @@ -235,7 +242,7 @@ protected function getTypeExpression(Node $node): ?string return 'EnumType::from(' . $enumClass . '::class)'; } - if ($node instanceof Node\Scalar\String_) { + if ($node instanceof String_) { return '"' . $node->value . '"'; } diff --git a/src/CodeGen/FileBuilder.php b/src/CodeGen/FileBuilder.php index ece3c8b11..3f8de9f99 100644 --- a/src/CodeGen/FileBuilder.php +++ b/src/CodeGen/FileBuilder.php @@ -16,12 +16,10 @@ */ namespace Bake\CodeGen; -use Cake\Console\ConsoleIo; +use Cake\Console\ConsoleIoInterface; class FileBuilder { - protected ConsoleIo $io; - protected string $namespace; protected ?ParsedFile $parsedFile; @@ -29,11 +27,11 @@ class FileBuilder protected ClassBuilder $classBuilder; /** - * @param \Cake\Console\ConsoleIo $io Console io + * @param \Cake\Console\ConsoleIoInterface $io Console io * @param string $namespace File namespace * @param \Bake\CodeGen\ParsedFile $parsedFile Parsed file it already exists */ - public function __construct(ConsoleIo $io, string $namespace, ?ParsedFile $parsedFile = null) + public function __construct(protected ConsoleIoInterface $io, string $namespace, ?ParsedFile $parsedFile = null) { if ($parsedFile instanceof ParsedFile && $parsedFile->namespace !== $namespace) { throw new ParseException(sprintf( @@ -42,8 +40,6 @@ public function __construct(ConsoleIo $io, string $namespace, ?ParsedFile $parse $namespace, )); } - - $this->io = $io; $this->namespace = $namespace; $this->parsedFile = $parsedFile; $this->classBuilder = new ClassBuilder($parsedFile->class ?? null); diff --git a/src/CodeGen/ImportHelper.php b/src/CodeGen/ImportHelper.php index 40308c90d..92aaee645 100644 --- a/src/CodeGen/ImportHelper.php +++ b/src/CodeGen/ImportHelper.php @@ -16,7 +16,7 @@ */ namespace Bake\CodeGen; -use Cake\Console\ConsoleIo; +use Cake\Console\ConsoleIoInterface; class ImportHelper { @@ -46,15 +46,15 @@ public static function normalize(array $imports): array * * @param array $existing Existing imports to merge into * @param array $imports Imports to merge into existing - * @param \Cake\Console\ConsoleIo|null $io Used to output warnings on collisions + * @param \Cake\Console\ConsoleIoInterface|null $io Used to output warnings on collisions * @return array */ - public static function merge(array $existing, array $imports, ?ConsoleIo $io = null): array + public static function merge(array $existing, array $imports, ?ConsoleIoInterface $io = null): array { $existing = static::normalize($existing); foreach (static::normalize($imports) as $alias => $class) { if (isset($existing[$alias]) && $existing[$alias] !== $class) { - if ($io instanceof ConsoleIo) { + if ($io !== null) { $io->warning(sprintf( 'Import `%s` conflicts with existing import, discarding.', $class, @@ -65,7 +65,7 @@ public static function merge(array $existing, array $imports, ?ConsoleIo $io = n $existingAlias = array_search($class, $existing, true); if ($existingAlias !== false && $existingAlias !== $alias) { - if ($io instanceof ConsoleIo) { + if ($io !== null) { $io->warning(sprintf( 'Import `%s` conflicts with existing import, discarding.', $class, diff --git a/src/CodeGen/ParsedClass.php b/src/CodeGen/ParsedClass.php index 28cad4ded..cbc5e900c 100644 --- a/src/CodeGen/ParsedClass.php +++ b/src/CodeGen/ParsedClass.php @@ -21,28 +21,6 @@ */ class ParsedClass { - public string $name; - - /** - * @var array - */ - public array $implements; - - /** - * @var array - */ - public array $constants; - - /** - * @var array - */ - public array $properties; - - /** - * @var array - */ - public array $methods; - /** * @param string $name Class name * @param array $implements List of implements @@ -50,12 +28,12 @@ class ParsedClass * @param array $properties Class properties * @param array $methods Class methods */ - public function __construct(string $name, array $implements, array $constants, array $properties, array $methods) - { - $this->name = $name; - $this->implements = $implements; - $this->constants = $constants; - $this->properties = $properties; - $this->methods = $methods; + public function __construct( + public string $name, + public array $implements, + public array $constants, + public array $properties, + public array $methods, + ) { } } diff --git a/src/CodeGen/ParsedFile.php b/src/CodeGen/ParsedFile.php index 185032bf6..68f03b1fd 100644 --- a/src/CodeGen/ParsedFile.php +++ b/src/CodeGen/ParsedFile.php @@ -21,25 +21,6 @@ */ class ParsedFile { - public string $namespace; - - /** - * @var array - */ - public array $classImports; - - /** - * @var array - */ - public array $functionImports; - - /** - * @var array - */ - public array $constImports; - - public ParsedClass $class; - /** * @param string $namespace Namespace * @param array $classImports Class imports @@ -48,16 +29,11 @@ class ParsedFile * @param \Bake\CodeGen\ParsedClass $class Parsed class */ public function __construct( - string $namespace, - array $classImports, - array $functionImports, - array $constImports, - ParsedClass $class, + public string $namespace, + public array $classImports, + public array $functionImports, + public array $constImports, + public ParsedClass $class, ) { - $this->namespace = $namespace; - $this->classImports = $classImports; - $this->functionImports = $functionImports; - $this->constImports = $constImports; - $this->class = $class; } } diff --git a/src/Command/AllCommand.php b/src/Command/AllCommand.php index cd0a5993e..d2421b169 100644 --- a/src/Command/AllCommand.php +++ b/src/Command/AllCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; use Throwable; @@ -47,7 +46,7 @@ class AllCommand extends BakeCommand */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser = $parser->setDescription( 'Generate the model, controller, template, tests and fixture for a table.', @@ -68,44 +67,38 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $args->getArgument('name') ?? ''; - $name = $this->_getName($name); - - $io->out('Bake All'); - $io->hr(); - + $this->extractCommonProperties($this->args); + $name = $this->args->getArgument('name') ?? ''; + $name = $this->getNameWithoutPrefix($name); + $this->io->out('Bake All'); + $this->io->hr(); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); $tables = $scanner->removeShadowTranslationTables($scanner->listUnskipped()); - - if (!$name && !$args->getOption('everything')) { - $io->out('Choose a table to generate from the following:'); + if (!$name && !$this->args->getOption('everything')) { + $this->io->out('Choose a table to generate from the following:'); foreach ($tables as $table) { - $io->out('- ' . $this->_camelize($table)); + $this->io->out('- ' . $this->camelize($table)); } return static::CODE_SUCCESS; } - if (!$args->getOption('everything')) { + if (!$this->args->getOption('everything')) { $tables = [$name]; } - $errors = 0; foreach ($this->commands as $commandName) { - /** @var \Cake\Command\Command $command */ - $command = new $commandName(); + /** @var \Bake\Command\BakeCommand $command */ + $command = new $commandName($this->factory); - $options = $args->getOptions(); + $options = $this->args->getOptions(); if ( - $args->hasOption('prefix') && + $this->args->hasOption('prefix') && !($command instanceof ControllerCommand) && !($command instanceof TemplateCommand) ) { @@ -116,24 +109,26 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $parser = $command->getOptionParser(); $subArgs = new Arguments([$table], $options, $parser->argumentNames()); + $command->setIo($this->io); + $command->setArgs($subArgs); + try { - $command->execute($subArgs, $io); + $command->execute(); } catch (Throwable $e) { - if (!$args->getOption('everything') || !$args->getOption('force')) { + if (!$this->args->getOption('everything') || !$this->args->getOption('force')) { throw $e; } $message = sprintf('Error generating %s for %s: %s', $commandName, $table, $e->getMessage()); - $io->error($message); + $this->io->error($message); $errors++; } } } - if ($errors) { - $io->warning(sprintf('Bake All completed, but with %s errors.', $errors)); + $this->io->warning(sprintf('Bake All completed, but with %s errors.', $errors)); } else { - $io->success('Bake All complete.'); + $this->io->success('Bake All complete.'); } return $errors ? static::CODE_ERROR : static::CODE_SUCCESS; diff --git a/src/Command/BakeCommand.php b/src/Command/BakeCommand.php index 1c783b2e6..77de8da91 100644 --- a/src/Command/BakeCommand.php +++ b/src/Command/BakeCommand.php @@ -22,7 +22,7 @@ use Bake\Utility\TemplateRenderer; use Cake\Command\Command; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; +use Cake\Console\ConsoleIoInterface; use Cake\Core\Configure; use Cake\Core\ConventionsTrait; use Cake\Event\Event; @@ -82,6 +82,17 @@ public static function defaultName(): string return 'bake ' . $name; } + /** + * Set arguments + * + * @param \Cake\Console\Arguments $args Arguments to set + * @return void + */ + public function setArgs(Arguments $args): void + { + $this->args = $args; + } + /** * Handles splitting up the plugin prefix and classname. * @@ -90,7 +101,7 @@ public static function defaultName(): string * @param string $name The name to possibly split. * @return string The name without the plugin prefix. */ - protected function _getName(string $name): string + protected function getNameWithoutPrefix(string $name): string { if (strpos($name, '.')) { [$plugin, $name] = pluginSplit($name); @@ -105,35 +116,33 @@ protected function _getName(string $name): string * * Handles camelcasing each namespace in the prefix path. * - * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. * @return string The inflected prefix path. */ - protected function getPrefix(Arguments $args): string + protected function getPrefix(): string { /** @var string|null $prefix */ - $prefix = $args->getOption('prefix'); + $prefix = $this->args->getOption('prefix'); if (!$prefix) { return ''; } $parts = explode('/', $prefix); - return implode('/', array_map($this->_camelize(...), $parts)); + return implode('/', array_map($this->camelize(...), $parts)); } /** * Gets the path for output. Checks the plugin property * and returns the correct path. * - * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. * @return string Path to output. */ - public function getPath(Arguments $args): string + public function getPath(): string { $path = APP . $this->pathFragment; if ($this->plugin) { - $path = $this->_pluginPath($this->plugin) . 'src/' . $this->pathFragment; + $path = $this->pluginPath($this->plugin) . 'src/' . $this->pathFragment; } - $prefix = $this->getPrefix($args); + $prefix = $this->getPrefix(); if ($prefix) { $path .= $prefix . DIRECTORY_SEPARATOR; } @@ -144,14 +153,13 @@ public function getPath(Arguments $args): string /** * Gets the path to the template path for the application or plugin. * - * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. * @param string|null $container The container directory in the templates directory. * @return string Path to output. */ - public function getTemplatePath(Arguments $args, ?string $container = null): string + public function getTemplatePath(?string $container = null): string { $paths = (array)Configure::read('App.paths.templates'); - if (empty($paths)) { + if ($paths === []) { throw new InvalidArgumentException( 'Could not read template paths. ' . 'Ensure `App.paths.templates` is defined in your application configuration.', @@ -159,12 +167,12 @@ public function getTemplatePath(Arguments $args, ?string $container = null): str } $path = $paths[0]; if ($this->plugin) { - $path = $this->_pluginPath($this->plugin) . 'templates' . DIRECTORY_SEPARATOR; + $path = $this->pluginPath($this->plugin) . 'templates' . DIRECTORY_SEPARATOR; } if ($container) { $path .= $container . DIRECTORY_SEPARATOR; } - $prefix = $this->getPrefix($args); + $prefix = $this->getPrefix(); if ($prefix) { $path .= $prefix . DIRECTORY_SEPARATOR; } @@ -189,14 +197,13 @@ public function createTemplateRenderer(): TemplateRenderer * Delete empty file in a given path * * @param string $path Path to folder which contains 'empty' file. - * @param \Cake\Console\ConsoleIo $io ConsoleIo to delete file with. * @return void */ - protected function deleteEmptyFile(string $path, ConsoleIo $io): void + protected function deleteEmptyFile(string $path): void { if (file_exists($path)) { unlink($path); - $io->out(sprintf('Deleted `%s`', $path)); + $this->io->out(sprintf('Deleted `%s`', $path)); } } @@ -229,7 +236,7 @@ protected function parseFile(string $path): ?ParsedFile return null; } - return (new CodeParser())->parseFile($contents); + return new CodeParser()->parseFile($contents); } return null; @@ -238,7 +245,7 @@ protected function parseFile(string $path): ?ParsedFile /** * Write file contents out to path and prompt user with options with file exists. * - * @param \Cake\Console\ConsoleIo $io Console io + * @param \Cake\Console\ConsoleIoInterface $io The console io * @param string $path The path to create the file at * @param string $contents The contents to put into the file * @param bool $forceOverwrite Whether the file should be overwritten without prompting the user @@ -248,7 +255,7 @@ protected function parseFile(string $path): ?ParsedFile * to whether a file should be overwritten. */ protected function writeFile( - ConsoleIo $io, + ConsoleIoInterface $io, string $path, string $contents, bool $forceOverwrite = false, diff --git a/src/Command/CellCommand.php b/src/Command/CellCommand.php index e1521a8d3..401ba74a0 100644 --- a/src/Command/CellCommand.php +++ b/src/Command/CellCommand.php @@ -16,8 +16,6 @@ */ namespace Bake\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; @@ -66,19 +64,18 @@ public function template(): string /** * Get template data. * - * @param \Cake\Console\Arguments $arguments Arguments object. * @return array */ - public function templateData(Arguments $arguments): array + public function templateData(): array { - $prefix = $this->getPrefix($arguments); + $prefix = $this->getPrefix(); if ($prefix) { $prefix = '\\' . str_replace('/', '\\', $prefix); } $namespace = Configure::read('App.namespace'); if ($this->plugin) { - $namespace = $this->_pluginNamespace($this->plugin); + $namespace = $this->pluginNamespace($this->plugin); } return compact('namespace', 'prefix'); @@ -88,31 +85,27 @@ public function templateData(Arguments $arguments): array * Bake the Cell class and template file. * * @param string $name The name of the cell to make. - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function bake(string $name, Arguments $args, ConsoleIo $io): void + protected function bake(string $name): void { - $this->bakeTemplate($name, $args, $io); + $this->bakeTemplate($name); - parent::bake($name, $args, $io); + parent::bake($name); } /** * Bake an empty file for a cell. * * @param string $name The name of the cell a template is needed for. - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function bakeTemplate(string $name, Arguments $args, ConsoleIo $io): void + protected function bakeTemplate(string $name): void { - $path = $this->getTemplatePath($args, 'cell'); + $path = $this->getTemplatePath('cell'); $path .= implode(DS, [$name, 'display.php']); - $io->createFile($path, '', $this->force); + $this->io->createFile($path, '', $this->force); } /** diff --git a/src/Command/CommandCommand.php b/src/Command/CommandCommand.php index d2aac4ac7..3b4f460e6 100644 --- a/src/Command/CommandCommand.php +++ b/src/Command/CommandCommand.php @@ -16,7 +16,6 @@ */ namespace Bake\Command; -use Cake\Console\Arguments; use Cake\Utility\Inflector; /** @@ -64,17 +63,16 @@ public function template(): string /** * Get template data. * - * @param \Cake\Console\Arguments $arguments Arguments object. * @return array */ - public function templateData(Arguments $arguments): array + public function templateData(): array { - $data = parent::templateData($arguments); + $data = parent::templateData(); $data['command_name'] = Inflector::underscore(str_replace( '.', ' ', - $arguments->getArgument('name') ?? '', + $this->args->getArgument('name') ?? '', )); return $data; diff --git a/src/Command/ControllerAllCommand.php b/src/Command/ControllerAllCommand.php index eb4a17877..ac3b0bdda 100644 --- a/src/Command/ControllerAllCommand.php +++ b/src/Command/ControllerAllCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; use Cake\ORM\Locator\LocatorAwareTrait; @@ -51,21 +50,20 @@ public static function defaultName(): string /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - + $this->extractCommonProperties($this->args); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); foreach ($scanner->listUnskipped() as $table) { $this->getTableLocator()->clear(); - $controllerArgs = new Arguments([$table], $args->getOptions(), ['name']); - $this->controllerCommand->execute($controllerArgs, $io); + $controllerArgs = new Arguments([$table], $this->args->getOptions(), ['name']); + $this->controllerCommand->setArgs($controllerArgs); + $this->controllerCommand->setIo($this->io); + $this->controllerCommand->execute(); } return static::CODE_SUCCESS; diff --git a/src/Command/ControllerCommand.php b/src/Command/ControllerCommand.php index 967a5ece6..544d406ee 100644 --- a/src/Command/ControllerCommand.php +++ b/src/Command/ControllerCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; use Cake\Core\Plugin; @@ -45,30 +44,26 @@ public static function getDescription(): string /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $args->getArgument('name') ?? ''; - $name = $this->_getName($name); - + $this->extractCommonProperties($this->args); + $name = $this->args->getArgument('name') ?? ''; + $name = $this->getNameWithoutPrefix($name); if (empty($name)) { /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); - $io->out('Possible controllers based on your current database:'); + $this->io->out('Possible controllers based on your current database:'); foreach ($scanner->listUnskipped() as $table) { - $io->out('- ' . $this->_camelize($table)); + $this->io->out('- ' . $this->camelize($table)); } return static::CODE_SUCCESS; } - - $controller = $this->_camelize($name); - $this->bake($controller, $args, $io); + $controller = $this->camelize($name); + $this->bake($controller); return static::CODE_SUCCESS; } @@ -77,38 +72,36 @@ public function execute(Arguments $args, ConsoleIo $io): ?int * Assembles and writes a Controller file * * @param string $controllerName Controller name already pluralized and correctly cased. - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - public function bake(string $controllerName, Arguments $args, ConsoleIo $io): void + public function bake(string $controllerName): void { - $io->quiet(sprintf('Baking controller class for %s...', $controllerName)); + $this->io->quiet(sprintf('Baking controller class for %s...', $controllerName)); $actions = []; - if (!$args->getOption('no-actions') && !$args->getOption('actions')) { + if (!$this->args->getOption('no-actions') && !$this->args->getOption('actions')) { $actions = ['index', 'view', 'add', 'edit', 'delete']; } - if ($args->getOption('actions')) { - $actions = array_map('trim', explode(',', (string)$args->getOption('actions'))); + if ($this->args->getOption('actions')) { + $actions = array_map('trim', explode(',', (string)$this->args->getOption('actions'))); $actions = array_filter($actions); } - if (!$args->getOption('actions') && Plugin::isLoaded('Authentication') && $controllerName === 'Users') { + if (!$this->args->getOption('actions') && Plugin::isLoaded('Authentication') && $controllerName === 'Users') { $actions[] = 'login'; } - $helpers = $this->getHelpers($args); - $components = $this->getComponents($args); + $helpers = $this->getHelpers(); + $components = $this->getComponents(); - $prefix = $this->getPrefix($args); + $prefix = $this->getPrefix(); if ($prefix) { $prefix = '\\' . str_replace('/', '\\', $prefix); } - // Controllers default to importing AppController from `App` - $baseNamespace = $namespace = Configure::read('App.namespace'); + $baseNamespace = Configure::read('App.namespace'); + $namespace = $baseNamespace; if ($this->plugin) { - $namespace = $this->_pluginNamespace($this->plugin); + $namespace = $this->pluginNamespace($this->plugin); } // If the plugin has an AppController other plugin controllers // should inherit from it. @@ -131,10 +124,10 @@ public function bake(string $controllerName, Arguments $args, ConsoleIo $io): vo ]); } - $pluralName = $this->_variableName($currentModelName); - $singularName = $this->_singularName($currentModelName); - $singularHumanName = $this->_singularHumanName($controllerName); - $pluralHumanName = $this->_variableName($controllerName); + $pluralName = $this->variableName($currentModelName); + $singularName = $this->singularName($currentModelName); + $singularHumanName = $this->singularHumanName($controllerName); + $pluralHumanName = $this->variableName($controllerName); // Handle cases where singular and plural are identical (e.g., "news", "sheep") // to avoid variable collisions in generated controller code @@ -146,7 +139,7 @@ public function bake(string $controllerName, Arguments $args, ConsoleIo $io): vo if (!class_exists($defaultModel)) { $defaultModel = null; } - $entityClassName = $this->_entityName($modelObj->getAlias()); + $entityClassName = $this->entityName($modelObj->getAlias()); $data = compact( 'actions', @@ -167,8 +160,8 @@ public function bake(string $controllerName, Arguments $args, ConsoleIo $io): vo ); $data['name'] = $controllerName; - $this->bakeController($controllerName, $data, $args, $io); - $this->bakeTest($controllerName, $args, $io); + $this->bakeController($controllerName, $data); + $this->bakeTest($controllerName); } /** @@ -176,11 +169,9 @@ public function bake(string $controllerName, Arguments $args, ConsoleIo $io): vo * * @param string $controllerName The name of the controller. * @param array $data The data to turn into code. - * @param \Cake\Console\Arguments $args The console args - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - public function bakeController(string $controllerName, array $data, Arguments $args, ConsoleIo $io): void + public function bakeController(string $controllerName, array $data): void { $data += [ 'name' => null, @@ -197,44 +188,43 @@ public function bakeController(string $controllerName, array $data, Arguments $a ->set($data) ->generate('Bake.Controller/controller'); - $path = $this->getPath($args); + $path = $this->getPath(); $filename = $path . $controllerName . 'Controller.php'; - $io->createFile($filename, $contents, $this->force); + $this->io->createFile($filename, $contents, $this->force); } /** * Assembles and writes a unit test file * * @param string $className Controller class name - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + public function bakeTest(string $className): void { - if ($args->getOption('no-test')) { + if ($this->args->getOption('no-test')) { return; } $test = new TestCommand(); $testArgs = new Arguments( ['controller', $className], - $args->getOptions(), + $this->args->getOptions(), ['type', 'name'], ); - $test->execute($testArgs, $io); + $test->setArgs($testArgs); + $test->setIo($this->io); + $test->execute(); } /** * Get the list of components for the controller. * - * @param \Cake\Console\Arguments $args The console arguments * @return array */ - public function getComponents(Arguments $args): array + public function getComponents(): array { $components = []; - if ($args->getOption('components')) { - $components = explode(',', (string)$args->getOption('components')); + if ($this->args->getOption('components')) { + $components = explode(',', (string)$this->args->getOption('components')); $components = array_values(array_filter(array_map('trim', $components))); } elseif (Plugin::isLoaded('Authorization')) { $components[] = 'Authorization.Authorization'; @@ -246,14 +236,13 @@ public function getComponents(Arguments $args): array /** * Get the list of helpers for the controller. * - * @param \Cake\Console\Arguments $args The console arguments * @return array */ - public function getHelpers(Arguments $args): array + public function getHelpers(): array { $helpers = []; - if ($args->getOption('helpers')) { - $helpers = explode(',', (string)$args->getOption('helpers')); + if ($this->args->getOption('helpers')) { + $helpers = explode(',', (string)$this->args->getOption('helpers')); $helpers = array_values(array_filter(array_map('trim', $helpers))); } @@ -268,7 +257,7 @@ public function getHelpers(Arguments $args): array */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser->setDescription( 'Bake a controller skeleton.', )->addArgument('name', [ diff --git a/src/Command/EntryCommand.php b/src/Command/EntryCommand.php index 11f69c546..f3557f9b6 100644 --- a/src/Command/EntryCommand.php +++ b/src/Command/EntryCommand.php @@ -17,11 +17,10 @@ namespace Bake\Command; use Cake\Command\Command; -use Cake\Console\Arguments; use Cake\Console\Command\HelpCommand; use Cake\Console\CommandCollection; use Cake\Console\CommandCollectionAwareInterface; -use Cake\Console\ConsoleIo; +use Cake\Console\ConsoleIoInterface; use Cake\Console\ConsoleOptionParser; use Cake\Console\Exception\ConsoleException; @@ -62,57 +61,63 @@ public function setCommandCollection(CommandCollection $commands): void * Override the run() method for special handling of the `--help` option. * * @param array $argv Arguments from the CLI environment. - * @param \Cake\Console\ConsoleIo $io The console io + * @param \Cake\Console\ConsoleIoInterface|null $io The console io + * instance if the default one shouldn't be used * @return int|null Exit code or null for success. */ - public function run(array $argv, ConsoleIo $io): ?int + public function run(array $argv, ?ConsoleIoInterface $io = null): ?int { - $this->initialize(); + if ($io !== null) { + $this->io = $io; + } $parser = $this->getOptionParser(); try { - [$options, $arguments] = $parser->parse($argv); - $args = new Arguments( - $arguments, - $options, - $parser->argumentNames(), - ); + $this->parseArguments($parser, $argv); } catch (ConsoleException $e) { - $io->error('Error: ' . $e->getMessage()); + $this->io->error('Error: ' . $e->getMessage()); return static::CODE_ERROR; } - $this->setOutputLevel($args, $io); + $this->setOutputLevel(); // This is the variance from Command::run() - if (!$args->getArgumentAt(0) && $args->getOption('help')) { - $this->executeCommand($this->help, [], $io); + if (!$this->args->getArgumentAt(0) && $this->args->getOption('help')) { + $this->executeCommand($this->help, []); return static::CODE_SUCCESS; } - return $this->execute($args, $io); + if ($this->args->getOption('quiet')) { + $this->io->setInteractive(false); + } + + $this->initialize(); + + $this->dispatchEvent('Command.beforeExecute', ['args' => $this->args, 'io' => $this->io]); + $result = $this->execute(); + $this->dispatchEvent('Command.afterExecute', ['args' => $this->args, 'io' => $this->io, 'result' => $result]); + + return $result; } /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - if ($args->hasArgumentAt(0)) { - $name = $args->getArgumentAt(0); - $io->error( + if ($this->args->hasArgumentAt(0)) { + $name = $this->args->getArgumentAt(0); + $this->io->error( "Could not find bake command named `{$name}`." . ' Run `bake --help` to get a list of commands.', ); return static::CODE_ERROR; } - $io->warning('No command provided. Run `bake --help` to get a list of commands.'); + $this->io->warning('No command provided. Run `bake --help` to get a list of commands.'); return static::CODE_ERROR; } diff --git a/src/Command/EnumCommand.php b/src/Command/EnumCommand.php index 09e0e97d3..550c88697 100644 --- a/src/Command/EnumCommand.php +++ b/src/Command/EnumCommand.php @@ -17,8 +17,6 @@ namespace Bake\Command; use Bake\Utility\Model\EnumParser; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Utility\Inflector; use InvalidArgumentException; @@ -68,11 +66,11 @@ public function template(): string /** * Get template data. * - * @param \Cake\Console\Arguments $arguments The arguments for the command * @return array */ - public function templateData(Arguments $arguments): array + public function templateData(): array { + $arguments = $this->args; $cases = EnumParser::parseCases($arguments->getArgument('cases'), (bool)$arguments->getOption('int')); $isOfTypeInt = $this->isOfTypeInt($cases); $backingType = $isOfTypeInt ? 'int' : 'string'; @@ -84,7 +82,7 @@ public function templateData(Arguments $arguments): array $backingType = 'int'; } - $data = parent::templateData($arguments); + $data = parent::templateData(); $data['backingType'] = $backingType; $data['cases'] = $this->formatCases($cases); @@ -99,7 +97,7 @@ public function templateData(Arguments $arguments): array */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser->setDescription( 'Bake backed enums for use in models.', @@ -123,17 +121,11 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption */ protected function isOfTypeInt(array $definition): bool { - if (!$definition) { + if ($definition === []) { return false; } - foreach ($definition as $value) { - if (!is_int($value)) { - return false; - } - } - - return true; + return array_all($definition, fn($value) => is_int($value)); } /** @@ -158,15 +150,13 @@ protected function formatCases(array $cases): array * Generate a class stub * * @param string $name The class name - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function bake(string $name, Arguments $args, ConsoleIo $io): void + protected function bake(string $name): void { - parent::bake($name, $args, $io); + parent::bake($name); - $path = $this->getPath($args); + $path = $this->getPath(); $filename = $path . $name . '.php'; // Work around composer caching that classes/files do not exist. diff --git a/src/Command/FixtureAllCommand.php b/src/Command/FixtureAllCommand.php index d5b691e72..e5b86a5fe 100644 --- a/src/Command/FixtureAllCommand.php +++ b/src/Command/FixtureAllCommand.php @@ -19,7 +19,6 @@ use Bake\Utility\CommonOptionsTrait; use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; @@ -54,7 +53,7 @@ public static function getDescription(): string */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser = $parser->setDescription( 'Generate all fixtures for use with the test suite.', @@ -82,23 +81,21 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - + $this->extractCommonProperties($this->args); /** @var \Cake\Database\Connection $connection */ - $connection = ConnectionManager::get((string)($args->getOption('connection') ?: 'default')); + $connection = ConnectionManager::get((string)($this->args->getOption('connection') ?: 'default')); $scanner = new TableScanner($connection); $fixture = new FixtureCommand(); - $tables = $scanner->removeShadowTranslationTables($scanner->listUnskipped()); foreach ($tables as $table) { - $fixtureArgs = new Arguments([$table], $args->getOptions(), ['name']); - $fixture->execute($fixtureArgs, $io); + $fixtureArgs = new Arguments([$table], $this->args->getOptions(), ['name']); + $fixture->setArgs($fixtureArgs); + $fixture->setIo($this->io); + $fixture->execute(); } return static::CODE_SUCCESS; diff --git a/src/Command/FixtureCommand.php b/src/Command/FixtureCommand.php index 405c25989..403ba8f2c 100644 --- a/src/Command/FixtureCommand.php +++ b/src/Command/FixtureCommand.php @@ -20,8 +20,6 @@ use Brick\VarExporter\VarExporter; use Cake\Chronos\Chronos; use Cake\Chronos\ChronosDate; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; use Cake\Core\Exception\CakeException; @@ -50,15 +48,14 @@ public static function getDescription(): string /** * Get the file path. * - * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. * @return string Path to output. */ - public function getPath(Arguments $args): string + public function getPath(): string { $dir = 'Fixture/'; $path = defined('TESTS') ? TESTS . $dir : ROOT . DS . 'tests' . DS . $dir; if ($this->plugin) { - $path = $this->_pluginPath($this->plugin) . 'tests/' . $dir; + $path = $this->pluginPath($this->plugin) . 'tests/' . $dir; } return str_replace('/', DS, $path); @@ -72,7 +69,7 @@ public function getPath(Arguments $args): string */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser = $parser->setDescription( 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.', @@ -108,31 +105,27 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $args->getArgument('name') ?? ''; - $name = $this->_getName($name); - + $this->extractCommonProperties($this->args); + $name = $this->args->getArgument('name') ?? ''; + $name = $this->getNameWithoutPrefix($name); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); if (empty($name)) { - $io->out('Choose a fixture to bake from the following:'); + $this->io->out('Choose a fixture to bake from the following:'); foreach ($scanner->listUnskipped() as $table) { - $io->out('- ' . $this->_camelize($table)); + $this->io->out('- ' . $this->camelize($table)); } return static::CODE_SUCCESS; } - - $table = (string)$args->getOption('table'); - $model = $this->_camelize($name); - $this->bake($model, $table, $args, $io); + $table = (string)$this->args->getOption('table'); + $model = $this->camelize($name); + $this->bake($model, $table); return static::CODE_SUCCESS; } @@ -142,15 +135,16 @@ public function execute(Arguments $args, ConsoleIo $io): ?int * * @param string $model Name of model to bake. * @param string $useTable Name of table to use. - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return void * @throws \RuntimeException */ - protected function bake(string $model, string $useTable, Arguments $args, ConsoleIo $io): void + protected function bake(string $model, string $useTable): void { - $table = $schema = $records = $import = $modelImport = null; - + $table = null; + $schema = null; + $records = null; + $import = null; + $modelImport = null; if (!$useTable) { $useTable = Inflector::tableize($model); } elseif ($useTable !== Inflector::tableize($model)) { @@ -158,14 +152,14 @@ protected function bake(string $model, string $useTable, Arguments $args, Consol } $importBits = []; - if ($args->getOption('schema')) { + if ($this->args->getOption('schema')) { $modelImport = true; $importBits[] = "'table' => '{$useTable}'"; } - if (!empty($importBits) && $this->connection !== 'default') { + if ($importBits !== [] && $this->connection !== 'default') { $importBits[] = "'connection' => '{$this->connection}'"; } - if (!empty($importBits)) { + if ($importBits !== []) { $import = sprintf('[%s]', implode(', ', $importBits)); } @@ -178,23 +172,23 @@ protected function bake(string $model, string $useTable, Arguments $args, Consol $data = $this->readSchema($model, $useTable); } - $this->validateNames($data, $io); + $this->validateNames($data); if ($modelImport === null) { - $schema = $this->_generateSchema($data); + $schema = $this->generateSchema($data); } - if ($args->getOption('records')) { - $records = $this->_makeRecordString($this->_getRecordsFromTable($args, $model, $useTable)); + if ($this->args->getOption('records')) { + $records = $this->makeRecordString($this->getRecordsFromTable($model, $useTable)); } else { $recordCount = 1; - if ($args->hasOption('count')) { - $recordCount = (int)$args->getOption('count'); + if ($this->args->hasOption('count')) { + $recordCount = (int)$this->args->getOption('count'); } - $records = $this->_makeRecordString($this->_generateRecords($data, $recordCount)); + $records = $this->makeRecordString($this->generateRecords($data, $recordCount)); } - $this->generateFixtureFile($args, $io, $model, compact('records', 'table', 'schema', 'import')); + $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import')); } /** @@ -224,15 +218,14 @@ public function readSchema(string $name, string $table): TableSchemaInterface * Validates table and column names are supported. * * @param \Cake\Database\Schema\TableSchemaInterface $schema Table schema - * @param \Cake\Console\ConsoleIo $io Console io * @return void * @throws \Cake\Console\Exception\StopException When table or column names are not supported */ - public function validateNames(TableSchemaInterface $schema, ConsoleIo $io): void + public function validateNames(TableSchemaInterface $schema): void { foreach ($schema->columns() as $column) { if (!$this->isValidColumnName($column)) { - $io->abort(sprintf( + $this->io->abort(sprintf( 'Unable to bake model. Table column name must start with a letter or underscore and cannot contain special characters. Found `%s`.', $column, @@ -244,13 +237,11 @@ public function validateNames(TableSchemaInterface $schema, ConsoleIo $io): void /** * Generate the fixture file, and write to disk * - * @param \Cake\Console\Arguments $args The CLI arguments. - * @param \Cake\Console\ConsoleIo $io The console io instance. * @param string $model name of the model being generated * @param array $otherVars Contents of the fixture file. * @return void */ - public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $model, array $otherVars): void + public function generateFixtureFile(string $model, array $otherVars): void { $defaults = [ 'name' => $model, @@ -262,14 +253,14 @@ public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $mode 'namespace' => Configure::read('App.namespace'), ]; if ($this->plugin) { - $defaults['namespace'] = $this->_pluginNamespace($this->plugin); + $defaults['namespace'] = $this->pluginNamespace($this->plugin); } $vars = $otherVars + $defaults; - if (!$args->getOption('fields')) { + if (!$this->args->getOption('fields')) { $vars['schema'] = null; } - $path = $this->getPath($args); + $path = $this->getPath(); $filename = $vars['name'] . 'Fixture.php'; $contents = $this->createTemplateRenderer() @@ -277,10 +268,10 @@ public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $mode ->set($vars) ->generate('Bake.tests/fixture'); - $io->out("\n" . sprintf('Baking test fixture for %s...', $model)); - $io->createFile($path . $filename, $contents, $this->force); + $this->io->out("\n" . sprintf('Baking test fixture for %s...', $model)); + $this->io->createFile($path . $filename, $contents, $this->force); $emptyFile = $path . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); + $this->deleteEmptyFile($emptyFile); } /** @@ -289,37 +280,39 @@ public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $mode * @param \Cake\Database\Schema\TableSchemaInterface $table Table schema * @return string fields definitions */ - protected function _generateSchema(TableSchemaInterface $table): string + protected function generateSchema(TableSchemaInterface $table): string { - $cols = $indexes = $constraints = []; + $cols = []; + $indexes = []; + $constraints = []; foreach ($table->columns() as $field) { /** @var array $fieldData */ $fieldData = $table->getColumn($field); - $properties = implode(', ', $this->_values($fieldData)); + $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)); + $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)); + $properties = implode(', ', $this->values($fieldData)); $constraints[] = " '{$index}' => [{$properties}],"; } - $options = $this->_values($table->getOptions()); + $options = $this->values($table->getOptions()); $content = implode("\n", $cols) . "\n"; - if (!empty($indexes)) { + if ($indexes !== []) { $content .= " '_indexes' => [\n" . implode("\n", $indexes) . "\n ],\n"; } - if (!empty($constraints)) { + if ($constraints !== []) { $content .= " '_constraints' => [\n" . implode("\n", $constraints) . "\n ],\n"; } - if (!empty($options)) { + if ($options !== []) { foreach ($options as &$option) { $option = ' ' . $option; } @@ -335,13 +328,13 @@ protected function _generateSchema(TableSchemaInterface $table): string * @param array $values options keys(type, null, default, key, length, extra) * @return array Formatted values */ - protected function _values(array $values): array + protected function values(array $values): array { $vals = []; foreach ($values as $key => $val) { if (is_array($val)) { - $vals[] = "'{$key}' => [" . implode(', ', $this->_values($val)) . ']'; + $vals[] = "'{$key}' => [" . implode(', ', $this->values($val)) . ']'; } else { $val = var_export($val, true); if ($val === 'NULL') { @@ -361,7 +354,7 @@ protected function _values(array $values): array * @param int $recordCount The number of records to generate. * @return array> Array of records to use in the fixture. */ - protected function _generateRecords(TableSchemaInterface $table, int $recordCount = 1): array + protected function generateRecords(TableSchemaInterface $table, int $recordCount = 1): array { $records = []; for ($i = 0; $i < $recordCount; $i++) { @@ -445,7 +438,7 @@ protected function _generateRecords(TableSchemaInterface $table, int $recordCoun } } else { $cases = $reflectionEnum->getCases(); - if ($cases) { + if ($cases !== []) { $firstCase = array_shift($cases); /** @var \BackedEnum $firstValue */ $firstValue = $firstCase->getValue(); @@ -471,7 +464,7 @@ protected function _generateRecords(TableSchemaInterface $table, int $recordCoun * @return string A string value of the $records array. * @throws \Brick\VarExporter\ExportException */ - protected function _makeRecordString(array $records): string + protected function makeRecordString(array $records): string { foreach ($records as &$record) { array_walk($record, function (&$value): void { @@ -490,16 +483,15 @@ protected function _makeRecordString(array $records): string * Interact with the user to get a custom SQL condition and use that to extract data * to build a fixture. * - * @param \Cake\Console\Arguments $args CLI arguments * @param string $modelName name of the model to take records from. * @param string|null $useTable Name of table to use. * @return array Array of records. */ - protected function _getRecordsFromTable(Arguments $args, string $modelName, ?string $useTable = null): array + protected function getRecordsFromTable(string $modelName, ?string $useTable = null): array { - $recordCount = ($args->getOption('count') ?? 10); + $recordCount = ($this->args->getOption('count') ?? 10); /** @var string $conditions */ - $conditions = ($args->getOption('conditions') ?? '1=1'); + $conditions = ($this->args->getOption('conditions') ?? '1=1'); if ($this->getTableLocator()->exists($modelName)) { $model = $this->getTableLocator()->get($modelName); } else { diff --git a/src/Command/MailerCommand.php b/src/Command/MailerCommand.php index 2ddd97600..d7077d597 100644 --- a/src/Command/MailerCommand.php +++ b/src/Command/MailerCommand.php @@ -16,9 +16,6 @@ */ namespace Bake\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; - /** * Mailer code generator. */ @@ -65,12 +62,10 @@ public function template(): string * Bake the Mailer class. * * @param string $name The name of the mailer to make. - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function bake(string $name, Arguments $args, ConsoleIo $io): void + protected function bake(string $name): void { - parent::bake($name, $args, $io); + parent::bake($name); } } diff --git a/src/Command/ModelAllCommand.php b/src/Command/ModelAllCommand.php index 55ec9a108..d03ab0643 100644 --- a/src/Command/ModelAllCommand.php +++ b/src/Command/ModelAllCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; use Cake\ORM\Locator\LocatorAwareTrait; @@ -72,21 +71,21 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); + $this->extractCommonProperties($this->args); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); $tables = $scanner->removeShadowTranslationTables($scanner->listUnskipped()); foreach ($tables as $table) { $this->getTableLocator()->clear(); - $modelArgs = new Arguments([$table], $args->getOptions(), ['name']); - $this->modelCommand->execute($modelArgs, $io); + $modelArgs = new Arguments([$table], $this->args->getOptions(), ['name']); + $this->modelCommand->setArgs($modelArgs); + $this->modelCommand->setIo($this->io); + $this->modelCommand->execute(); } return static::CODE_SUCCESS; diff --git a/src/Command/ModelCommand.php b/src/Command/ModelCommand.php index a8d87cdef..4a363a24d 100644 --- a/src/Command/ModelCommand.php +++ b/src/Command/ModelCommand.php @@ -22,7 +22,6 @@ use Bake\Utility\Model\EnumParser; use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; use Cake\Database\Connection; @@ -61,7 +60,7 @@ class ModelCommand extends BakeCommand * * @var array */ - protected array $_tables = []; + protected array $tables = []; /** * @inheritDoc @@ -74,24 +73,20 @@ public static function getDescription(): string /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $this->_getName($args->getArgument('name') ?? ''); - + $this->extractCommonProperties($this->args); + $name = $this->getNameWithoutPrefix($this->args->getArgument('name') ?? ''); if (empty($name)) { - $io->out('Choose a model to bake from the following:'); + $this->io->out('Choose a model to bake from the following:'); foreach ($this->listUnskipped() as $table) { - $io->out('- ' . $this->_camelize($table)); + $this->io->out('- ' . $this->camelize($table)); } return static::CODE_SUCCESS; } - // Disable caching before baking with connection $connection = ConnectionManager::get($this->connection); if ($connection instanceof Connection) { @@ -101,8 +96,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $connection->cacheMetadata(false); } } - - $this->bake($this->_camelize($name), $args, $io); + $this->bake($this->camelize($name)); return static::CODE_SUCCESS; } @@ -111,37 +105,34 @@ public function execute(Arguments $args, ConsoleIo $io): ?int * Generate code for the given model name. * * @param string $name The model name to generate. - * @param \Cake\Console\Arguments $args Console Arguments. - * @param \Cake\Console\ConsoleIo $io Console Io. * @return void */ - public function bake(string $name, Arguments $args, ConsoleIo $io): void + public function bake(string $name): void { - $table = $this->getTable($name, $args); + $table = $this->getTable($name); $tableObject = $this->getTableObject($name, $table); - $this->validateNames($tableObject->getSchema(), $io); - $data = $this->getTableContext($tableObject, $table, $name, $args, $io); - - $this->bakeEnums($tableObject, $data, $args, $io); - $this->bakeTable($tableObject, $data, $args, $io); - $this->bakeEntity($tableObject, $data, $args, $io); - $this->bakeFixture($tableObject->getAlias(), $tableObject->getTable(), $args, $io); - $this->bakeTest($tableObject->getAlias(), $args, $io); + $this->validateNames($tableObject->getSchema()); + $data = $this->getTableContext($tableObject, $table, $name); + + $this->bakeEnums($tableObject, $data); + $this->bakeTable($tableObject, $data); + $this->bakeEntity($tableObject, $data); + $this->bakeFixture($tableObject->getAlias(), $tableObject->getTable()); + $this->bakeTest($tableObject->getAlias()); } /** * Validates table and column names are supported. * * @param \Cake\Database\Schema\TableSchemaInterface $schema Table schema - * @param \Cake\Console\ConsoleIo $io Console io * @return void * @throws \Cake\Console\Exception\StopException When table or column names are not supported */ - public function validateNames(TableSchemaInterface $schema, ConsoleIo $io): void + public function validateNames(TableSchemaInterface $schema): void { foreach ($schema->columns() as $column) { if (!$this->isValidColumnName($column)) { - $io->abort(sprintf( + $this->io->abort(sprintf( 'Unable to bake model. Table column name must start with a letter or underscore and cannot contain special characters. Found `%s`.', $column, @@ -156,30 +147,26 @@ public function validateNames(TableSchemaInterface $schema, ConsoleIo $io): void * @param \Cake\ORM\Table $tableObject The model name to generate. * @param string $table The table name for the model being baked. * @param string $name The model name to generate. - * @param \Cake\Console\Arguments $args CLI Arguments - * @param \Cake\Console\ConsoleIo $io CLI io * @return array */ public function getTableContext( Table $tableObject, string $table, string $name, - Arguments $args, - ConsoleIo $io, ): array { - $associations = $this->getAssociations($tableObject, $args, $io); + $associations = $this->getAssociations($tableObject); $this->applyAssociations($tableObject, $associations); $associationInfo = $this->getAssociationInfo($tableObject); - $primaryKey = $this->getPrimaryKey($tableObject, $args); - $displayField = $this->getDisplayField($tableObject, $args); + $primaryKey = $this->getPrimaryKey($tableObject); + $displayField = $this->getDisplayField($tableObject); $propertySchema = $this->getEntityPropertySchema($tableObject); - $fields = $this->getFields($tableObject, $args); - $validation = $this->getValidation($tableObject, $associations, $args); - $rulesChecker = $this->getRules($tableObject, $associations, $args); + $fields = $this->getFields($tableObject); + $validation = $this->getValidation($tableObject, $associations); + $rulesChecker = $this->getRules($tableObject, $associations); $behaviors = $this->getBehaviors($tableObject); $connection = $this->connection; - $hidden = $this->getHiddenFields($tableObject, $args); + $hidden = $this->getHiddenFields($tableObject); $enumSchema = $this->getEnumDefinitions($tableObject->getSchema()); return compact( @@ -227,16 +214,14 @@ public function getTableObject(string $className, string $table): Table * Get the array of associations to generate. * * @param \Cake\ORM\Table $table The table to get associations for. - * @param \Cake\Console\Arguments $args CLI Arguments - * @param \Cake\Console\ConsoleIo $io CLI io * @return array> */ - public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): array + public function getAssociations(Table $table): array { - if ($args->getOption('no-associations')) { + if ($this->args->getOption('no-associations')) { return []; } - $io->out('One moment while associations are detected.'); + $this->io->out('One moment while associations are detected.'); $this->listAll(); @@ -248,10 +233,10 @@ public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): a ]; $primary = $table->getPrimaryKey(); - $associations = $this->findBelongsTo($table, $associations, $args); + $associations = $this->findBelongsTo($table, $associations); if (is_array($primary) && count($primary) > 1) { - $io->warning( + $this->io->warning( 'Bake cannot generate associations for composite primary keys at this time.', ); @@ -345,10 +330,9 @@ public function getAssociationInfo(Table $table): array * * @param \Cake\ORM\Table $model Database\Table instance of table being generated. * @param array> $associations Array of in progress associations - * @param \Cake\Console\Arguments|null $args CLI arguments * @return array> Associations with belongsTo added in. */ - public function findBelongsTo(Table $model, array $associations, ?Arguments $args = null): array + public function findBelongsTo(Table $model, array $associations): array { $schema = $model->getSchema(); foreach ($schema->columns() as $fieldName) { @@ -365,7 +349,7 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg 'foreignKey' => $fieldName, ]; } else { - $tmpModelName = $this->_modelNameFromKey($fieldName); + $tmpModelName = $this->modelNameFromKey($fieldName); // A key that resolves to the table itself (e.g. a `system_id` // column on `systems`) is only a real self-reference when it is // actually constrained as a foreign key to this table. Otherwise @@ -389,7 +373,7 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg $associationTable::class === Table::class && !in_array(Inflector::tableize($tmpModelName), $tables, true) ) { - $allowAliasRelations = $args instanceof Arguments && $args->getOption('skip-relation-check'); + $allowAliasRelations = isset($this->args) && $this->args->getOption('skip-relation-check'); $found = $this->findTableReferencedBy($schema, $fieldName); if ($found) { $className = ($this->plugin ? $this->plugin . '.' : '') . Inflector::camelize($found); @@ -520,7 +504,7 @@ public function findHasOne(Table $model, array $associations): array $schema = $model->getSchema(); $primaryKey = $schema->getPrimaryKey(); $tableName = $schema->name(); - $foreignKey = $this->_modelKey($tableName); + $foreignKey = $this->modelKey($tableName); $tables = $this->listAll(); foreach ($tables as $otherTableName) { @@ -528,7 +512,7 @@ public function findHasOne(Table $model, array $associations): array continue; } - $otherModel = $this->getTableObject($this->_camelize($otherTableName), $otherTableName); + $otherModel = $this->getTableObject($this->camelize($otherTableName), $otherTableName); $otherSchema = $otherModel->getSchema(); foreach ($otherSchema->columns() as $fieldName) { @@ -571,7 +555,7 @@ public function findHasMany(Table $model, array $associations): array $schema = $model->getSchema(); $primaryKey = $schema->getPrimaryKey(); $tableName = $schema->name(); - $foreignKey = $this->_modelKey($tableName); + $foreignKey = $this->modelKey($tableName); $tables = $this->listAll(); foreach ($tables as $otherTableName) { @@ -579,7 +563,7 @@ public function findHasMany(Table $model, array $associations): array continue; } - $otherModel = $this->getTableObject($this->_camelize($otherTableName), $otherTableName); + $otherModel = $this->getTableObject($this->camelize($otherTableName), $otherTableName); $otherSchema = $otherModel->getSchema(); foreach ($otherSchema->columns() as $fieldName) { @@ -625,7 +609,7 @@ public function findBelongsToMany(Table $model, array $associations): array { $schema = $model->getSchema(); $tableName = $schema->name(); - $foreignKey = $this->_modelKey($tableName); + $foreignKey = $this->modelKey($tableName); $tables = $this->listAll(); foreach ($tables as $otherTableName) { @@ -639,11 +623,11 @@ public function findBelongsToMany(Table $model, array $associations): array $assocTable = substr($otherTableName, 0, $otherOffset); } if ($assocTable && in_array($assocTable, $tables)) { - $habtmName = $this->_camelize($assocTable); + $habtmName = $this->camelize($assocTable); $assoc = [ 'alias' => $habtmName, 'foreignKey' => $foreignKey, - 'targetForeignKey' => $this->_modelKey($habtmName), + 'targetForeignKey' => $this->modelKey($habtmName), 'joinTable' => $otherTableName, ]; if ($this->plugin) { @@ -660,29 +644,27 @@ public function findBelongsToMany(Table $model, array $associations): array * Get the display field from the model or parameters * * @param \Cake\ORM\Table $model The model to introspect. - * @param \Cake\Console\Arguments $args CLI Arguments * @return array|string */ - public function getDisplayField(Table $model, Arguments $args): array|string + public function getDisplayField(Table $model): array|string { - if ($args->getOption('display-field')) { - return (string)$args->getOption('display-field'); + if ($this->args->getOption('display-field')) { + return (string)$this->args->getOption('display-field'); } - return $model->getDisplayField() ?? []; + return $model->getDisplayField(); } /** * Get the primary key field from the model or parameters * * @param \Cake\ORM\Table $model The model to introspect. - * @param \Cake\Console\Arguments $args CLI Arguments * @return array The columns in the primary key */ - public function getPrimaryKey(Table $model, Arguments $args): array + public function getPrimaryKey(Table $model): array { - if ($args->getOption('primary-key')) { - $fields = explode(',', (string)$args->getOption('primary-key')); + if ($this->args->getOption('primary-key')) { + $fields = explode(',', (string)$this->args->getOption('primary-key')); return array_values(array_filter(array_map('trim', $fields))); } @@ -743,7 +725,7 @@ public function getEntityPropertySchema(Table $model): array } $namespace = str_replace('/', '\\', trim((string)$namespace, '\\')); - $entityClass = $this->_entityName($association->getTarget()->getAlias()); + $entityClass = $this->entityName($association->getTarget()->getAlias()); $entityClass = '\\' . $namespace . '\Model\Entity\\' . $entityClass; } @@ -766,18 +748,17 @@ public function getEntityPropertySchema(Table $model): array * fields will be set as accessible. * * @param \Cake\ORM\Table $table The table instance to get fields for. - * @param \Cake\Console\Arguments $args CLI Arguments * @return array|false|null Either an array of fields, `false` in * case the no-fields option is used, or `null` if none of the * field options is used. */ - public function getFields(Table $table, Arguments $args): array|false|null + public function getFields(Table $table): array|false|null { - if ($args->getOption('no-fields')) { + if ($this->args->getOption('no-fields')) { return false; } - if ($args->getOption('fields')) { - $fields = explode(',', (string)$args->getOption('fields')); + if ($this->args->getOption('fields')) { + $fields = explode(',', (string)$this->args->getOption('fields')); return array_values(array_filter(array_map('trim', $fields))); } @@ -797,16 +778,15 @@ public function getFields(Table $table, Arguments $args): array|false|null * Uses the hidden and no-hidden options. * * @param \Cake\ORM\Table $model The model to introspect. - * @param \Cake\Console\Arguments $args CLI Arguments * @return array The columns to make accessible */ - public function getHiddenFields(Table $model, Arguments $args): array + public function getHiddenFields(Table $model): array { - if ($args->getOption('no-hidden')) { + if ($this->args->getOption('no-hidden')) { return []; } - if ($args->getOption('hidden')) { - $fields = explode(',', (string)$args->getOption('hidden')); + if ($this->args->getOption('hidden')) { + $fields = explode(',', (string)$this->args->getOption('hidden')); return array_values(array_filter(array_map('trim', $fields))); } @@ -822,17 +802,16 @@ public function getHiddenFields(Table $model, Arguments $args): array * * @param \Cake\ORM\Table $model The model to introspect. * @param array> $associations The associations list. - * @param \Cake\Console\Arguments $args CLI Arguments * @return array>|false The validation rules. */ - public function getValidation(Table $model, array $associations, Arguments $args): array|false + public function getValidation(Table $model, array $associations): array|false { - if ($args->getOption('no-validation')) { + if ($this->args->getOption('no-validation')) { return []; } $schema = $model->getSchema(); $fields = $schema->columns(); - if (!$fields) { + if ($fields === []) { return false; } @@ -852,7 +831,7 @@ public function getValidation(Table $model, array $associations, Arguments $args $field = $schema->getColumn($fieldName); $field['isForeignKey'] = in_array($fieldName, $foreignKeys, true); $validation = $this->fieldValidation($schema, $fieldName, $field, $primaryKey); - if ($validation) { + if ($validation !== []) { $validate[$fieldName] = $validation; } } @@ -1015,17 +994,16 @@ protected function getEmptyMethod(string $fieldName, array $metaData, string $pr * * @param \Cake\ORM\Table $model The model to introspect. * @param array> $associations The associations for the model. - * @param \Cake\Console\Arguments $args CLI Arguments * @return list> The rules to be applied. */ - public function getRules(Table $model, array $associations, Arguments $args): array + public function getRules(Table $model, array $associations): array { - if ($args->getOption('no-rules')) { + if ($this->args->getOption('no-rules')) { return []; } $schema = $model->getSchema(); $schemaFields = $schema->columns(); - if (empty($schemaFields)) { + if ($schemaFields === []) { return []; } @@ -1109,7 +1087,7 @@ public function getBehaviors(Table $model): array $behaviors = []; $schema = $model->getSchema(); $fields = $schema->columns(); - if (empty($fields)) { + if ($fields === []) { return []; } if (in_array('created', $fields, true) || in_array('modified', $fields, true)) { @@ -1127,7 +1105,7 @@ public function getBehaviors(Table $model): array } $counterCache = $this->getCounterCache($model); - if (!empty($counterCache)) { + if ($counterCache !== []) { $behaviors['CounterCache'] = $counterCache; } @@ -1146,7 +1124,7 @@ public function getCounterCache(Table $model): array $counterCache = []; foreach ($belongsTo['belongsTo'] as $otherTable) { $otherAlias = $otherTable['alias']; - $otherModel = $this->getTableObject($this->_camelize($otherAlias), Inflector::underscore($otherAlias)); + $otherModel = $this->getTableObject($this->camelize($otherAlias), Inflector::underscore($otherAlias)); try { $otherSchema = $otherModel->getSchema(); @@ -1170,31 +1148,29 @@ public function getCounterCache(Table $model): array * * @param \Cake\ORM\Table $model Model name or object * @param array $data An array to use to generate the Table - * @param \Cake\Console\Arguments $args CLI Arguments - * @param \Cake\Console\ConsoleIo $io CLI io * @return void */ - public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo $io): void + public function bakeEntity(Table $model, array $data): void { - if ($args->getOption('no-entity')) { + if ($this->args->getOption('no-entity')) { return; } - $name = $this->_entityName($model->getAlias()); - $io->out("\n" . sprintf('Baking entity class for %s...', $name)); + $name = $this->entityName($model->getAlias()); + $this->io->out("\n" . sprintf('Baking entity class for %s...', $name)); $namespace = Configure::read('App.namespace'); $pluginPath = ''; if ($this->plugin) { - $namespace = $this->_pluginNamespace($this->plugin); + $namespace = $this->pluginNamespace($this->plugin); $pluginPath = $this->plugin . '.'; } - $path = $this->getPath($args); + $path = $this->getPath(); $filename = $path . 'Entity' . DS . $name . '.php'; $parsedFile = null; - if ($args->getOption('update')) { + if ($this->args->getOption('update')) { $parsedFile = $this->parseFile($filename); } @@ -1204,17 +1180,17 @@ public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo 'plugin' => $this->plugin, 'pluginPath' => $pluginPath, 'primaryKey' => [], - 'fileBuilder' => new FileBuilder($io, "{$namespace}\Model\Entity", $parsedFile), + 'fileBuilder' => new FileBuilder($this->io, "{$namespace}\Model\Entity", $parsedFile), ]; $contents = $this->createTemplateRenderer() ->set($data) ->generate('Bake.Model/entity'); - $this->writeFile($io, $filename, $contents, $this->force); + $this->writeFile($this->io, $filename, $contents, $this->force); $emptyFile = $path . 'Entity' . DS . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); + $this->deleteEmptyFile($emptyFile); } /** @@ -1222,31 +1198,29 @@ public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo * * @param \Cake\ORM\Table $model Model name or object * @param array $data An array to use to generate the Table - * @param \Cake\Console\Arguments $args CLI Arguments - * @param \Cake\Console\ConsoleIo $io CLI Arguments * @return void */ - public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo $io): void + public function bakeTable(Table $model, array $data): void { - if ($args->getOption('no-table')) { + if ($this->args->getOption('no-table')) { return; } $name = $model->getAlias(); - $io->out("\n" . sprintf('Baking table class for %s...', $name)); + $this->io->out("\n" . sprintf('Baking table class for %s...', $name)); $namespace = Configure::read('App.namespace'); $pluginPath = ''; if ($this->plugin) { - $namespace = $this->_pluginNamespace($this->plugin); + $namespace = $this->pluginNamespace($this->plugin); } - $path = $this->getPath($args); + $path = $this->getPath(); $filename = $path . 'Table' . DS . $name . 'Table.php'; $parsedFile = null; $customColumnTypes = []; - if ($args->getOption('update')) { + if ($this->args->getOption('update')) { $parsedFile = $this->parseFile($filename); // Extract custom column types from existing file if ($parsedFile instanceof ParsedFile && isset($parsedFile->class->methods['initialize'])) { @@ -1254,7 +1228,7 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo } } - $entity = $this->_entityName($model->getAlias()); + $entity = $this->entityName($model->getAlias()); $enums = $this->enums($model, $entity, $namespace); // Merge custom column types with generated enums @@ -1279,14 +1253,14 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo 'enums' => $enums, 'customColumnTypes' => $customColumnTypes, 'connection' => $this->connection, - 'fileBuilder' => new FileBuilder($io, "{$namespace}\Model\Table", $parsedFile), + 'fileBuilder' => new FileBuilder($this->io, "{$namespace}\Model\Table", $parsedFile), ]; $contents = $this->createTemplateRenderer() ->set($data) ->generate('Bake.Model/table'); - $this->writeFile($io, $filename, $contents, $this->force); + $this->writeFile($this->io, $filename, $contents, $this->force); // Work around composer caching that classes/files do not exist. // Check for the file as it might not exist in tests. @@ -1296,7 +1270,7 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo $this->getTableLocator()->clear(); $emptyFile = $path . 'Table' . DS . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); + $this->deleteEmptyFile($emptyFile); } /** @@ -1306,16 +1280,16 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo */ public function listAll(): array { - if (!empty($this->_tables)) { - return $this->_tables; + if ($this->tables !== []) { + return $this->tables; } /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); - $this->_tables = $scanner->listAll(); + $this->tables = $scanner->listAll(); - return $this->_tables; + return $this->tables; } /** @@ -1338,13 +1312,12 @@ public function listUnskipped(): array * Uses the `table` option if it is set. * * @param string $name Table name - * @param \Cake\Console\Arguments $args The CLI arguments * @return string */ - public function getTable(string $name, Arguments $args): string + public function getTable(string $name): string { - if ($args->getOption('table')) { - return (string)$args->getOption('table'); + if ($this->args->getOption('table')) { + return (string)$this->args->getOption('table'); } return Inflector::underscore($name); @@ -1358,7 +1331,7 @@ public function getTable(string $name, Arguments $args): string */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser->setDescription( 'Bake table and entity classes.', @@ -1422,48 +1395,46 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * * @param string $className Name of class to bake fixture for * @param string $useTable Optional table name for fixture to use. - * @param \Cake\Console\Arguments $args Arguments instance - * @param \Cake\Console\ConsoleIo $io ConsoleIo instance * @return void */ public function bakeFixture( string $className, string $useTable, - Arguments $args, - ConsoleIo $io, ): void { - if ($args->getOption('no-fixture')) { + if ($this->args->getOption('no-fixture')) { return; } $fixture = new FixtureCommand(); $fixtureArgs = new Arguments( [$className], - ['table' => $useTable] + $args->getOptions(), + ['table' => $useTable] + $this->args->getOptions(), ['name'], ); - $fixture->execute($fixtureArgs, $io); + $fixture->setIo($this->io); + $fixture->setArgs($fixtureArgs); + $fixture->execute(); } /** * Assembles and writes a unit test file * * @param string $className Model class name - * @param \Cake\Console\Arguments $args Arguments instance - * @param \Cake\Console\ConsoleIo $io ConsoleIo instance * @return void */ - public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + public function bakeTest(string $className): void { - if ($args->getOption('no-test')) { + if ($this->args->getOption('no-test')) { return; } $test = new TestCommand(); $testArgs = new Arguments( ['table', $className], - $args->getOptions(), + $this->args->getOptions(), ['type', 'name'], ); - $test->execute($testArgs, $io); + $test->setIo($this->io); + $test->setArgs($testArgs); + $test->execute(); } /** @@ -1548,7 +1519,7 @@ protected function getEnumDefinitions(TableSchemaInterface $schema): array } } $enumsDefinition = EnumParser::parseCases($enumsDefinitionString, $isInt); - if (!$enumsDefinition) { + if ($enumsDefinition === []) { continue; } @@ -1565,14 +1536,14 @@ protected function getEnumDefinitions(TableSchemaInterface $schema): array * @param array $data * @return void */ - protected function bakeEnums(Table $model, array $data, Arguments $args, ConsoleIo $io): void + protected function bakeEnums(Table $model, array $data): void { $enums = $data['enumSchema']; if (!$enums) { return; } - $entity = $this->_entityName($model->getAlias()); + $entity = $this->entityName($model->getAlias()); foreach ($enums as $column => $data) { $enumCommand = new EnumCommand(); @@ -1589,12 +1560,14 @@ protected function bakeEnums(Table $model, array $data, Arguments $args, Console $cases[] = $k . ':' . $v; } - $args = new Arguments( + $this->args = new Arguments( [$name, implode(',', $cases)], - ['int' => $data['type'] === 'int'] + $args->getOptions(), + ['int' => $data['type'] === 'int'] + $this->args->getOptions(), ['name', 'cases'], ); - $enumCommand->execute($args, $io); + $enumCommand->setArgs($this->args); + $enumCommand->setIo($this->io); + $enumCommand->execute(); } } @@ -1634,7 +1607,7 @@ protected function createAssociationAlias(array $association): string { $foreignKey = $association['foreignKey']; - return $this->_modelNameFromKey($foreignKey); + return $this->modelNameFromKey($foreignKey); } /** diff --git a/src/Command/PluginCommand.php b/src/Command/PluginCommand.php index 020fb6b68..e12240783 100644 --- a/src/Command/PluginCommand.php +++ b/src/Command/PluginCommand.php @@ -20,8 +20,6 @@ use Bake\Utility\TemplateRenderer; use Bake\View\BakeView; use Cake\Command\PluginLoadCommand; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\App; use Cake\Core\Configure; @@ -54,43 +52,39 @@ public static function getDescription(): string /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $name = $args->getArgument('name'); + $name = $this->args->getArgument('name'); if (empty($name)) { - $io->error('You must provide a plugin name in CamelCase format.'); - $io->out('To make an "MyExample" plugin, run `cake bake plugin MyExample`.'); + $this->io->error('You must provide a plugin name in CamelCase format.'); + $this->io->out('To make an "MyExample" plugin, run `cake bake plugin MyExample`.'); return static::CODE_ERROR; } $parts = explode('/', $name); $plugin = implode('/', array_map(Inflector::camelize(...), $parts)); - - if ($args->getOption('standalone-path')) { - $this->path = (string)$args->getOption('standalone-path'); + if ($this->args->getOption('standalone-path')) { + $this->path = (string)$this->args->getOption('standalone-path'); $this->path = rtrim($this->path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $this->isVendor = true; if (!is_dir($this->path)) { - $io->error(sprintf('Path `%s` does not exist.', $this->path)); + $this->io->error(sprintf('Path `%s` does not exist.', $this->path)); return static::CODE_ERROR; } } - - $pluginPath = $this->_pluginPath($plugin); - if (is_dir($pluginPath) && !$args->getOption('class-only')) { - $io->out(sprintf('Plugin: %s already exists, no action taken', $plugin)); - $io->out(sprintf('Path: %s', $pluginPath)); + $pluginPath = $this->pluginPath($plugin); + if (is_dir($pluginPath) && !$this->args->getOption('class-only')) { + $this->io->out(sprintf('Plugin: %s already exists, no action taken', $plugin)); + $this->io->out(sprintf('Path: %s', $pluginPath)); return static::CODE_ERROR; } - if (!$this->bake($plugin, $args, $io)) { - $io->error(sprintf('An error occurred trying to bake: %s in %s', $plugin, $this->path . $plugin)); + if (!$this->bake($plugin)) { + $this->io->error(sprintf('An error occurred trying to bake: %s in %s', $plugin, $this->path . $plugin)); $this->abort(); } @@ -103,11 +97,9 @@ public function execute(Arguments $args, ConsoleIo $io): ?int * Also update the autoloader and the root composer.json file if it can be found * * @param string $plugin Name of the plugin in CamelCased format - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return bool|null */ - public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool + public function bake(string $plugin): ?bool { if (!$this->isVendor) { $pathOptions = App::path('plugins'); @@ -115,56 +107,55 @@ public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool $this->path = $currentPath !== false ? $currentPath : ''; if (count($pathOptions) > 1) { - $this->findPath($pathOptions, $io); + $this->findPath($pathOptions); } } - $io->out(sprintf('Plugin Name: %s', $plugin)); - $io->out(sprintf('Plugin Directory: %s', $this->path . $plugin)); - $io->hr(); + $this->io->out(sprintf('Plugin Name: %s', $plugin)); + $this->io->out(sprintf('Plugin Directory: %s', $this->path . $plugin)); + $this->io->hr(); - $looksGood = $io->askChoice('Look okay?', ['y', 'n', 'q'], 'y'); + $looksGood = $this->io->askChoice('Look okay?', ['y', 'n', 'q'], 'y'); if (strtolower($looksGood) !== 'y') { return null; } - $this->_generateFiles($plugin, $this->path, $args, $io); + $this->generateFiles($plugin, $this->path); if (!$this->isVendor) { - if (!$args->getOption('class-only')) { - $this->_modifyApplication($plugin, $io); + if (!$this->args->getOption('class-only')) { + $this->modifyApplication($plugin); } - $composer = $this->findComposer($args, $io); + $composer = $this->findComposer(); if ($composer === false) { - $io->error('Could not find composer executable.'); + $this->io->error('Could not find composer executable.'); $this->abort(); } + /** @var non-empty-string $cwd */ + $cwd = getcwd(); try { - /** @var non-empty-string $cwd */ - $cwd = getcwd(); - // Windows makes running multiple commands at once hard. - chdir(dirname($this->_rootComposerFilePath())); + chdir(dirname($this->rootComposerFilePath())); $command = 'php ' . escapeshellarg($composer) . ' dump-autoload'; - $process = new Process($io); - $io->out($process->call($command)); - - chdir($cwd); + $process = new Process($this->io); + $this->io->out($process->call($command)); } catch (RuntimeException $e) { $error = $e->getMessage(); - $io->error(sprintf('Could not run `composer dump-autoload`: %s', $error)); + $this->io->error(sprintf('Could not run `composer dump-autoload`: %s', $error)); $this->abort(); + } finally { + chdir($cwd); } } - $io->hr(); - $io->out(sprintf('Created: %s in %s', $plugin, $this->path . $plugin), 2); + $this->io->hr(); + $this->io->out(sprintf('Created: %s in %s', $plugin, $this->path . $plugin), 2); $emptyFile = $this->path . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); + $this->deleteEmptyFile($emptyFile); return true; } @@ -173,12 +164,11 @@ public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool * Modify the application class * * @param string $plugin Name of plugin the plugin. - * @param \Cake\Console\ConsoleIo $io ConsoleIo * @return void */ - protected function _modifyApplication(string $plugin, ConsoleIo $io): void + protected function modifyApplication(string $plugin): void { - $this->executeCommand(PluginLoadCommand::class, [$plugin], $io); + $this->executeCommand(PluginLoadCommand::class, [$plugin]); } /** @@ -191,15 +181,11 @@ protected function _modifyApplication(string $plugin, ConsoleIo $io): void * * @param string $pluginName the CamelCase name of the plugin * @param string $path the path to the plugins dir (the containing folder) - * @param \Cake\Console\Arguments $args CLI arguments. - * @param \Cake\Console\ConsoleIo $io The io instance. * @return void */ - protected function _generateFiles( + protected function generateFiles( string $pluginName, string $path, - Arguments $args, - ConsoleIo $io, ): void { $namespace = str_replace('/', '\\', $pluginName); $baseNamespace = Configure::read('App.namespace'); @@ -232,8 +218,8 @@ protected function _generateFiles( $root = $path . $pluginName . DS; $paths = []; - if ($args->hasOption('theme')) { - $paths[] = Plugin::templatePath((string)$args->getOption('theme')); + if ($this->args->hasOption('theme')) { + $paths[] = Plugin::templatePath((string)$this->args->getOption('theme')); } $paths = array_merge($paths, Configure::read('App.paths.templates')); @@ -261,7 +247,7 @@ protected function _generateFiles( } } - if ($args->getOption('class-only')) { + if ($this->args->getOption('class-only')) { $files = array_filter($files, function ($file): bool { return $file->getFilename() === 'Plugin.php.twig'; }); @@ -279,7 +265,7 @@ protected function _generateFiles( if ($filename === 'src' . DIRECTORY_SEPARATOR . 'Plugin.php') { $filename = 'src' . DIRECTORY_SEPARATOR . $name . 'Plugin.php'; } - $this->_generateFile($renderer, $template, $root, $filename, $io); + $this->generateFile($renderer, $template, $root, $filename); } } @@ -290,19 +276,17 @@ protected function _generateFiles( * @param string $template The template to render * @param string $root The path to the plugin's root * @param string $filename Filename to generate. - * @param \Cake\Console\ConsoleIo $io The io instance. * @return void */ - protected function _generateFile( + protected function generateFile( TemplateRenderer $renderer, string $template, string $root, string $filename, - ConsoleIo $io, ): void { - $io->out(sprintf('Generating %s file...', $template)); + $this->io->out(sprintf('Generating %s file...', $template)); $out = $renderer->generate('Bake.Plugin/' . $template); - $io->createFile($root . $filename, $out); + $this->io->createFile($root . $filename, $out); } /** @@ -312,7 +296,7 @@ protected function _generateFile( * * @return string the abs file path */ - protected function _rootComposerFilePath(): string + protected function rootComposerFilePath(): string { return ROOT . DS . 'composer.json'; } @@ -321,10 +305,9 @@ protected function _rootComposerFilePath(): string * find and change $this->path to the user selection * * @param array $pathOptions The list of paths to look in. - * @param \Cake\Console\ConsoleIo $io The io object * @return void */ - public function findPath(array $pathOptions, ConsoleIo $io): void + public function findPath(array $pathOptions): void { $valid = false; foreach ($pathOptions as $i => $path) { @@ -336,7 +319,7 @@ public function findPath(array $pathOptions, ConsoleIo $io): void $max = count($pathOptions); if ($max === 0) { - $io->error('No valid plugin paths found! Please configure a plugin path that exists.'); + $this->io->error('No valid plugin paths found! Please configure a plugin path that exists.'); $this->abort(); } @@ -349,10 +332,10 @@ public function findPath(array $pathOptions, ConsoleIo $io): void $choice = 0; while (!$valid) { foreach ($pathOptions as $i => $option) { - $io->out($i + 1 . '. ' . $option); + $this->io->out($i + 1 . '. ' . $option); } $prompt = 'Choose a plugin path from the paths above.'; - $choice = (int)$io->ask($prompt); + $choice = (int)$this->io->ask($prompt); if ($choice > 0 && $choice <= $max) { $valid = true; } @@ -385,7 +368,7 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption 'short' => 't', 'help' => 'The theme to use when baking code.', 'default' => Configure::read('Bake.theme') ?: null, - 'choices' => $this->_getBakeThemes(), + 'choices' => $this->getBakeThemes(), ]) ->addOption('standalone-path', [ 'short' => 'p', @@ -402,15 +385,13 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption /** * Uses either the CLI option or looks in $PATH and cwd for composer. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return string|false Either the path to composer or false if it cannot be found. */ - public function findComposer(Arguments $args, ConsoleIo $io): string|bool + public function findComposer(): string|bool { - if ($args->hasOption('composer')) { + if ($this->args->hasOption('composer')) { /** @var string $path */ - $path = $args->getOption('composer'); + $path = $this->args->getOption('composer'); if (file_exists($path)) { return $path; } @@ -419,7 +400,7 @@ public function findComposer(Arguments $args, ConsoleIo $io): string|bool $path = (string)env('PATH'); if (!empty($path)) { $paths = explode(PATH_SEPARATOR, $path); - $composer = $this->_searchPath($paths, $io); + $composer = $this->searchPath($paths); } return $composer; @@ -429,16 +410,15 @@ public function findComposer(Arguments $args, ConsoleIo $io): string|bool * Search the $PATH for composer. * * @param array $path The paths to search. - * @param \Cake\Console\ConsoleIo $io The console io * @return string|false */ - protected function _searchPath(array $path, ConsoleIo $io): string|bool + protected function searchPath(array $path): string|bool { $composer = ['composer.phar', 'composer']; foreach ($path as $dir) { foreach ($composer as $cmd) { if (is_file($dir . DS . $cmd)) { - $io->verbose('Found composer executable in ' . $dir); + $this->io->verbose('Found composer executable in ' . $dir); return $dir . DS . $cmd; } diff --git a/src/Command/SimpleBakeCommand.php b/src/Command/SimpleBakeCommand.php index 59dcbc5c3..2322c5d7a 100644 --- a/src/Command/SimpleBakeCommand.php +++ b/src/Command/SimpleBakeCommand.php @@ -16,8 +16,6 @@ */ namespace Bake\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; use Cake\Utility\Inflector; @@ -52,14 +50,13 @@ abstract public function template(): string; /** * Get template data. * - * @param \Cake\Console\Arguments $arguments The arguments for the command * @return array */ - public function templateData(Arguments $arguments): array + public function templateData(): array { $namespace = Configure::read('App.namespace'); if ($this->plugin) { - $namespace = $this->_pluginNamespace($this->plugin); + $namespace = $this->pluginNamespace($this->plugin); } return ['namespace' => $namespace]; @@ -68,22 +65,20 @@ public function templateData(Arguments $arguments): array /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $args->getArgumentAt(0); + $this->extractCommonProperties($this->args); + $name = $this->args->getArgumentAt(0); if (empty($name)) { - $io->error('You must provide a name to bake a ' . $this->name()); + $this->io->error('You must provide a name to bake a ' . $this->name()); $this->abort(); } - $name = $this->_getName($name); + $name = $this->getNameWithoutPrefix($name); $name = Inflector::camelize($name); - $this->bake($name, $args, $io); - $this->bakeTest($name, $args, $io); + $this->bake($name); + $this->bakeTest($name); return static::CODE_SUCCESS; } @@ -92,40 +87,38 @@ public function execute(Arguments $args, ConsoleIo $io): ?int * Generate a class stub * * @param string $name The class name - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function bake(string $name, Arguments $args, ConsoleIo $io): void + protected function bake(string $name): void { $contents = $this->createTemplateRenderer() ->set('name', $name) - ->set($this->templateData($args)) + ->set($this->templateData()) ->generate($this->template()); - $filename = $this->getPath($args) . $this->fileName($name); - $io->createFile($filename, $contents, $this->force); + $filename = $this->getPath() . $this->fileName($name); + $this->io->createFile($filename, $contents, $this->force); - $emptyFile = $this->getPath($args) . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); + $emptyFile = $this->getPath() . '.gitkeep'; + $this->deleteEmptyFile($emptyFile); } /** * Generate a test case. * * @param string $className The class to bake a test for. - * @param \Cake\Console\Arguments $args The console arguments - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + public function bakeTest(string $className): void { - if ($args->getOption('no-test')) { + if ($this->args->getOption('no-test')) { return; } $test = new TestCommand(); $test->plugin = $this->plugin; - $test->bake($this->name(), $className, $args, $io); + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake($this->name(), $className); } /** @@ -136,7 +129,7 @@ public function bakeTest(string $className, Arguments $args, ConsoleIo $io): voi */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $name = $this->name(); $parser->setDescription( sprintf('Bake a %s class file.', $name), diff --git a/src/Command/TemplateAllCommand.php b/src/Command/TemplateAllCommand.php index 8f271e018..9a9199f52 100644 --- a/src/Command/TemplateAllCommand.php +++ b/src/Command/TemplateAllCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\TableScanner; use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; @@ -48,27 +47,26 @@ public static function defaultName(): string /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int The exit code */ - public function execute(Arguments $args, ConsoleIo $io): int + public function execute(): int { - $this->extractCommonProperties($args); + $this->extractCommonProperties($this->args); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); - $tables = $scanner->removeShadowTranslationTables($scanner->listUnskipped()); foreach ($tables as $table) { $parser = $this->templateCommand->getOptionParser(); $templateArgs = new Arguments( [$table], - $args->getOptions(), + $this->args->getOptions(), $parser->argumentNames(), ); - $this->templateCommand->execute($templateArgs, $io); + $this->templateCommand->setArgs($templateArgs); + $this->templateCommand->setIo($this->io); + $this->templateCommand->execute(); } return static::CODE_SUCCESS; @@ -87,7 +85,7 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption // always runs before execute(), so this guarantees the subcommand is available there. $this->templateCommand ??= new TemplateCommand(); - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser ->setDescription('Bake all view template files.') ->addOption('prefix', [ diff --git a/src/Command/TemplateCommand.php b/src/Command/TemplateCommand.php index e2ff285b4..1b8e90eb6 100644 --- a/src/Command/TemplateCommand.php +++ b/src/Command/TemplateCommand.php @@ -18,8 +18,6 @@ use Bake\Utility\Model\AssociationFilter; use Bake\Utility\TableScanner; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\App; use Cake\Core\Configure; @@ -69,7 +67,7 @@ class TemplateCommand extends BakeCommand /** * AssociationFilter utility */ - protected ?AssociationFilter $_associationFilter = null; + protected ?AssociationFilter $associationFilter = null; /** * Template path. @@ -112,53 +110,46 @@ public function initialize(): void /** * Execute the command. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - $name = $args->getArgument('name') ?? ''; - $name = $this->_getName($name); - + $this->extractCommonProperties($this->args); + $name = $this->args->getArgument('name') ?? ''; + $name = $this->getNameWithoutPrefix($name); if (empty($name)) { - $io->out('Possible tables to bake view templates for based on your current database:'); + $this->io->out('Possible tables to bake view templates for based on your current database:'); /** @var \Cake\Database\Connection $connection */ $connection = ConnectionManager::get($this->connection); $scanner = new TableScanner($connection); foreach ($scanner->listUnskipped() as $table) { - $io->out('- ' . $this->_camelize($table)); + $this->io->out('- ' . $this->camelize($table)); } return static::CODE_SUCCESS; } - $template = $args->getArgument('template'); - $action = $args->getArgument('action'); - - $this->controller($args, $name, (string)$args->getOption('controller')); + $template = $this->args->getArgument('template'); + $action = $this->args->getArgument('action'); + $this->controller($name, (string)$this->args->getOption('controller')); $this->model($name); - if ($template && $action === null) { $action = $template; } if ($template) { - $this->bake($args, $io, $template, true, $action); + $this->bake($template, true, $action); return static::CODE_SUCCESS; } - - $vars = $this->_loadController($io); - $methods = $this->_methodsToBake(); - + $vars = $this->loadController(); + $methods = $this->methodsToBake(); foreach ($methods as $method) { try { - $content = $this->getContent($args, $io, $method, $vars); - $this->bake($args, $io, $method, $content); + $content = $this->getContent($method, $vars); + $this->bake($method, $content); } catch (MissingTemplateException $e) { - $io->verbose($e->getMessage()); + $this->io->verbose($e->getMessage()); } catch (RuntimeException $e) { - $io->error($e->getMessage()); + $this->io->error($e->getMessage()); } } @@ -173,7 +164,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int */ public function model(string $table): void { - $tableName = $this->_camelize($table); + $tableName = $this->camelize($table); $plugin = $this->plugin; if ($plugin) { $plugin .= '.'; @@ -184,14 +175,13 @@ public function model(string $table): void /** * Set the controller related properties. * - * @param \Cake\Console\Arguments $args The arguments * @param string $table The table/model that is being baked. * @param string|null $controller The controller name if specified. * @return void */ - public function controller(Arguments $args, string $table, ?string $controller = null): void + public function controller(string $table, ?string $controller = null): void { - $tableName = $this->_camelize($table); + $tableName = $this->camelize($table); if (empty($controller)) { $controller = $tableName; } @@ -201,7 +191,7 @@ public function controller(Arguments $args, string $table, ?string $controller = if ($plugin) { $plugin .= '.'; } - $prefix = $this->getPrefix($args); + $prefix = $this->getPrefix(); if ($prefix) { $prefix .= '/'; } @@ -211,13 +201,12 @@ public function controller(Arguments $args, string $table, ?string $controller = /** * Get the path base for view templates. * - * @param \Cake\Console\Arguments $args The arguments * @param string|null $container Unused. * @return string */ - public function getTemplatePath(Arguments $args, ?string $container = null): string + public function getTemplatePath(?string $container = null): string { - $path = parent::getTemplatePath($args, $container); + $path = parent::getTemplatePath($container); return $path . $this->controllerName . DS; } @@ -227,7 +216,7 @@ public function getTemplatePath(Arguments $args, ?string $container = null): str * * @return array Array of action names that should be baked */ - protected function _methodsToBake(): array + protected function methodsToBake(): array { $base = Configure::read('App.namespace'); @@ -244,7 +233,7 @@ protected function _methodsToBake(): array ), ); } - if (empty($methods)) { + if ($methods === []) { $methods = $this->scaffoldActions; } foreach ($methods as $i => $method) { @@ -273,10 +262,9 @@ protected function _methodsToBake(): array * - 'keyFields' * - 'schema' * - * @param \Cake\Console\ConsoleIo $io Instance of the ConsoleIO * @return array Returns variables to be made available to a view template */ - protected function _loadController(ConsoleIo $io): array + protected function loadController(): array { if ($this->getTableLocator()->exists($this->modelName)) { $modelObject = $this->getTableLocator()->get($this->modelName); @@ -285,48 +273,47 @@ protected function _loadController(ConsoleIo $io): array 'connectionName' => $this->connection, ]); } - $namespace = Configure::read('App.namespace'); - - $primaryKey = $displayField = $singularVar = $singularHumanName = null; - $schema = $fields = $hidden = $modelClass = null; + $primaryKey = null; + $displayField = null; + $singularVar = null; + $singularHumanName = null; + $schema = null; + $fields = null; + $hidden = null; + $modelClass = null; try { $primaryKey = (array)$modelObject->getPrimaryKey(); $displayField = $modelObject->getDisplayField(); - $singularVar = $this->_singularName($this->controllerName); - $singularHumanName = $this->_singularHumanName($this->controllerName); + $singularVar = $this->singularName($this->controllerName); + $singularHumanName = $this->singularHumanName($this->controllerName); $schema = $modelObject->getSchema(); $fields = $schema->columns(); $hidden = $modelObject->newEmptyEntity()->getHidden() ?: ['token', 'password', 'passwd']; $modelClass = $this->modelName; } catch (Exception $exception) { - $io->error($exception->getMessage()); + $this->io->error($exception->getMessage()); $this->abort(); } - - [, $entityClass] = namespaceSplit($this->_entityName($this->modelName)); + [, $entityClass] = namespaceSplit($this->entityName($this->modelName)); $entityClass = sprintf('%s\Model\Entity\%s', $namespace, $entityClass); if (!class_exists($entityClass)) { $entityClass = EntityInterface::class; } - $associations = $this->_filteredAssociations($modelObject); + $associations = $this->filteredAssociations($modelObject); $keyFields = []; - if (isset($associations['BelongsToMany'])) { foreach ($associations['BelongsToMany'] as $assoc) { $keyFields[$assoc['foreignKey']] = $assoc['variable']; } } - if (isset($associations['BelongsTo'])) { foreach ($associations['BelongsTo'] as $assoc) { $keyFields[$assoc['foreignKey']] = $assoc['variable']; } } - $pluralVar = Inflector::variable($this->controllerName); - $pluralHumanName = $this->_pluralHumanName($this->controllerName); - + $pluralHumanName = $this->pluralHumanName($this->controllerName); // Handle cases where singular and plural are identical (e.g., "news", "sheep") // to avoid generating invalid code like `foreach ($news as $news)` if ($singularVar === $pluralVar) { @@ -355,56 +342,48 @@ protected function _loadController(ConsoleIo $io): array /** * Assembles and writes bakes the view file. * - * @param \Cake\Console\Arguments $args CLI arguments - * @param \Cake\Console\ConsoleIo $io Console io * @param string $template Template file to use. * @param string|true $content Content to write. * @param ?string $outputFile The output file to create. If null will use `$template` * @return void */ public function bake( - Arguments $args, - ConsoleIo $io, string $template, string|bool $content = '', ?string $outputFile = null, ): void { - if ($outputFile === null) { - $outputFile = $template; - } + $outputFile ??= $template; if ($content === true) { - $content = $this->getContent($args, $io, $template); + $content = $this->getContent($template); } if (empty($content)) { // phpcs:ignore Generic.Files.LineLength - $io->warning("No generated content for '{$template}.{$this->ext}', not generating template."); + $this->io->warning("No generated content for '{$template}.{$this->ext}', not generating template."); return; } - $path = $this->getTemplatePath($args); + $path = $this->getTemplatePath(); $filename = $path . Inflector::underscore($outputFile) . '.' . $this->ext; - $io->out("\n" . sprintf('Baking `%s` view template file...', $outputFile)); - $io->createFile($filename, $content, $this->force); + $this->io->out("\n" . sprintf('Baking `%s` view template file...', $outputFile)); + $this->io->createFile($filename, $content, $this->force); } /** * Builds content from template and variables * - * @param \Cake\Console\Arguments $args The CLI arguments - * @param \Cake\Console\ConsoleIo $io The console io * @param string $action name to generate content to * @param array|null $vars passed for use in templates * @return string Content from template */ - public function getContent(Arguments $args, ConsoleIo $io, string $action, ?array $vars = null): string + public function getContent(string $action, ?array $vars = null): string { if (!$vars) { - $vars = $this->_loadController($io); + $vars = $this->loadController(); } if (empty($vars['primaryKey'])) { - $io->error('Cannot generate views for models with no primary key'); + $this->io->error('Cannot generate views for models with no primary key'); $this->abort(); } @@ -418,8 +397,8 @@ public function getContent(Arguments $args, ConsoleIo $io, string $action, ?arra ->set($vars); $indexColumns = 0; - if ($action === 'index' && $args->getOption('index-columns') !== null) { - $indexColumns = $args->getOption('index-columns'); + if ($action === 'index' && $this->args->getOption('index-columns') !== null) { + $indexColumns = $this->args->getOption('index-columns'); } $renderer->set('indexColumns', $indexColumns); @@ -438,7 +417,7 @@ public function getContent(Arguments $args, ConsoleIo $io, string $action, ?arra */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $parser->setDescription( 'Bake views for a controller, using built-in or custom templates. ', @@ -467,12 +446,12 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\ORM\Table $model Table * @return array> associations */ - protected function _filteredAssociations(Table $model): array + protected function filteredAssociations(Table $model): array { - if (!$this->_associationFilter instanceof AssociationFilter) { - $this->_associationFilter = new AssociationFilter(); + if (!$this->associationFilter instanceof AssociationFilter) { + $this->associationFilter = new AssociationFilter(); } - return $this->_associationFilter->filterAssociations($model); + return $this->associationFilter->filterAssociations($model); } } diff --git a/src/Command/TestCommand.php b/src/Command/TestCommand.php index bdefcfb1a..58ddead33 100644 --- a/src/Command/TestCommand.php +++ b/src/Command/TestCommand.php @@ -16,7 +16,6 @@ */ namespace Bake\Command; -use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Controller\Controller; @@ -93,7 +92,7 @@ class TestCommand extends BakeCommand * * @var array */ - protected array $_fixtures = []; + protected array $fixtures = []; /** * @inheritDoc @@ -106,39 +105,35 @@ public static function getDescription(): string /** * Execute test generation * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io): ?int + public function execute(): ?int { - $this->extractCommonProperties($args); - if (!$args->hasArgument('type') && !$args->hasArgument('name')) { - $this->outputTypeChoices($io); + $this->extractCommonProperties($this->args); + if (!$this->args->hasArgument('type') && !$this->args->hasArgument('name')) { + $this->outputTypeChoices(); return null; } - $type = $this->normalize((string)$args->getArgument('type')); - - if ($args->getOption('all')) { - $this->_bakeAll($type, $args, $io); + $type = $this->normalize((string)$this->args->getArgument('type')); + if ($this->args->getOption('all')) { + $this->bakeAll($type); return null; } - if (!$args->hasArgument('name')) { - $this->outputClassChoices($type, $io); + if (!$this->args->hasArgument('name')) { + $this->outputClassChoices($type); return null; } - $name = (string)$args->getArgument('name'); - $name = $this->_getName($name); - - $result = $this->bake($type, $name, $args, $io); + $name = (string)$this->args->getArgument('name'); + $name = $this->getNameWithoutPrefix($name); + $result = $this->bake($type, $name); if ($result === static::CODE_ERROR) { return static::CODE_ERROR; } if ($result) { - $io->success('Done'); + $this->io->success('Done'); } return static::CODE_SUCCESS; @@ -147,68 +142,64 @@ public function execute(Arguments $args, ConsoleIo $io): ?int /** * Output a list of class types you can bake a test for. * - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function outputTypeChoices(ConsoleIo $io): void + protected function outputTypeChoices(): void { - $io->out( + $this->io->out( 'You must provide a class type to bake a test for. The valid types are:', 2, ); $i = 0; foreach (array_keys($this->classTypes) as $option) { - $io->out(++$i . '. ' . $option); + $this->io->out(++$i . '. ' . $option); } - $io->out(''); - $io->out('Re-run your command as `cake bake `'); + $this->io->out(''); + $this->io->out('Re-run your command as `cake bake `'); } /** * Output a list of possible classnames you might want to generate a test for. * * @param string $typeName The typename to get classes for. - * @param \Cake\Console\ConsoleIo $io The console io * @return void */ - protected function outputClassChoices(string $typeName, ConsoleIo $io): void + protected function outputClassChoices(string $typeName): void { $type = $this->mapType($typeName); - $io->out( + $this->io->out( 'You must provide a class to bake a test for. Some possible options are:', 2, ); - $options = $this->_getClassOptions($type); + $options = $this->getClassOptions($type); $i = 0; foreach ($options as $option) { - $io->out(++$i . '. ' . $option); + $this->io->out(++$i . '. ' . $option); } - $io->out(''); - $io->out('Re-run your command as `cake bake ' . $typeName . ' `'); + $this->io->out(''); + $this->io->out('Re-run your command as `cake bake ' . $typeName . ' `'); } /** * Bake all tests for one class type. * * @param string $type The typename to get bake all classes for. - * @param \Cake\Console\Arguments $args Arguments - * @param \Cake\Console\ConsoleIo $io ConsoleIo instance * @return void */ - protected function _bakeAll(string $type, Arguments $args, ConsoleIo $io): void + protected function bakeAll(string $type): void { $mappedType = $this->mapType($type); - $classes = $this->_getClassOptions($mappedType); + $classes = $this->getClassOptions($mappedType); foreach ($classes as $class) { - if ($this->bake($type, $class, $args, $io)) { - $io->success('Done - ' . $class); + if ($this->bake($type, $class)) { + $this->io->success('Done - ' . $class); } else { - $io->error('Failed - ' . $class); + $this->io->error('Failed - ' . $class); } } - $io->info('Bake finished'); + $this->io->info('Bake finished'); } /** @@ -217,7 +208,7 @@ protected function _bakeAll(string $type, Arguments $args, ConsoleIo $io): void * @param string $namespace The namespace fragment to look for classes in. * @return array */ - protected function _getClassOptions(string $namespace): array + protected function getClassOptions(string $namespace): array { $classes = []; $base = APP; @@ -229,7 +220,7 @@ protected function _getClassOptions(string $namespace): array // For generic Class type (empty namespace), search recursively if ($namespace === '') { - $files = (new Filesystem())->findRecursive($path, '/\.php$/'); + $files = new Filesystem()->findRecursive($path, '/\.php$/'); foreach ($files as $fileObj) { if ($fileObj->isFile() && $fileObj->getFileName() !== 'Application.php') { // Build the namespace path relative to App directory @@ -241,7 +232,7 @@ protected function _getClassOptions(string $namespace): array } } } else { - $files = (new Filesystem())->find($path); + $files = new Filesystem()->find($path); foreach ($files as $fileObj) { if ($fileObj->isFile()) { $classes[] = substr((string)$fileObj->getFileName(), 0, -4) ?: ''; @@ -258,11 +249,9 @@ protected function _getClassOptions(string $namespace): array * * @param string $type Type of object to bake test case for ie. Model, Controller * @param string $className the 'cake name' for the class ie. Posts for the PostsController - * @param \Cake\Console\Arguments $args Arguments - * @param \Cake\Console\ConsoleIo $io ConsoleIo instance - * @return string|bool|int Returns the generated code as string on success, false on failure, or CODE_ERROR for validation errors + * @return string|int|bool Returns the generated code as string on success, false on failure, or CODE_ERROR for validation errors */ - public function bake(string $type, string $className, Arguments $args, ConsoleIo $io): string|bool|int + public function bake(string $type, string $className): string|bool|int { $type = $this->normalize($type); if (!isset($this->classSuffixes[$type]) || !isset($this->classTypes[$type])) { @@ -271,28 +260,28 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo // For Class type, validate that backslashes are properly escaped if ($type === 'Class' && !str_contains($className, '\\')) { - $io->error('Class name appears to have no namespace separators.'); - $io->out(''); - $io->out('If you meant to specify a namespaced class, please use quotes:'); - $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'); + $this->io->error('Class name appears to have no namespace separators.'); + $this->io->out(''); + $this->io->out('If you meant to specify a namespaced class, please use quotes:'); + $this->io->out(" bin/cake bake test class '{$className}'"); + $this->io->out(''); + $this->io->out('Or specify without the base namespace:'); + $this->io->out(' bin/cake bake test class YourNamespace\ClassName'); return static::CODE_ERROR; } - $prefix = $this->getPrefix($args); + $prefix = $this->getPrefix(); $fullClassName = $this->getRealClassName($type, $className, $prefix); // For Class type, validate that the class exists if ($type === 'Class' && !class_exists($fullClassName)) { - $io->error("Class '{$fullClassName}' does not exist or cannot be loaded."); - $io->out(''); - $io->out('Please check:'); - $io->out(' - The class file exists in the correct location'); - $io->out(' - The class is properly autoloaded'); - $io->out(' - The namespace and class name are correct'); + $this->io->error("Class '{$fullClassName}' does not exist or cannot be loaded."); + $this->io->out(''); + $this->io->out('Please check:'); + $this->io->out(' - The class file exists in the correct location'); + $this->io->out(' - The class is properly autoloaded'); + $this->io->out(' - The namespace and class name are correct'); return static::CODE_ERROR; } @@ -300,14 +289,14 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo // Check if fixture factories plugin is available $hasFixtureFactories = $this->hasFixtureFactories(); - if (!$args->getOption('no-fixture')) { + if (!$this->args->getOption('no-fixture')) { if ($hasFixtureFactories) { - $io->info('Fixture Factories plugin detected - skipping fixture property generation.'); - } elseif ($args->getOption('fixtures')) { - $fixtures = array_map('trim', explode(',', (string)$args->getOption('fixtures'))); - $this->_fixtures = array_filter($fixtures); + $this->io->info('Fixture Factories plugin detected - skipping fixture property generation.'); + } elseif ($this->args->getOption('fixtures')) { + $fixtures = array_map('trim', explode(',', (string)$this->args->getOption('fixtures'))); + $this->fixtures = array_filter($fixtures); } elseif ($this->typeCanDetectFixtures($type) && class_exists($fullClassName)) { - $io->out('Bake is detecting possible fixtures...'); + $this->io->out('Bake is detecting possible fixtures...'); $testSubject = $this->buildTestSubject($type, $fullClassName); if ($testSubject instanceof Table || $testSubject instanceof Controller) { $this->generateFixtureList($testSubject); @@ -334,16 +323,16 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo $baseNamespace = Configure::read('App.namespace'); if ($this->plugin) { - $baseNamespace = $this->_pluginNamespace($this->plugin); + $baseNamespace = $this->pluginNamespace($this->plugin); } $subNamespace = substr($namespace, strlen((string)$baseNamespace) + 1); $properties = $this->generateProperties($type, $subject, $fullClassName); - $io->out("\n" . sprintf('Baking test case for %s ...', $fullClassName), 1, ConsoleIo::QUIET); + $this->io->out("\n" . sprintf('Baking test case for %s ...', $fullClassName), 1, ConsoleIo::QUIET); $contents = $this->createTemplateRenderer() - ->set('fixtures', $this->_fixtures) + ->set('fixtures', $this->fixtures) ->set('plugin', $this->plugin) ->set('hasFixtureFactories', $hasFixtureFactories) ->set(compact( @@ -366,8 +355,8 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo $filename = $this->testCaseFileName($type, $fullClassName); $emptyFile = dirname($filename) . DS . '.gitkeep'; - $this->deleteEmptyFile($emptyFile, $io); - if ($io->createFile($filename, $contents, $this->force)) { + $this->deleteEmptyFile($emptyFile); + if ($this->io->createFile($filename, $contents, $this->force)) { return $contents; } @@ -530,14 +519,14 @@ public function getTestableMethods(string $className): array */ public function generateFixtureList(Table|Controller $subject): array { - $this->_fixtures = []; + $this->fixtures = []; if ($subject instanceof Table) { - $this->_processModel($subject); + $this->processModel($subject); } else { - $this->_processController($subject); + $this->processController($subject); } - return array_values($this->_fixtures); + return array_values($this->fixtures); } /** @@ -546,9 +535,9 @@ public function generateFixtureList(Table|Controller $subject): array * @param \Cake\ORM\Table $subject A Model class to scan for associations and pull fixtures off of. * @return void */ - protected function _processModel(Table $subject): void + protected function processModel(Table $subject): void { - $this->_addFixture($subject->getAlias()); + $this->addFixture($subject->getAlias()); foreach ($subject->associations()->keys() as $alias) { $assoc = $subject->getAssociation($alias); $target = $assoc->getTarget(); @@ -558,8 +547,8 @@ protected function _processModel(Table $subject): void if ($subjectClass !== Table::class && $subjectClass === $target::class) { continue; } - if (!isset($this->_fixtures[$name])) { - $this->_addFixture($target->getAlias()); + if (!isset($this->fixtures[$name])) { + $this->addFixture($target->getAlias()); } } } @@ -571,7 +560,7 @@ protected function _processModel(Table $subject): void * @param \Cake\Controller\Controller $subject A controller to pull model names off of. * @return void */ - protected function _processController(Controller $subject): void + protected function processController(Controller $subject): void { try { $model = $subject->fetchTable(); @@ -583,7 +572,7 @@ protected function _processController(Controller $subject): void $models = [$model->getAlias()]; foreach ($models as $model) { [, $model] = pluginSplit($model); - $this->_processModel($subject->{$model}); + $this->processModel($subject->{$model}); } } @@ -594,11 +583,11 @@ protected function _processController(Controller $subject): void * @param string $name Name of the Model class that a fixture might be required for. * @return void */ - protected function _addFixture(string $name): void + protected function addFixture(string $name): void { $prefix = $this->plugin ? 'plugin.' . $this->plugin . '.' : 'app.'; - $fixture = $prefix . $this->_fixtureName($name); - $this->_fixtures[$name] = $fixture; + $fixture = $prefix . $this->fixtureName($name); + $this->fixtures[$name] = $fixture; } /** @@ -623,7 +612,9 @@ public function hasMockClass(string $type): bool public function generateConstructor(string $type, string $fullClassName): array { [, $className] = namespaceSplit($fullClassName); - $pre = $construct = $post = ''; + $pre = ''; + $construct = ''; + $post = ''; if ($type === 'Table') { $tableName = str_replace('Table', '', $className); $pre = "\$config = \$this->getTableLocator()->exists('{$tableName}') " . @@ -775,7 +766,7 @@ public function getBasePath(): string { $dir = 'TestCase/'; if ($this->plugin) { - return $this->_pluginPath($this->plugin) . 'tests/' . $dir; + return $this->pluginPath($this->plugin) . 'tests/' . $dir; } return defined('TESTS') ? TESTS . $dir : ROOT . DS . 'tests' . DS . $dir; @@ -811,7 +802,7 @@ public function testCaseFileName(string $type, string $className): string */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser = $this->_setCommonOptions($parser); + $parser = $this->setCommonOptions($parser); $types = array_keys($this->classTypes); $types = array_merge($types, array_map($this->underscore(...), $types)); diff --git a/src/Utility/CommonOptionsTrait.php b/src/Utility/CommonOptionsTrait.php index 64ee4c859..9198f1b96 100644 --- a/src/Utility/CommonOptionsTrait.php +++ b/src/Utility/CommonOptionsTrait.php @@ -52,7 +52,7 @@ protected function extractCommonProperties(Arguments $args): void if ($args->hasOption('plugin')) { $plugin = (string)$args->getOption('plugin'); $parts = explode('/', $plugin); - $this->plugin = implode('/', array_map([$this, '_camelize'], $parts)); + $this->plugin = implode('/', array_map([$this, 'camelize'], $parts)); if (strpos($this->plugin, '\\')) { throw new InvalidArgumentException( @@ -73,7 +73,7 @@ protected function extractCommonProperties(Arguments $args): void * * @return list */ - protected function _getBakeThemes(): array + protected function getBakeThemes(): array { $bakeThemes = []; $templates = 'templates' . DS . 'bake'; @@ -93,7 +93,7 @@ protected function _getBakeThemes(): array * @param \Cake\Console\ConsoleOptionParser $parser Options parser. * @return \Cake\Console\ConsoleOptionParser */ - protected function _setCommonOptions(ConsoleOptionParser $parser): ConsoleOptionParser + protected function setCommonOptions(ConsoleOptionParser $parser): ConsoleOptionParser { $parser->addOption('plugin', [ 'short' => 'p', @@ -111,7 +111,7 @@ protected function _setCommonOptions(ConsoleOptionParser $parser): ConsoleOption 'short' => 't', 'help' => 'The theme to use when baking code.', 'default' => Configure::read('Bake.theme') ?? '', - 'choices' => $this->_getBakeThemes(), + 'choices' => $this->getBakeThemes(), ]); return $parser; diff --git a/src/Utility/Model/EnumParser.php b/src/Utility/Model/EnumParser.php index ac80024b8..bcd8b390c 100644 --- a/src/Utility/Model/EnumParser.php +++ b/src/Utility/Model/EnumParser.php @@ -20,7 +20,8 @@ public static function parseCases(?string $casesString, bool $int): array $definition = []; foreach ($enumCases as $k => $enumCase) { - $case = $value = trim($enumCase); + $case = trim($enumCase); + $value = $case; $pos = strpos($case, ':'); if ($pos !== false) { $value = trim(mb_substr($case, $pos + 1)); diff --git a/src/Utility/Process.php b/src/Utility/Process.php index 27c9cc155..ce1dc076e 100644 --- a/src/Utility/Process.php +++ b/src/Utility/Process.php @@ -16,7 +16,7 @@ */ namespace Bake\Utility; -use Cake\Console\ConsoleIo; +use Cake\Console\ConsoleIoInterface; use RuntimeException; /** @@ -26,16 +26,13 @@ */ class Process { - protected ConsoleIo $io; - /** * Constructor * - * @param \Cake\Console\ConsoleIo $io The console io + * @param \Cake\Console\ConsoleIoInterface $io The console io */ - public function __construct(ConsoleIo $io) + public function __construct(protected ConsoleIoInterface $io) { - $this->io = $io; } /** diff --git a/src/Utility/SubsetSchemaCollection.php b/src/Utility/SubsetSchemaCollection.php index 995a31e65..8c7de605c 100644 --- a/src/Utility/SubsetSchemaCollection.php +++ b/src/Utility/SubsetSchemaCollection.php @@ -27,21 +27,12 @@ */ class SubsetSchemaCollection implements CollectionInterface { - protected CollectionInterface $collection; - - /** - * @var array - */ - protected array $tables = []; - /** * @param \Cake\Database\Schema\CollectionInterface $collection The wrapped collection * @param list $tables The subset of tables. */ - public function __construct(CollectionInterface $collection, array $tables) + public function __construct(protected CollectionInterface $collection, protected array $tables) { - $this->collection = $collection; - $this->tables = $tables; } /** @@ -64,6 +55,16 @@ public function listTables(): array return $this->tables; } + /** + * Get the list of tables in this schema collection. + * + * @return array + */ + public function listTablesWithoutViews(): array + { + return $this->tables; + } + /** * @inheritDoc */ diff --git a/src/Utility/TableScanner.php b/src/Utility/TableScanner.php index ace2b00ca..d631b52b1 100644 --- a/src/Utility/TableScanner.php +++ b/src/Utility/TableScanner.php @@ -29,8 +29,6 @@ */ class TableScanner { - protected Connection $connection; - /** * @var array */ @@ -43,12 +41,9 @@ class TableScanner * @param array|null $ignore List of tables or regex pattern to ignore. If null, the default ignore * list will be used. */ - public function __construct(Connection $connection, ?array $ignore = null) + public function __construct(protected Connection $connection, ?array $ignore = null) { - $this->connection = $connection; - if ($ignore === null) { - $ignore = ['i18n', 'cake_sessions', 'cake_migrations', 'cake_seeds', 'sessions', '/phinxlog/']; - } + $ignore ??= ['i18n', 'cake_sessions', 'cake_migrations', 'cake_seeds', 'sessions', '/phinxlog/']; $this->ignore = $ignore; } @@ -61,7 +56,7 @@ public function listAll(): array { $schema = $this->connection->getSchemaCollection(); $tables = $schema->listTables(); - if (!$tables) { + if ($tables === []) { throw new RuntimeException('Your database does not have any tables.'); } sort($tables); diff --git a/src/Utility/TemplateRenderer.php b/src/Utility/TemplateRenderer.php index 89f5360a7..09a03a178 100644 --- a/src/Utility/TemplateRenderer.php +++ b/src/Utility/TemplateRenderer.php @@ -37,19 +37,13 @@ class TemplateRenderer */ protected ?BakeView $view = null; - /** - * Template theme - */ - protected ?string $theme; - /** * Constructor * * @param ?string $theme The template theme/plugin to use. */ - public function __construct(?string $theme = null) + public function __construct(protected ?string $theme = null) { - $this->theme = $theme; } /** diff --git a/src/View/BakeView.php b/src/View/BakeView.php index b6a6abb4b..3f74572cb 100644 --- a/src/View/BakeView.php +++ b/src/View/BakeView.php @@ -78,20 +78,18 @@ public function render(?string $template = null, string|false|null $layout = nul { assert($template !== null, 'Template name must be provided.'); - $viewFileName = $this->_getTemplateFileName($template); + $viewFileName = $this->getTemplateFileName($template); [, $templateEventName] = pluginSplit($template); $templateEventName = str_replace(['/', '\\'], '.', $templateEventName); - $this->_currentType = static::TYPE_TEMPLATE; + $this->currentType = static::TYPE_TEMPLATE; $this->dispatchEvent('View.beforeRender', [$viewFileName]); $this->dispatchEvent('View.beforeRender.' . $templateEventName, [$viewFileName]); - $this->Blocks->set('content', $this->_render($viewFileName)); + $this->Blocks->set('content', $this->renderFile($viewFileName)); $this->dispatchEvent('View.afterRender', [$viewFileName]); $this->dispatchEvent('View.afterRender.' . $templateEventName, [$viewFileName]); - if ($layout === null) { - $layout = $this->layout; - } + $layout ??= $this->layout; if ($layout && $this->autoLayout) { $this->Blocks->set('content', $this->renderLayout('', $layout)); } @@ -126,9 +124,9 @@ public function dispatchEvent(string $name, array $data = [], ?object $subject = * @param bool $cached Set to false to force a refresh of view paths. Default true. * @return array paths */ - protected function _paths(?string $plugin = null, bool $cached = true): array + protected function paths(?string $plugin = null, bool $cached = true): array { - $paths = parent::_paths($plugin, false); + $paths = parent::paths($plugin, false); foreach ($paths as &$path) { // Append 'bake' to all directories that aren't the application override directory. if (!str_contains($path, 'plugin' . DS . 'Bake')) { diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index 3c7b01aef..1358d8e2f 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -33,12 +33,12 @@ class BakeHelper extends Helper * * @var array */ - protected array $_defaultConfig = []; + protected array $defaultConfig = []; /** * AssociationFilter utility */ - protected ?AssociationFilter $_associationFilter = null; + protected ?AssociationFilter $associationFilter = null; /** * Used for generating formatted properties such as component and helper arrays @@ -50,7 +50,7 @@ class BakeHelper extends Helper */ public function arrayProperty(string $name, array $value = [], array $options = []): string { - if (!$value) { + if ($value === []) { return ''; } @@ -62,7 +62,7 @@ public function arrayProperty(string $name, array $value = [], array $options = 'value' => $value, ]; - return $this->_View->element('array_property', $options); + return $this->View->element('array_property', $options); } /** @@ -119,7 +119,7 @@ public function aliasExtractor(Table $table, string $assoc): array }; $aliases = array_map($extractor, $table->associations()->getByType($assoc)); if ($assoc === 'HasMany') { - return $this->_filterHasManyAssociationsAliases($table, $aliases); + return $this->filterHasManyAssociationsAliases($table, $aliases); } return $aliases; @@ -544,12 +544,10 @@ public function concat( * @param array $aliases array of aliases * @return array */ - protected function _filterHasManyAssociationsAliases(Table $table, array $aliases): array + protected function filterHasManyAssociationsAliases(Table $table, array $aliases): array { - if (is_null($this->_associationFilter)) { - $this->_associationFilter = new AssociationFilter(); - } + $this->associationFilter ??= new AssociationFilter(); - return $this->_associationFilter->filterHasManyAssociationsAliases($table, $aliases); + return $this->associationFilter->filterHasManyAssociationsAliases($table, $aliases); } } diff --git a/src/View/Helper/DocBlockHelper.php b/src/View/Helper/DocBlockHelper.php index c94ed29a7..78d6e71b7 100644 --- a/src/View/Helper/DocBlockHelper.php +++ b/src/View/Helper/DocBlockHelper.php @@ -21,7 +21,7 @@ class DocBlockHelper extends Helper /** * @var bool Whether to add a blank line between different class annotations */ - protected bool $_annotationSpacing = true; + protected bool $annotationSpacing = true; /** * Writes the DocBlock header for a class which includes the property and method declarations. Annotations are @@ -48,7 +48,7 @@ public function classDescription(string $className, string $classType, array $an if (strlen($annotation) > 1 && $annotation[0] === '@' && strpos($annotation, ' ') > 0) { $type = substr($annotation, 0, strpos($annotation, ' ')); if ( - $this->_annotationSpacing && + $this->annotationSpacing && $previous !== false && $previous !== $type ) { @@ -59,7 +59,7 @@ public function classDescription(string $className, string $classType, array $an $lines[] = $annotation; } - $lines = array_merge(['/**'], (new Collection($lines))->map(function ($line): string { + $lines = array_merge(['/**'], new Collection($lines)->map(function ($line): string { return rtrim(" * {$line}"); })->toArray(), [' */']); @@ -150,7 +150,7 @@ public function buildEntityAssociationHintTypeMap(array $propertySchema): array if ($info['kind'] === 'association') { $type = $this->associatedEntityTypeToHintType($info['type'], $info['association']); if ($info['association']->type() === Association::MANY_TO_ONE) { - $properties = $this->_insertAfter( + $properties = $this->insertAfter( $properties, $info['association']->getForeignKey(), [$property => $type], @@ -329,7 +329,7 @@ public function buildTableAnnotations( * @param mixed $value The entry to insert. * @return array The array with the new value inserted. */ - protected function _insertAfter(array $target, string $key, mixed $value): array + protected function insertAfter(array $target, string $key, mixed $value): array { $index = array_search($key, array_keys($target), true); if ($index !== false) { diff --git a/templates/bake/Command/command.twig b/templates/bake/Command/command.twig index 54aec5479..ef134acdd 100644 --- a/templates/bake/Command/command.twig +++ b/templates/bake/Command/command.twig @@ -17,8 +17,6 @@ namespace: "#{namespace}\\Command", classImports: [ 'Cake\\Command\\Command', - 'Cake\\Console\\Arguments', - 'Cake\\Console\\ConsoleIo', 'Cake\\Console\\ConsoleOptionParser', ], }) }} @@ -71,11 +69,9 @@ class {{ name }}Command extends Command /** * Implement this method with your command's logic. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null|void The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io) + public function execute() { } } diff --git a/templates/bake/Model/entity.twig b/templates/bake/Model/entity.twig index ab924dd7b..c282602fc 100644 --- a/templates/bake/Model/entity.twig +++ b/templates/bake/Model/entity.twig @@ -39,7 +39,7 @@ class {{ name }} extends Entity{{ fileBuilder.classBuilder.implements ? ' implem {% endif %} {% if accessible %} -{%~ set generatedProperties = generatedProperties|merge(['_accessible']) %} +{%~ set generatedProperties = generatedProperties|merge(['patchable']) %} /** * Fields that can be mass assigned using newEntity() or patchEntity(). * @@ -49,19 +49,19 @@ class {{ name }} extends Entity{{ fileBuilder.classBuilder.implements ? ' implem * * @var array */ - protected array $_accessible = {{ Bake.exportVar(accessible, 1)|raw }}; + protected array $patchable = {{ Bake.exportVar(accessible, 1)|raw }}; {% endif %} {% if accessible and hidden %} {% endif %} {% if hidden %} - {%~ set generatedProperties = generatedProperties|merge(['_hidden']) %} + {%~ set generatedProperties = generatedProperties|merge(['hidden']) %} /** * Fields that are excluded from JSON versions of the entity. * * @var array */ - protected array $_hidden = {{ Bake.exportVar(hidden, 1)|raw }}; + protected array $hidden = {{ Bake.exportVar(hidden, 1)|raw }}; {% endif %} {% set userProperties = fileBuilder.classBuilder.userProperties(generatedProperties) %} {% if userProperties %} diff --git a/templates/bake/View/cell.twig b/templates/bake/View/cell.twig index 922ba54e7..ce72b3ee5 100644 --- a/templates/bake/View/cell.twig +++ b/templates/bake/View/cell.twig @@ -31,7 +31,7 @@ class {{ name }}Cell extends Cell * * @var array */ - protected array $_validCellOptions = []; + protected array $validCellOptions = []; /** * Initialization logic run at the end of object construction. diff --git a/tests/TestCase/CodeGen/FileBuilderTest.php b/tests/TestCase/CodeGen/FileBuilderTest.php index 8eb62e96f..f3e8544df 100644 --- a/tests/TestCase/CodeGen/FileBuilderTest.php +++ b/tests/TestCase/CodeGen/FileBuilderTest.php @@ -26,11 +26,6 @@ class FileBuilderTest extends TestCase { - /** - * @var \Cake\TestSuite\Stub\ConsoleOutput - */ - protected $out; - /** * @var \Cake\Console\ConsoleIo */ diff --git a/tests/TestCase/Command/CellCommandTest.php b/tests/TestCase/Command/CellCommandTest.php index 10be3815f..936e90f0d 100644 --- a/tests/TestCase/Command/CellCommandTest.php +++ b/tests/TestCase/Command/CellCommandTest.php @@ -33,7 +33,7 @@ class CellCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Cell' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Cell' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -64,7 +64,7 @@ public function testMain(): void */ public function testMainPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ @@ -86,7 +86,7 @@ public function testMainPlugin(): void */ public function testBakePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ @@ -127,7 +127,7 @@ public function testMainPrefix(): void */ public function testMainPrefixPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ diff --git a/tests/TestCase/Command/CommandCommandTest.php b/tests/TestCase/Command/CommandCommandTest.php index 65e7f8aba..2056f89fd 100644 --- a/tests/TestCase/Command/CommandCommandTest.php +++ b/tests/TestCase/Command/CommandCommandTest.php @@ -33,7 +33,7 @@ class CommandCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Command' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Command' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -63,7 +63,7 @@ public function testMain(): void */ public function testMainPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ @@ -84,7 +84,7 @@ public function testMainPlugin(): void */ public function testBakePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ diff --git a/tests/TestCase/Command/CommandHelperTest.php b/tests/TestCase/Command/CommandHelperTest.php index 01fa12bc7..f37ef67c2 100644 --- a/tests/TestCase/Command/CommandHelperTest.php +++ b/tests/TestCase/Command/CommandHelperTest.php @@ -33,7 +33,7 @@ class CommandHelperTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Command' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Command' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -54,7 +54,7 @@ public function testBakeCommandHelper(): void $this->assertFilesExist($this->generatedFiles); $this->assertSameAsFile(__FUNCTION__ . '.php', file_get_contents($this->generatedFiles[0])); - $testsPath = dirname($this->_compareBasePath) . DS . 'Test' . DS; + $testsPath = dirname($this->compareBasePath) . DS . 'Test' . DS; $this->assertSameAsFile($testsPath . __FUNCTION__ . 'Test.php', file_get_contents($this->generatedFiles[1])); } @@ -65,7 +65,7 @@ public function testBakeCommandHelper(): void */ public function testBakeCommandHelperPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ diff --git a/tests/TestCase/Command/ControllerAllCommandTest.php b/tests/TestCase/Command/ControllerAllCommandTest.php index e5882a743..70593d418 100644 --- a/tests/TestCase/Command/ControllerAllCommandTest.php +++ b/tests/TestCase/Command/ControllerAllCommandTest.php @@ -52,7 +52,7 @@ class ControllerAllCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Controller' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Controller' . DS; $this->setAppNamespace('Bake\Test\App'); $this->getTableLocator()->get('BakeArticles', [ diff --git a/tests/TestCase/Command/ControllerCommandTest.php b/tests/TestCase/Command/ControllerCommandTest.php index 2c6731570..e3e65f7bc 100644 --- a/tests/TestCase/Command/ControllerCommandTest.php +++ b/tests/TestCase/Command/ControllerCommandTest.php @@ -51,7 +51,7 @@ class ControllerCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Controller' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Controller' . DS; $this->setAppNamespace('Bake\Test\App'); $this->getTableLocator()->get('BakeArticles', [ @@ -97,11 +97,13 @@ public function testGetComponents(): void { $command = new ControllerCommand(); $args = new Arguments([], [], []); - $result = $command->getComponents($args); + $command->setArgs($args); + $result = $command->getComponents(); $this->assertSame([], $result); $args = new Arguments([], ['components' => ' , Auth, , RequestHandler'], []); - $result = $command->getComponents($args); + $command->setArgs($args); + $result = $command->getComponents(); $this->assertSame(['Auth', 'RequestHandler'], $result); } @@ -112,15 +114,17 @@ public function testGetComponents(): void */ public function testGetComponentsInferredDefaults(): void { - $this->_loadTestPlugin('Authorization'); + $this->loadTestPlugin('Authorization'); $command = new ControllerCommand(); $args = new Arguments([], [], []); - $result = $command->getComponents($args); + $command->setArgs($args); + $result = $command->getComponents(); $this->assertSame(['Authorization.Authorization'], $result); $args = new Arguments([], ['components' => 'Flash, FormProtection'], []); - $result = $command->getComponents($args); + $command->setArgs($args); + $result = $command->getComponents(); $this->assertSame(['Flash', 'FormProtection'], $result); } @@ -133,11 +137,13 @@ public function testGetHelpers(): void { $command = new ControllerCommand(); $args = new Arguments([], [], []); - $result = $command->getHelpers($args); + $command->setArgs($args); + $result = $command->getHelpers(); $this->assertSame([], $result); $args = new Arguments([], ['helpers' => ' , Session , , Number'], []); - $result = $command->getHelpers($args); + $command->setArgs($args); + $result = $command->getHelpers(); $this->assertSame(['Session', 'Number'], $result); } @@ -220,7 +226,7 @@ public function testBakeActions(): void */ public function testBakeActionsAuthorizationPlugin(): void { - $this->_loadTestPlugin('Authorization'); + $this->loadTestPlugin('Authorization'); $this->generatedFile = APP . 'Controller/BakeArticlesController.php'; $this->exec('bake controller --connection test --no-test BakeArticles'); @@ -235,7 +241,7 @@ public function testBakeActionsAuthorizationPlugin(): void */ public function testBakeActionsAuthenticationPlugin(): void { - $this->_loadTestPlugin('Authentication'); + $this->loadTestPlugin('Authentication'); $generatedFile = APP . 'Controller/UsersController.php'; $exists = file_exists($generatedFile); @@ -289,7 +295,7 @@ public function testBakePrefixNested(): void */ public function testBakeWithPlugin(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $path = Plugin::path('BakeTest'); $this->generatedFile = $path . 'src/Controller/BakeArticlesController.php'; @@ -402,7 +408,7 @@ public function testMainWithControllerNameVariations(string $name): void */ public function testMainWithPluginDot(): void { - $this->_loadTestPlugin('Company/Pastry'); + $this->loadTestPlugin('Company/Pastry'); $path = Plugin::path('Company/Pastry'); $this->generatedFile = $path . 'src/Controller/BakeArticlesController.php'; @@ -423,7 +429,7 @@ public function testMainWithPluginDot(): void */ public function testMainWithPluginOption(): void { - $this->_loadTestPlugin('Company/Pastry'); + $this->loadTestPlugin('Company/Pastry'); $path = Plugin::path('Company/Pastry'); $this->generatedFile = $path . 'src/Controller/BakeArticlesController.php'; diff --git a/tests/TestCase/Command/EntryCommandTest.php b/tests/TestCase/Command/EntryCommandTest.php index 712582b34..f53f75338 100644 --- a/tests/TestCase/Command/EntryCommandTest.php +++ b/tests/TestCase/Command/EntryCommandTest.php @@ -58,7 +58,7 @@ public function testExecuteHelp(): void $this->assertExitCode(CommandInterface::CODE_SUCCESS); // Output format varies between CakePHP versions - $output = $this->_out->output(); + $output = $this->out->output(); $this->assertTrue( str_contains($output, 'Available Commands') || str_contains($output, 'bake:'), 'Expected help output to contain command listing', @@ -102,7 +102,7 @@ public function testExecuteAppTaskHelp(): void */ public function testExecutePluginCommand(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $this->exec('bake zergling --verbose'); diff --git a/tests/TestCase/Command/EnumCommandTest.php b/tests/TestCase/Command/EnumCommandTest.php index d78496693..f842adc7c 100644 --- a/tests/TestCase/Command/EnumCommandTest.php +++ b/tests/TestCase/Command/EnumCommandTest.php @@ -33,7 +33,7 @@ class EnumCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; $this->setAppNamespace('Bake\Test\App'); } diff --git a/tests/TestCase/Command/FixtureAllCommandTest.php b/tests/TestCase/Command/FixtureAllCommandTest.php index 0544a1d7c..520901efe 100644 --- a/tests/TestCase/Command/FixtureAllCommandTest.php +++ b/tests/TestCase/Command/FixtureAllCommandTest.php @@ -51,7 +51,7 @@ protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Fixture' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Fixture' . DS; $this->setAppNamespace('Bake\Test\App'); $connection = ConnectionManager::get('test'); diff --git a/tests/TestCase/Command/FixtureCommandTest.php b/tests/TestCase/Command/FixtureCommandTest.php index 866ab4fc3..031c78634 100644 --- a/tests/TestCase/Command/FixtureCommandTest.php +++ b/tests/TestCase/Command/FixtureCommandTest.php @@ -55,7 +55,7 @@ protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Fixture' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Fixture' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -73,7 +73,8 @@ public function testValidateNamesWithValid(): void $abortCalled = false; try { $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $command->validateNames($schema, $io); + $command->setIo($io); + $command->validateNames($schema); } catch (StopException) { $abortCalled = true; } @@ -93,7 +94,8 @@ public function testValidateNamesWithInvalid(): void $this->expectException(StopException::class); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $command->validateNames($schema, $io); + $command->setIo($io); + $command->validateNames($schema); } /** @@ -109,7 +111,8 @@ public function testValidateNamesWithInvalidSpecialChars(): void $this->expectException(StopException::class); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $command->validateNames($schema, $io); + $command->setIo($io); + $command->validateNames($schema); } /** @@ -295,7 +298,7 @@ public function testRecordGenerationForDatatypes(): void $this->assertStringContainsString("'columns' => ['id']", $result); $this->assertStringContainsString("'uuid' => ['type' => 'uuid'", $result); $this->assertMatchesRegularExpression( - "/(\s+)('uuid' => ')([a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12})(')/", + "/(\s+)('uuid' => ')([a-f0-9]{8}-[a-f0-9]{4}-[7][a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12})(')/", $result, ); } @@ -358,7 +361,7 @@ public function testGenerateFixtureFileRemappedJsonTypes(): void */ public function testGeneratePluginFixtureFile(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $root = Plugin::path('TestBake'); $this->generatedFile = $root . 'tests/Fixture/ArticlesFixture.php'; diff --git a/tests/TestCase/Command/MailerCommandTest.php b/tests/TestCase/Command/MailerCommandTest.php index dd11c2d21..caa2e3064 100644 --- a/tests/TestCase/Command/MailerCommandTest.php +++ b/tests/TestCase/Command/MailerCommandTest.php @@ -33,7 +33,7 @@ class MailerCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Mailer' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Mailer' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -62,7 +62,7 @@ public function testMain(): void */ public function testMainPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ @@ -84,7 +84,7 @@ public function testMainPlugin(): void */ public function testBakePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $templatePath = Plugin::templatePath('TestBake'); diff --git a/tests/TestCase/Command/MiddlewareCommandTest.php b/tests/TestCase/Command/MiddlewareCommandTest.php index afd49befc..bc01ad9eb 100644 --- a/tests/TestCase/Command/MiddlewareCommandTest.php +++ b/tests/TestCase/Command/MiddlewareCommandTest.php @@ -33,7 +33,7 @@ class MiddlewareCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Middleware' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Middleware' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -58,7 +58,7 @@ public function testMain(): void */ public function testMainPlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFile = $path . 'src/Middleware/ExampleMiddleware.php'; @@ -75,7 +75,7 @@ public function testMainPlugin(): void */ public function testBakePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFile = $path . 'src/Middleware/ExampleMiddleware.php'; diff --git a/tests/TestCase/Command/ModelCommandAssociationDetectionTest.php b/tests/TestCase/Command/ModelCommandAssociationDetectionTest.php index 5e30da66c..f19414fa6 100644 --- a/tests/TestCase/Command/ModelCommandAssociationDetectionTest.php +++ b/tests/TestCase/Command/ModelCommandAssociationDetectionTest.php @@ -54,7 +54,7 @@ class ModelCommandAssociationDetectionTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; $this->setAppNamespace('Bake\Test\App'); $this->getTableLocator()->clear(); @@ -76,7 +76,7 @@ protected function tearDown(): void * * @return void */ - protected function _compareBakeTableResult($name, string $comparisonFile) + protected function compareBakeTableResult($name, string $comparisonFile) { $this->generatedFiles = [ APP . "Model/Table/{$name}Table.php", @@ -97,7 +97,7 @@ public function testBakeAssociationDetectionCategoriesTable(): void { $driver = ConnectionManager::get('test')->getDriver(); $this->skipIf($driver instanceof Mysql, 'Incompatible with mysql'); - $this->_compareBakeTableResult('Categories', __FUNCTION__); + $this->compareBakeTableResult('Categories', __FUNCTION__); } /** @@ -111,7 +111,7 @@ public function testBakeAssociationDetectionCategoriesTableSigned(): void $this->skipIf($driver instanceof Sqlite, 'Incompatible with sqlite'); $this->skipIf($driver instanceof Postgres, 'Incompatible with postgres'); $this->skipIf($driver instanceof Sqlserver, 'Incompatible with sqlserver'); - $this->_compareBakeTableResult('Categories', __FUNCTION__); + $this->compareBakeTableResult('Categories', __FUNCTION__); } /** @@ -121,7 +121,7 @@ public function testBakeAssociationDetectionCategoriesTableSigned(): void */ public function testBakeAssociationDetectionCategoriesProductsTable(): void { - $this->_compareBakeTableResult('CategoriesProducts', __FUNCTION__); + $this->compareBakeTableResult('CategoriesProducts', __FUNCTION__); } /** @@ -133,7 +133,7 @@ public function testBakeAssociationDetectionOldProductsTable(): void { $driver = ConnectionManager::get('test')->getDriver(); $this->skipIf($driver instanceof Mysql, 'Incompatible with mysql'); - $this->_compareBakeTableResult('OldProducts', __FUNCTION__); + $this->compareBakeTableResult('OldProducts', __FUNCTION__); } /** @@ -147,7 +147,7 @@ public function testBakeAssociationDetectionOldProductsTableSigned(): void $this->skipIf($driver instanceof Sqlite, 'Incompatible with sqlite'); $this->skipIf($driver instanceof Postgres, 'Incompatible with postgres'); $this->skipIf($driver instanceof Sqlserver, 'Incompatible with sqlserver'); - $this->_compareBakeTableResult('OldProducts', __FUNCTION__); + $this->compareBakeTableResult('OldProducts', __FUNCTION__); } /** @@ -160,7 +160,7 @@ public function testBakeAssociationDetectionProductVersionsTable(): void $driver = ConnectionManager::get('test')->getDriver(); $this->skipIf($driver instanceof Mysql, 'Incompatible with mysql'); $this->skipIf($driver instanceof Sqlite, 'Incompatible with sqlite'); - $this->_compareBakeTableResult('ProductVersions', __FUNCTION__); + $this->compareBakeTableResult('ProductVersions', __FUNCTION__); } /** @@ -173,6 +173,6 @@ public function testBakeAssociationDetectionProductVersionsTableSigned(): void $driver = ConnectionManager::get('test')->getDriver(); $this->skipIf($driver instanceof Postgres, 'Incompatible with postgres'); $this->skipIf($driver instanceof Sqlserver, 'Incompatible with sqlserver'); - $this->_compareBakeTableResult('ProductVersions', __FUNCTION__); + $this->compareBakeTableResult('ProductVersions', __FUNCTION__); } } diff --git a/tests/TestCase/Command/ModelCommandTest.php b/tests/TestCase/Command/ModelCommandTest.php index dd34feb5e..14eb58b80 100644 --- a/tests/TestCase/Command/ModelCommandTest.php +++ b/tests/TestCase/Command/ModelCommandTest.php @@ -71,7 +71,7 @@ class ModelCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Model' . DS; $this->setAppNamespace('Bake\Test\App'); $this->getTableLocator()->clear(); @@ -114,11 +114,13 @@ public function testGetTable(): void { $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getTable('TodoItems', $args); + $command->setArgs($args); + $result = $command->getTable('TodoItems'); $this->assertSame('todo_items', $result); $args = new Arguments([], ['table' => 'items'], []); - $result = $command->getTable('TodoItems', $args); + $command->setArgs($args); + $result = $command->getTable('TodoItems'); $this->assertSame('items', $result); } @@ -178,7 +180,8 @@ public function testValidateNamesWithValid(): void $abortCalled = false; try { $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $command->validateNames($schema, $io); + $command->setIo($io); + $command->validateNames($schema); } catch (StopException) { $abortCalled = true; } @@ -198,7 +201,8 @@ public function testValidateNamesWithInvalid(): void $this->expectException(StopException::class); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $command->validateNames($schema, $io); + $command->setIo($io); + $command->validateNames($schema); } /** @@ -296,7 +300,9 @@ public function testGetAssociationsSkipsSelfReferencingKey(): void $command->connection = 'test'; $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($systems, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($systems); $aliases = array_merge( array_column($result['belongsTo'], 'alias'), @@ -323,7 +329,9 @@ public function testGetAssociationsKeepsConstrainedSelfReference(): void $command->connection = 'test'; $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($nodes, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($nodes); $this->assertSame(['Nodes'], array_column($result['belongsTo'], 'alias')); @@ -345,7 +353,9 @@ public function testGetAssociationsSkipsUniqueSelfReferencingKey(): void $command->connection = 'test'; $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($gadgets, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($gadgets); $aliases = array_merge( array_column($result['belongsTo'], 'alias'), @@ -372,7 +382,9 @@ public function testGetAssociations(): void $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($items, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($items); $expected = [ 'belongsTo' => [ @@ -419,7 +431,9 @@ public function testGetAssociationsNoFlag(): void $arguments = new Arguments([], ['no-associations' => true], []); $io = $this->createStub(ConsoleIo::class); $articles = $this->getTableLocator()->get('BakeArticle'); - $this->assertEquals([], $command->getAssociations($articles, $arguments, $io)); + $command->setArgs($arguments); + $command->setIo($io); + $this->assertEquals([], $command->getAssociations($articles)); } /** @@ -436,7 +450,9 @@ public function testGetAssociationsPlugin(): void $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($items, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($items); $expected = [ 'belongsTo' => [ [ @@ -489,7 +505,9 @@ public function testGetAssociationsIgnoreUnderscoreIdIfNoDbTable(): void $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($items, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($items); $expected = [ 'belongsTo' => [ [ @@ -538,7 +556,9 @@ public function testGetAssociationsAddAssociationIfTableExist(): void $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($items, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($items); $expected = [ 'belongsTo' => [ [ @@ -591,7 +611,9 @@ public function testGetAssociationsAddAssociationIfNoTableExistButAliasIsAllowed $args = new Arguments([], ['skip-relation-check' => true], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($items, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($items); $expected = [ 'belongsTo' => [ [ @@ -646,7 +668,9 @@ public function testGetAssociationsIgnoreUnderscoreId(): void $command = new ModelCommand(); $command->connection = 'test'; - $result = $command->getAssociations($model, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($model); $expected = [ 'hasOne' => [], 'hasMany' => [], @@ -669,7 +693,9 @@ public function testGetAssociationsConstraints(): void $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getAssociations($model, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getAssociations($model); $expected = [ [ @@ -699,6 +725,7 @@ public function testBelongsToGeneration(): void $command = new ModelCommand(); $command->connection = 'test'; + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -712,6 +739,7 @@ public function testBelongsToGeneration(): void $this->assertEquals($expected, $result); $model = $this->getTableLocator()->get('CategoryThreads'); + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -725,6 +753,7 @@ public function testBelongsToGeneration(): void $this->assertEquals($expected, $result); $command->plugin = 'Blog'; + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -748,6 +777,7 @@ public function testBelongsToGenerationConstraints(): void $model = $this->getTableLocator()->get('Relations'); $command = new ModelCommand(); $command->connection = 'test'; + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -777,6 +807,7 @@ public function testBelongsToGenerationConstraintsAliased(): void $model = $this->getTableLocator()->get('Invitations'); $command = new ModelCommand(); $command->connection = 'test'; + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -808,6 +839,7 @@ public function testBelongsToGenerationCompositeKey(): void $model = $this->getTableLocator()->get('TodoItemsTodoLabels'); $command = new ModelCommand(); $command->connection = 'test'; + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $expected = [ 'belongsTo' => [ @@ -839,6 +871,7 @@ public function testBelongsToGenerationIdMidColumn(): void 'thing_id_field' => ['type' => 'integer'], ]); $command = new ModelCommand(); + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $this->assertEquals([], $result); } @@ -859,6 +892,7 @@ public function testBelongsToGenerationPrimaryKey(): void ], ]); $command = new ModelCommand(); + $command->setArgs(new Arguments([], [], [])); $result = $command->findBelongsTo($model, []); $this->assertEquals([], $result); } @@ -1077,7 +1111,8 @@ public function testGetFields(): void $model = $this->getTableLocator()->get('TodoItems'); $command = new ModelCommand(); - $result = $command->getFields($model, new Arguments([], [], [])); + $command->setArgs(new Arguments([], [], [])); + $result = $command->getFields($model); $expected = [ 'user_id', 'title', @@ -1101,7 +1136,8 @@ public function testGetFieldsDisabled(): void $model = $this->getTableLocator()->get('TodoItems'); $args = new Arguments([], ['no-fields' => true], []); $command = new ModelCommand(); - $result = $command->getFields($model, $args); + $command->setArgs($args); + $result = $command->getFields($model); $this->assertFalse($result); } @@ -1116,7 +1152,8 @@ public function testGetFieldsWhiteList(): void $args = new Arguments([], ['fields' => 'id, title , , body , created'], []); $command = new ModelCommand(); - $result = $command->getFields($model, $args); + $command->setArgs($args); + $result = $command->getFields($model); $expected = [ 'id', 'title', @@ -1137,7 +1174,8 @@ public function testGetHiddenFields(): void $args = new Arguments([], [], []); $command = new ModelCommand(); - $result = $command->getHiddenFields($model, $args); + $command->setArgs($args); + $result = $command->getHiddenFields($model); $expected = [ 'password', ]; @@ -1155,7 +1193,8 @@ public function testGetHiddenFieldsDisabled(): void $args = new Arguments([], ['no-hidden' => true], []); $command = new ModelCommand(); - $result = $command->getHiddenFields($model, $args); + $command->setArgs($args); + $result = $command->getHiddenFields($model); $this->assertEquals([], $result); } @@ -1170,7 +1209,8 @@ public function testGetHiddenFieldsWhiteList(): void $args = new Arguments([], ['hidden' => 'id, title , , body , created'], []); $command = new ModelCommand(); - $result = $command->getHiddenFields($model, $args); + $command->setArgs($args); + $result = $command->getHiddenFields($model); $expected = [ 'id', 'title', @@ -1191,12 +1231,14 @@ public function testGetPrimaryKey(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getPrimaryKey($model, $args); + $command->setArgs($args); + $result = $command->getPrimaryKey($model); $expected = ['id']; $this->assertEquals($expected, $result); $args = new Arguments([], ['primary-key' => 'id, , account_id'], []); - $result = $command->getPrimaryKey($model, $args); + $command->setArgs($args); + $result = $command->getPrimaryKey($model); $expected = ['id', 'account_id']; $this->assertEquals($expected, $result); } @@ -1211,7 +1253,8 @@ public function testGetValidationDisabled(): void $model = $this->getTableLocator()->get('TodoItems'); $command = new ModelCommand(); $args = new Arguments([], ['no-validation' => true], []); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $this->assertEquals([], $result); } @@ -1230,7 +1273,8 @@ public function testGetValidation(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $expected = [ 'user_id' => [ 'integer' => ['rule' => 'integer', 'args' => []], @@ -1277,7 +1321,8 @@ public function testGetValidationSigned(): void $model = $this->getTableLocator()->get('TodoTasks'); $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $expected = [ 'todo_item_id' => [ 'integer' => ['rule' => 'integer', 'args' => []], @@ -1324,7 +1369,8 @@ public function testGetValidationUniqueDateField(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $this->assertArrayHasKey('release_date', $result); $expected = [ 'dateTime' => ['rule' => 'dateTime', 'args' => []], @@ -1348,7 +1394,8 @@ public function testGetValidationTree(): void $model = $this->getTableLocator()->get('NumberTrees'); $args = new Arguments([], [], []); $command = new ModelCommand(); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $expected = [ 'name' => [ 'scalar' => ['rule' => 'scalar', 'args' => []], @@ -1382,7 +1429,8 @@ public function testGetValidationTreeSigned(): void $model = $this->getTableLocator()->get('NumberTrees'); $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, [], $args); + $command->setArgs($args); + $result = $command->getValidation($model, []); $expected = [ 'name' => [ 'scalar' => ['rule' => 'scalar', 'args' => []], @@ -1421,7 +1469,8 @@ public function testGetValidationExcludeForeignKeysSigned(): void ]; $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, $associations, $args); + $command->setArgs($args); + $result = $command->getValidation($model, $associations); $expected = [ 'title' => [ 'scalar' => ['rule' => 'scalar', 'args' => []], @@ -1478,7 +1527,8 @@ public function testGetValidationOfPossibleFileFields(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getValidation($model, $associations, $args); + $command->setArgs($args); + $result = $command->getValidation($model, $associations); $expected = [ // matches @@ -1548,7 +1598,8 @@ public function testGetRulesDisabled(): void $model = $this->getTableLocator()->get('Users'); $command = new ModelCommand(); $args = new Arguments([], ['no-rules' => true], []); - $result = $command->getRules($model, [], $args); + $command->setArgs($args); + $result = $command->getRules($model, []); $this->assertEquals([], $result); } @@ -1580,7 +1631,8 @@ public function testGetRules(): void ]; $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getRules($model, $associations, $args); + $command->setArgs($args); + $result = $command->getRules($model, $associations); $expected = [ [ 'name' => 'isUnique', @@ -1622,7 +1674,8 @@ public function testGetRulesUniqueKeys(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getRules($model, [], $args); + $command->setArgs($args); + $result = $command->getRules($model, []); $expected = [ [ 'name' => 'isUnique', @@ -1669,7 +1722,8 @@ public function testGetRulesNoColumnNameConflictForUniqueConstraints(): void ], ]; - $result = $command->getRules($model, $associations, $args); + $command->setArgs($args); + $result = $command->getRules($model, $associations); $expected = [ [ 'name' => 'isUnique', @@ -1709,7 +1763,8 @@ public function testGetRulesForPossiblyUniqueColumns(): void $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getRules($model, [], $args); + $command->setArgs($args); + $result = $command->getRules($model, []); $expected = [ [ 'name' => 'isUnique', @@ -1738,7 +1793,8 @@ public function testGetRulesForPossiblyUniqueColumns(): void 'columns' => ['department_id', 'username'], ]); - $result = $command->getRules($model, [], $args); + $command->setArgs($args); + $result = $command->getRules($model, []); $expected = [ [ 'name' => 'isUnique', @@ -1789,11 +1845,13 @@ public function testGetDisplayField(): void $model = $this->getTableLocator()->get('TodoItems'); $command = new ModelCommand(); $args = new Arguments([], [], []); - $result = $command->getDisplayField($model, $args); + $command->setArgs($args); + $result = $command->getDisplayField($model); $this->assertSame('title', $result); $args = new Arguments([], ['display-field' => 'custom'], []); - $result = $command->getDisplayField($model, $args); + $command->setArgs($args); + $result = $command->getDisplayField($model); $this->assertSame('custom', $result); } @@ -1965,9 +2023,12 @@ public function testBakeTableValidation(): void $args = new Arguments([$name], ['table' => 'bake_articles', 'force' => true], []); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $table = $command->getTable($name, $args); + $command->setArgs($args); + $table = $command->getTable($name); $tableObject = $command->getTableObject($name, $table); - $data = $command->getTableContext($tableObject, $table, $name, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $data = $command->getTableContext($tableObject, $table, $name); $data['validation'] = $validation; $data['associations'] = [ 'belongsTo' => [], @@ -1975,7 +2036,7 @@ public function testBakeTableValidation(): void 'belongsToMany' => [], ]; $data['rulesChecker'] = []; - $command->bakeTable($tableObject, $data, $args, $io); + $command->bakeTable($tableObject, $data); $result = file_get_contents($this->generatedFiles[0]); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); @@ -1997,14 +2058,17 @@ public function testBakeTableRules(): void $args = new Arguments([$name], ['table' => 'unique_fields', 'force' => true], []); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $table = $command->getTable($name, $args); + $command->setArgs($args); + $table = $command->getTable($name); $tableObject = $command->getTableObject($name, $table); - $data = $command->getTableContext($tableObject, $table, $name, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $data = $command->getTableContext($tableObject, $table, $name); $data['validation'] = []; - $command->bakeTable($tableObject, $data, $args, $io); + $command->bakeTable($tableObject, $data); $result = file_get_contents($this->generatedFiles[0]); - $expected = file_get_contents($this->_compareBasePath . __FUNCTION__ . '.php'); + $expected = file_get_contents($this->compareBasePath . __FUNCTION__ . '.php'); if (ConnectionManager::get('test')->getDriver() instanceof Sqlserver) { $expected = preg_replace("/'allowMultipleNulls' => true/", "'allowMultipleNulls' => false", $expected); } @@ -2054,7 +2118,7 @@ public function testBakeEntitySimple(): void public function testBakeEntitySimpleUnchanged(): void { $this->generatedFile = APP . 'Model/Entity/User.php'; - $result = file_get_contents($this->_compareBasePath . __FUNCTION__ . '.php'); + $result = file_get_contents($this->compareBasePath . __FUNCTION__ . '.php'); file_put_contents($this->generatedFile, str_replace("\r\n", "\n", $result)); $this->exec('bake model --no-test --no-fixture --no-table --no-fields --no-hidden users'); @@ -2205,7 +2269,7 @@ public function testBakeEntityCustomHidden(): void */ public function testBakeTableWithPlugin(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $path = Plugin::path('BakeTest'); $this->generatedFile = $path . 'src/Model/Table/UsersTable.php'; @@ -2289,7 +2353,7 @@ public function testBakeTableWithCounterCache(): void */ public function testBakeEntityWithPlugin(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $path = Plugin::path('BakeTest'); $this->generatedFile = $path . 'src/Model/Entity/User.php'; @@ -2435,7 +2499,7 @@ class TodoItem implements IdentityInterface */ protected const MY_CONST = 1; - protected array $_accessible = [ + protected array $patchable = [ // should not get overwritten ]; @@ -2635,9 +2699,12 @@ public function testBakeTableNullableForeignKey(): void $args = new Arguments([$name], ['table' => 'bake_articles', 'force' => true], []); $io = new ConsoleIo(new StubConsoleOutput(), new StubConsoleOutput(), new StubConsoleInput([])); - $table = $command->getTable($name, $args); + $command->setArgs($args); + $table = $command->getTable($name); $tableObject = $command->getTableObject($name, $table); - $data = $command->getTableContext($tableObject, $table, $name, $args, $io); + $command->setArgs($args); + $command->setIo($io); + $data = $command->getTableContext($tableObject, $table, $name); $data['validation'] = $validation; $data['associations'] = [ 'belongsTo' => [], @@ -2645,7 +2712,7 @@ public function testBakeTableNullableForeignKey(): void 'belongsToMany' => [], ]; $data['rulesChecker'] = []; - $command->bakeTable($tableObject, $data, $args, $io); + $command->bakeTable($tableObject, $data); $result = file_get_contents($this->generatedFiles[0]); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); diff --git a/tests/TestCase/Command/PluginCommandTest.php b/tests/TestCase/Command/PluginCommandTest.php index a681f35c0..8b739587c 100644 --- a/tests/TestCase/Command/PluginCommandTest.php +++ b/tests/TestCase/Command/PluginCommandTest.php @@ -46,21 +46,18 @@ class PluginCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Plugin' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Plugin' . DS; $this->setAppNamespace('Bake\Test\App'); // Output into a safe place. Configure::write('App.paths.plugins', [$this->pluginsPath]); - // Create the test output path - if (!file_exists($this->pluginsPath)) { - mkdir($this->pluginsPath, 0777, true); - } - - // Create the test output path - if (!file_exists($this->pluginsStandalonePath)) { - mkdir($this->pluginsStandalonePath, 0777, true); - } + // Always start from a clean output path. + $fs = new Filesystem(); + $fs->deleteDir($this->pluginsPath); + $fs->deleteDir($this->pluginsStandalonePath); + mkdir($this->pluginsPath, 0777, true); + mkdir($this->pluginsStandalonePath, 0777, true); if (file_exists(APP . 'Application.php.bak')) { rename(APP . 'Application.php.bak', APP . 'Application.php'); @@ -173,11 +170,11 @@ public function testMainUpdateComposer(): void DIRECTORY_SEPARATOR === '\\', 'Skipping composer test on windows as `which` does not work well.', ); - $composerPath = exec('which composer'); + $composerPath = (string)exec('which composer'); if (!$composerPath && file_exists('./composer.phar')) { $composerPath = './composer.phar'; } - $this->skipIf(!file_exists($composerPath), 'Cannot find composer.phar.'); + $this->skipIf(!$composerPath || !file_exists($composerPath), 'Cannot find composer.phar.'); $composerConfig = ROOT . 'composer.json'; copy($composerConfig, ROOT . 'composer.json.bak'); @@ -209,7 +206,8 @@ public function testFindPathNonExistent(): void $command = new PluginCommand(); $command->path = TMP . 'tests' . DS; - $result = $command->findPath($paths, $io); + $command->setIo($io); + $result = $command->findPath($paths); $this->assertNull($result, 'no return'); $this->assertSame($this->pluginsPath, $command->path); @@ -230,7 +228,8 @@ public function testFindPathEmpty(): void $command = new PluginCommand(); $command->path = TMP . 'tests' . DS; - $command->findPath($paths, $io); + $command->setIo($io); + $command->findPath($paths); } public function testMainClassOnlyOption(): void @@ -257,7 +256,7 @@ public function testMainClassOnlyOption(): void public function assertPluginContents($pluginName, bool $vendor = false): void { $pluginName = str_replace('/', DS, $pluginName); - $comparisonRoot = $this->_compareBasePath . $pluginName . DS; + $comparisonRoot = $this->compareBasePath . $pluginName . DS; $comparisonFiles = $this->getFiles($comparisonRoot); if ($vendor) { diff --git a/tests/TestCase/Command/SimpleBakeCommandTest.php b/tests/TestCase/Command/SimpleBakeCommandTest.php index f3b985d84..fd8adcaa0 100644 --- a/tests/TestCase/Command/SimpleBakeCommandTest.php +++ b/tests/TestCase/Command/SimpleBakeCommandTest.php @@ -34,7 +34,7 @@ class SimpleBakeCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Plugin' . DS . 'Simple' . DS; $this->setAppNamespace('Bake\Test\App'); } @@ -94,7 +94,7 @@ public function testBakeTestNoTest(): void public function testBakeWithTheme(): void { - $this->_loadTestPlugin('TestBakeTheme'); + $this->loadTestPlugin('TestBakeTheme'); $this->generatedFile = APP . 'Model/Behavior/FooBarBehavior.php'; $this->exec('bake behavior --no-test --theme TestBakeTheme FooBar'); @@ -110,7 +110,7 @@ public function testBakeWithTheme(): void */ public function testBakePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::path('TestBake'); $this->generatedFiles = [ diff --git a/tests/TestCase/Command/TemplateAllCommandTest.php b/tests/TestCase/Command/TemplateAllCommandTest.php index 1f2d8bc5c..bdc461640 100644 --- a/tests/TestCase/Command/TemplateAllCommandTest.php +++ b/tests/TestCase/Command/TemplateAllCommandTest.php @@ -54,7 +54,7 @@ class TemplateAllCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Template' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Template' . DS; $this->setAppNamespace('Bake\Test\App'); diff --git a/tests/TestCase/Command/TemplateCommandTest.php b/tests/TestCase/Command/TemplateCommandTest.php index 4f6617d6e..7cb864e25 100644 --- a/tests/TestCase/Command/TemplateCommandTest.php +++ b/tests/TestCase/Command/TemplateCommandTest.php @@ -67,7 +67,7 @@ class TemplateCommandTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Template' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Template' . DS; $this->setAppNamespace('Bake\Test\App'); @@ -96,7 +96,8 @@ public function testController(): void { $command = new TemplateCommand(); $args = new Arguments([], [], []); - $command->controller($args, 'Comments'); + $command->setArgs($args); + $command->controller('Comments'); $this->assertSame('Comments', $command->controllerName); $this->assertSame( 'Bake\Test\App\Controller\CommentsController', @@ -114,7 +115,8 @@ public function testControllerVariations(string $name): void { $command = new TemplateCommand(); $args = new Arguments([], [], []); - $command->controller($args, $name); + $command->setArgs($args); + $command->controller($name); $this->assertSame('TemplateTaskComments', $command->controllerName); } @@ -128,7 +130,8 @@ public function testControllerPlugin(): void $command = new TemplateCommand(); $command->plugin = 'BakeTest'; $args = new Arguments([], [], []); - $command->controller($args, 'Tests'); + $command->setArgs($args); + $command->controller('Tests'); $this->assertSame('Tests', $command->controllerName); $this->assertSame( @@ -147,7 +150,8 @@ public function testControllerPrefix(): void $command = new TemplateCommand(); $args = new Arguments([], ['prefix' => 'Admin'], []); - $command->controller($args, 'Posts'); + $command->setArgs($args); + $command->controller('Posts'); $this->assertSame('Posts', $command->controllerName); $this->assertSame( 'Bake\Test\App\Controller\Admin\PostsController', @@ -155,7 +159,8 @@ public function testControllerPrefix(): void ); $command->plugin = 'BakeTest'; - $command->controller($args, 'Comments'); + $command->setArgs($args); + $command->controller('Comments'); $this->assertSame('Comments', $command->controllerName); $this->assertSame( 'BakeTest\Controller\Admin\CommentsController', @@ -173,7 +178,8 @@ public function testControllerPrefixNested(): void $command = new TemplateCommand(); $args = new Arguments([], ['prefix' => 'Admin/Management'], []); - $command->controller($args, 'Posts'); + $command->setArgs($args); + $command->controller('Posts'); $this->assertSame('Posts', $command->controllerName); $this->assertSame( 'Bake\Test\App\Controller\Admin\Management\PostsController', @@ -191,7 +197,8 @@ public function testControllerWithOverride(): void $command = new TemplateCommand(); $args = new Arguments([], [], []); - $command->controller($args, 'Comments', 'Posts'); + $command->setArgs($args); + $command->controller('Comments', 'Posts'); $this->assertSame('Posts', $command->controllerName); $this->assertSame( 'Bake\Test\App\Controller\PostsController', @@ -241,19 +248,23 @@ public function testGetTemplatePath(): void $command->controllerName = 'Posts'; $args = new Arguments([], [], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals(ROOT . 'templates/Posts/', $result); $args = new Arguments([], ['prefix' => 'admin'], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals(ROOT . 'templates/Admin/Posts/', $result); $args = new Arguments([], ['prefix' => 'admin/management'], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals(ROOT . 'templates/Admin/Management/Posts/', $result); $args = new Arguments([], ['prefix' => 'Admin/management'], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals(ROOT . 'templates/Admin/Management/Posts/', $result); } @@ -273,12 +284,14 @@ public function testGetTemplatePathPlugin(): void // Use this->plugin as plugin could be in the name arg $args = new Arguments([], [], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals($pluginPath . 'templates/Posts/', $result); // Use this->plugin as plugin could be in the name arg $args = new Arguments([], ['prefix' => 'admin'], []); - $result = $command->getTemplatePath($args); + $command->setArgs($args); + $result = $command->getTemplatePath(); $this->assertPathEquals($pluginPath . 'templates/Admin/Posts/', $result); $this->removePlugins(['TestTemplate']); @@ -311,7 +324,9 @@ public function testGetContent(): void $command = new TemplateCommand(); $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getContent($args, $io, 'view', $vars); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getContent('view', $vars); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); } @@ -356,7 +371,9 @@ public function testGetContentAssociations(): void $command = new TemplateCommand(); $args = new Arguments([], [], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getContent($args, $io, 'view', $vars); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getContent('view', $vars); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); } @@ -393,7 +410,9 @@ public function testGetContentWithNoPrimaryKey(): void $command = new TemplateCommand(); $args = new Arguments([], [], []); - $command->getContent($args, $io, 'view', $vars); + $command->setArgs($args); + $command->setIo($io); + $command->getContent('view', $vars); } /** @@ -430,10 +449,14 @@ public function testGetContentWithRoutingPrefix(): void $args = new Arguments([], ['prefix' => 'Admin'], []); $io = $this->createStub(ConsoleIo::class); - $result = $command->getContent($args, $io, 'view', $vars); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getContent('view', $vars); $this->assertSameAsFile(__FUNCTION__ . '-view.php', $result); - $result = $command->getContent($args, $io, 'add', $vars); + $command->setArgs($args); + $command->setIo($io); + $result = $command->getContent('add', $vars); $this->assertSameAsFile(__FUNCTION__ . '-add.php', $result); } @@ -644,7 +667,7 @@ public function testBakeIndexWithEnumNoLabel(): void */ public function testBakeIndexPlugin(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $path = Plugin::templatePath('BakeTest'); // Setup association to ensure properties don't have dots @@ -666,7 +689,7 @@ public function testBakeIndexPlugin(): void */ public function testBakePluginTemplatesWithDomain(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $path = Plugin::templatePath('BakeTest'); // Setup association to ensure properties don't have dots @@ -825,7 +848,7 @@ public function testMainWithExistingController(): void */ public function testMainWithPluginName(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $path = Plugin::templatePath('TestBake'); $this->generatedFile = $path . 'Comments/index.php'; diff --git a/tests/TestCase/Command/TestCommandTest.php b/tests/TestCase/Command/TestCommandTest.php index 9cfa3135c..4ef6ba696 100644 --- a/tests/TestCase/Command/TestCommandTest.php +++ b/tests/TestCase/Command/TestCommandTest.php @@ -53,7 +53,7 @@ protected function setUp(): void { parent::setUp(); $this->setAppNamespace('Bake\Test\App'); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Test' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Test' . DS; } protected function tearDown(): void @@ -120,7 +120,7 @@ public function testExecuteWithTwoArgs(): void */ public function testExecuteWithPluginName(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $this->generatedFiles = [ ROOT . 'Plugin/TestBake/tests/TestCase/Model/Table/BakeArticlesTableTest.php', @@ -311,7 +311,7 @@ public function testGetRealClassname(string $type, string $name, string $expecte */ public function testGetRealClassnamePlugin(): void { - $this->_loadTestPlugin('TestBake'); + $this->loadTestPlugin('TestBake'); $command = new TestCommand(); $command->plugin = 'TestBake'; diff --git a/tests/TestCase/PluginTest.php b/tests/TestCase/PluginTest.php index 8f970bda3..e4defe8c6 100644 --- a/tests/TestCase/PluginTest.php +++ b/tests/TestCase/PluginTest.php @@ -64,7 +64,7 @@ public function testConsoleDiscoverBakeCommands(): void public function testConsoleDiscoverPluginCommands(): void { - $this->_loadTestPlugin('BakeTest'); + $this->loadTestPlugin('BakeTest'); $commands = new CommandCollection(); $plugin = new BakePlugin(); @@ -77,7 +77,7 @@ public function testConsoleDiscoverPluginCommands(): void public function testConsoleDiscoverPluginCommandsInSubFolder(): void { - $this->_loadTestPlugin('WithBakeSubFolder'); + $this->loadTestPlugin('WithBakeSubFolder'); $commands = new CommandCollection(); $plugin = new BakePlugin(); diff --git a/tests/TestCase/TestCase.php b/tests/TestCase/TestCase.php index 376509612..d680bab57 100644 --- a/tests/TestCase/TestCase.php +++ b/tests/TestCase/TestCase.php @@ -70,7 +70,7 @@ protected function tearDown(): void * @param bool $loadBake Whether or not to load the Bake plugin as well. * @return void */ - protected function _loadTestPlugin(string $name, bool $loadBake = false): void + protected function loadTestPlugin(string $name, bool $loadBake = false): void { $root = dirname(__FILE__, 2) . DS; $path = $root . 'test_app' . DS . 'Plugin' . DS . $name . DS; diff --git a/tests/TestCase/Utility/TemplateRendererTest.php b/tests/TestCase/Utility/TemplateRendererTest.php index a44e092ca..8bab05727 100644 --- a/tests/TestCase/Utility/TemplateRendererTest.php +++ b/tests/TestCase/Utility/TemplateRendererTest.php @@ -38,7 +38,7 @@ class TemplateRendererTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'TemplateRenderer' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'TemplateRenderer' . DS; $this->renderer = new TemplateRenderer(); } @@ -72,7 +72,7 @@ public function testGenerate(): void */ public function testGenerateWithTemplateOverride(): void { - $this->_loadTestPlugin('TestBakeTheme', true); + $this->loadTestPlugin('TestBakeTheme', true); $renderer = new TemplateRenderer('TestBakeTheme'); $renderer->set([ 'plugin' => 'Special', @@ -89,7 +89,7 @@ public function testGenerateWithTemplateOverride(): void */ public function testGenerateWithTemplateFallbacks(): void { - $this->_loadTestPlugin('TestBakeTheme', true); + $this->loadTestPlugin('TestBakeTheme', true); $renderer = new TemplateRenderer('TestBakeTheme'); $renderer->set([ 'name' => 'Articles', diff --git a/tests/TestCase/View/BakeViewTest.php b/tests/TestCase/View/BakeViewTest.php index ece9d31d1..45db8e184 100644 --- a/tests/TestCase/View/BakeViewTest.php +++ b/tests/TestCase/View/BakeViewTest.php @@ -44,7 +44,7 @@ class BakeViewTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'BakeView' . DS; + $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'BakeView' . DS; $request = new Request(); $response = new Response(); diff --git a/tests/TestCase/View/Helper/BakeHelperTest.php b/tests/TestCase/View/Helper/BakeHelperTest.php index 4e1bbfd96..dbf0914a8 100644 --- a/tests/TestCase/View/Helper/BakeHelperTest.php +++ b/tests/TestCase/View/Helper/BakeHelperTest.php @@ -93,10 +93,10 @@ public function testAliasExtractorFilteredHasMany(): void ]); $this->BakeHelper = $this->getMockBuilder('Bake\View\Helper\BakeHelper') ->disableOriginalConstructor() - ->onlyMethods(['_filterHasManyAssociationsAliases']) + ->onlyMethods(['filterHasManyAssociationsAliases']) ->getMock(); $this->BakeHelper->expects($this->once()) - ->method('_filterHasManyAssociationsAliases') + ->method('filterHasManyAssociationsAliases') ->with($table, ['ArticlesTags']); $result = $this->BakeHelper->aliasExtractor($table, 'HasMany'); $this->assertEmpty($result); diff --git a/tests/TestCase/View/Helper/DocBlockHelperTest.php b/tests/TestCase/View/Helper/DocBlockHelperTest.php index 1fc832bf7..51c01e870 100644 --- a/tests/TestCase/View/Helper/DocBlockHelperTest.php +++ b/tests/TestCase/View/Helper/DocBlockHelperTest.php @@ -25,6 +25,7 @@ use Cake\ORM\Association\BelongsToMany; use Cake\ORM\Association\HasMany; use Cake\ORM\Association\HasOne; +use Cake\ORM\Table; use Cake\TestSuite\TestCase; use PHPUnit\Framework\Attributes\CoversClass; @@ -96,30 +97,32 @@ public function testClassDescription(): void */ public function testAssociatedEntityTypeToHintType(): void { + $sourceTable = new Table(['alias' => 'Source']); + // Test with MANY_TO_MANY $type = 'Foo'; - $association = new BelongsToMany('Foo'); + $association = new BelongsToMany('Foo', $sourceTable); $assocEntityType = $this->DocBlockHelper->associatedEntityTypeToHintType($type, $association); $expected = 'Foo[]'; $this->assertSame($expected, $assocEntityType); // Test with ONE_TO_MANY $type = 'Bar'; - $association = new HasMany('Bar'); + $association = new HasMany('Bar', $sourceTable); $assocEntityType = $this->DocBlockHelper->associatedEntityTypeToHintType($type, $association); $expected = 'Bar[]'; $this->assertSame($expected, $assocEntityType); // Test with ONE_TO_ONE $type = 'Ping'; - $association = new HasOne('Ping'); + $association = new HasOne('Ping', $sourceTable); $assocEntityType = $this->DocBlockHelper->associatedEntityTypeToHintType($type, $association); $expected = 'Ping'; $this->assertSame($expected, $assocEntityType); // Test with MANY_TO_ONE $type = 'Pong'; - $association = new BelongsTo('Pong'); + $association = new BelongsTo('Pong', $sourceTable); $assocEntityType = $this->DocBlockHelper->associatedEntityTypeToHintType($type, $association); $expected = 'Pong'; $this->assertSame($expected, $assocEntityType); diff --git a/tests/comparisons/Cell/testBakePlugin.php b/tests/comparisons/Cell/testBakePlugin.php index 07b743bee..be3502961 100644 --- a/tests/comparisons/Cell/testBakePlugin.php +++ b/tests/comparisons/Cell/testBakePlugin.php @@ -16,7 +16,7 @@ class ExampleCell extends Cell * * @var array */ - protected array $_validCellOptions = []; + protected array $validCellOptions = []; /** * Initialization logic run at the end of object construction. diff --git a/tests/comparisons/Command/testBakePlugin.php b/tests/comparisons/Command/testBakePlugin.php index 9e8b4adda..e5cbf9102 100644 --- a/tests/comparisons/Command/testBakePlugin.php +++ b/tests/comparisons/Command/testBakePlugin.php @@ -4,8 +4,6 @@ namespace TestBake\Command; use Cake\Command\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; /** @@ -56,11 +54,9 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar /** * Implement this method with your command's logic. * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io * @return int|null|void The exit code or null for success */ - public function execute(Arguments $args, ConsoleIo $io) + public function execute() { } } diff --git a/tests/comparisons/Model/testBakeEntityCustomHidden.php b/tests/comparisons/Model/testBakeEntityCustomHidden.php index cce168ac3..5620c2afb 100644 --- a/tests/comparisons/Model/testBakeEntityCustomHidden.php +++ b/tests/comparisons/Model/testBakeEntityCustomHidden.php @@ -25,7 +25,7 @@ class User extends Entity * * @var array */ - protected array $_hidden = [ + protected array $hidden = [ 'foo', 'bar', ]; diff --git a/tests/comparisons/Model/testBakeEntityFieldsDefaults.php b/tests/comparisons/Model/testBakeEntityFieldsDefaults.php index 9e1fb300d..ce7e18fa3 100644 --- a/tests/comparisons/Model/testBakeEntityFieldsDefaults.php +++ b/tests/comparisons/Model/testBakeEntityFieldsDefaults.php @@ -34,7 +34,7 @@ class TodoItem extends Entity * * @var array */ - protected array $_accessible = [ + protected array $patchable = [ 'user_id' => true, 'title' => true, 'body' => true, diff --git a/tests/comparisons/Model/testBakeEntityFieldsWhiteList.php b/tests/comparisons/Model/testBakeEntityFieldsWhiteList.php index 03ba67d3e..7bdd1875d 100644 --- a/tests/comparisons/Model/testBakeEntityFieldsWhiteList.php +++ b/tests/comparisons/Model/testBakeEntityFieldsWhiteList.php @@ -34,7 +34,7 @@ class TodoItem extends Entity * * @var array */ - protected array $_accessible = [ + protected array $patchable = [ 'id' => true, 'title' => true, 'body' => true, diff --git a/tests/comparisons/Model/testBakeEntityFullContext.php b/tests/comparisons/Model/testBakeEntityFullContext.php index 1229c8bfb..7409ed469 100644 --- a/tests/comparisons/Model/testBakeEntityFullContext.php +++ b/tests/comparisons/Model/testBakeEntityFullContext.php @@ -29,7 +29,7 @@ class User extends Entity * * @var array */ - protected array $_accessible = [ + protected array $patchable = [ 'username' => true, 'password' => true, 'created' => true, @@ -44,7 +44,7 @@ class User extends Entity * * @var array */ - protected array $_hidden = [ + protected array $hidden = [ 'password', ]; } diff --git a/tests/comparisons/Model/testBakeEntityHidden.php b/tests/comparisons/Model/testBakeEntityHidden.php index 602b70721..1bc24a41b 100644 --- a/tests/comparisons/Model/testBakeEntityHidden.php +++ b/tests/comparisons/Model/testBakeEntityHidden.php @@ -25,7 +25,7 @@ class User extends Entity * * @var array */ - protected array $_hidden = [ + protected array $hidden = [ 'password', ]; } diff --git a/tests/comparisons/Model/testBakeEntityWithPlugin.php b/tests/comparisons/Model/testBakeEntityWithPlugin.php index d7139c3c3..298399f7f 100644 --- a/tests/comparisons/Model/testBakeEntityWithPlugin.php +++ b/tests/comparisons/Model/testBakeEntityWithPlugin.php @@ -29,7 +29,7 @@ class User extends Entity * * @var array */ - protected array $_accessible = [ + protected array $patchable = [ 'username' => true, 'password' => true, 'created' => true, @@ -44,7 +44,7 @@ class User extends Entity * * @var array */ - protected array $_hidden = [ + protected array $hidden = [ 'password', ]; } diff --git a/tests/comparisons/Model/testBakeUpdateEntity.php b/tests/comparisons/Model/testBakeUpdateEntity.php index f9d673f98..940bac049 100644 --- a/tests/comparisons/Model/testBakeUpdateEntity.php +++ b/tests/comparisons/Model/testBakeUpdateEntity.php @@ -37,11 +37,11 @@ class TodoItem extends Entity implements IdentityInterface * * @var array */ - protected array $_hidden = [ + protected array $hidden = [ 'user_id', ]; - protected array $_accessible = [ + protected array $patchable = [ // should not get overwritten ]; diff --git a/tests/test_app/App/Command/AppPolicyCommand.php b/tests/test_app/App/Command/AppPolicyCommand.php index d4e34f160..7521c6bbf 100644 --- a/tests/test_app/App/Command/AppPolicyCommand.php +++ b/tests/test_app/App/Command/AppPolicyCommand.php @@ -29,10 +29,9 @@ class AppPolicyCommand extends BakeCommand { - public function execute(Arguments $args, ConsoleIo $io) + public function execute() { - $io->out('App Policy Generated'); - + $this->io->out('App Policy Generated'); return static::CODE_SUCCESS; } } diff --git a/tests/test_app/App/Controller/ArticlesController.php b/tests/test_app/App/Controller/ArticlesController.php index 88a54a1dc..fe81dc22f 100644 --- a/tests/test_app/App/Controller/ArticlesController.php +++ b/tests/test_app/App/Controller/ArticlesController.php @@ -95,7 +95,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $article = $this->Articles->get($id); diff --git a/tests/test_app/App/Controller/ArticlesTagsController.php b/tests/test_app/App/Controller/ArticlesTagsController.php index 627df9b3e..58b897def 100644 --- a/tests/test_app/App/Controller/ArticlesTagsController.php +++ b/tests/test_app/App/Controller/ArticlesTagsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $articlesTag = $this->ArticlesTags->get($id); diff --git a/tests/test_app/App/Controller/BakeArticlesBakeTagsController.php b/tests/test_app/App/Controller/BakeArticlesBakeTagsController.php index 101515469..72581f378 100644 --- a/tests/test_app/App/Controller/BakeArticlesBakeTagsController.php +++ b/tests/test_app/App/Controller/BakeArticlesBakeTagsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $bakeArticlesBakeTag = $this->BakeArticlesBakeTags->get($id); diff --git a/tests/test_app/App/Controller/BakeAuthorsController.php b/tests/test_app/App/Controller/BakeAuthorsController.php index ee6f7c3f2..162adf19f 100644 --- a/tests/test_app/App/Controller/BakeAuthorsController.php +++ b/tests/test_app/App/Controller/BakeAuthorsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $bakeAuthor = $this->BakeAuthors->get($id); diff --git a/tests/test_app/App/Controller/BakeTagsController.php b/tests/test_app/App/Controller/BakeTagsController.php index 7f83da53e..0c17afb34 100644 --- a/tests/test_app/App/Controller/BakeTagsController.php +++ b/tests/test_app/App/Controller/BakeTagsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $bakeTag = $this->BakeTags->get($id); diff --git a/tests/test_app/App/Controller/BakeUsersController.php b/tests/test_app/App/Controller/BakeUsersController.php index bef3e0dd7..17f1b9eae 100644 --- a/tests/test_app/App/Controller/BakeUsersController.php +++ b/tests/test_app/App/Controller/BakeUsersController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $bakeUser = $this->BakeUsers->get($id); diff --git a/tests/test_app/App/Controller/BinaryTestsController.php b/tests/test_app/App/Controller/BinaryTestsController.php index ff608c135..2f7151187 100644 --- a/tests/test_app/App/Controller/BinaryTestsController.php +++ b/tests/test_app/App/Controller/BinaryTestsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $binaryTest = $this->BinaryTests->get($id); diff --git a/tests/test_app/App/Controller/CarController.php b/tests/test_app/App/Controller/CarController.php index dfc719d7e..3f9ab590b 100644 --- a/tests/test_app/App/Controller/CarController.php +++ b/tests/test_app/App/Controller/CarController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $car = $this->Car->get($id); diff --git a/tests/test_app/App/Controller/CarsController.php b/tests/test_app/App/Controller/CarsController.php index 095e251a1..119b72f6e 100644 --- a/tests/test_app/App/Controller/CarsController.php +++ b/tests/test_app/App/Controller/CarsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $car = $this->Cars->get($id); diff --git a/tests/test_app/App/Controller/CategoriesController.php b/tests/test_app/App/Controller/CategoriesController.php index d875f42d5..88724c706 100644 --- a/tests/test_app/App/Controller/CategoriesController.php +++ b/tests/test_app/App/Controller/CategoriesController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $category = $this->Categories->get($id); diff --git a/tests/test_app/App/Controller/CategoriesProductsController.php b/tests/test_app/App/Controller/CategoriesProductsController.php index 75a208dfb..de6a02360 100644 --- a/tests/test_app/App/Controller/CategoriesProductsController.php +++ b/tests/test_app/App/Controller/CategoriesProductsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $categoriesProduct = $this->CategoriesProducts->get($id); diff --git a/tests/test_app/App/Controller/CategoryThreadsController.php b/tests/test_app/App/Controller/CategoryThreadsController.php index e1c136360..59ddce9fe 100644 --- a/tests/test_app/App/Controller/CategoryThreadsController.php +++ b/tests/test_app/App/Controller/CategoryThreadsController.php @@ -93,7 +93,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $categoryThread = $this->CategoryThreads->get($id); diff --git a/tests/test_app/App/Controller/DatatypesController.php b/tests/test_app/App/Controller/DatatypesController.php index cfcf77cd3..ee4c6a940 100644 --- a/tests/test_app/App/Controller/DatatypesController.php +++ b/tests/test_app/App/Controller/DatatypesController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $datatype = $this->Datatypes->get($id); diff --git a/tests/test_app/App/Controller/HiddenFieldsController.php b/tests/test_app/App/Controller/HiddenFieldsController.php index 4361ca920..b051371da 100644 --- a/tests/test_app/App/Controller/HiddenFieldsController.php +++ b/tests/test_app/App/Controller/HiddenFieldsController.php @@ -90,7 +90,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $hiddenField = $this->HiddenFields->get($id); diff --git a/tests/test_app/App/Controller/InvitationsController.php b/tests/test_app/App/Controller/InvitationsController.php index e9db62dd3..f833483f5 100644 --- a/tests/test_app/App/Controller/InvitationsController.php +++ b/tests/test_app/App/Controller/InvitationsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $invitation = $this->Invitations->get($id); diff --git a/tests/test_app/App/Controller/NumberTreesController.php b/tests/test_app/App/Controller/NumberTreesController.php index 2eaa2f14c..86905ed53 100644 --- a/tests/test_app/App/Controller/NumberTreesController.php +++ b/tests/test_app/App/Controller/NumberTreesController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $numberTree = $this->NumberTrees->get($id); diff --git a/tests/test_app/App/Controller/OldProductsController.php b/tests/test_app/App/Controller/OldProductsController.php index 6f53633f0..78c3e311c 100644 --- a/tests/test_app/App/Controller/OldProductsController.php +++ b/tests/test_app/App/Controller/OldProductsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $oldProduct = $this->OldProducts->get($id); diff --git a/tests/test_app/App/Controller/ProfilesController.php b/tests/test_app/App/Controller/ProfilesController.php index 5ab5ed32c..d69112635 100644 --- a/tests/test_app/App/Controller/ProfilesController.php +++ b/tests/test_app/App/Controller/ProfilesController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $profile = $this->Profiles->get($id); diff --git a/tests/test_app/App/Controller/RelationsController.php b/tests/test_app/App/Controller/RelationsController.php index 14140deb3..0bb4e4621 100644 --- a/tests/test_app/App/Controller/RelationsController.php +++ b/tests/test_app/App/Controller/RelationsController.php @@ -84,7 +84,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $relation = $this->Relations->get($id); diff --git a/tests/test_app/App/Controller/RolesController.php b/tests/test_app/App/Controller/RolesController.php index bbf764a95..f1ad90f69 100644 --- a/tests/test_app/App/Controller/RolesController.php +++ b/tests/test_app/App/Controller/RolesController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $role = $this->Roles->get($id); diff --git a/tests/test_app/App/Controller/SelfReferencingUniqueKeysController.php b/tests/test_app/App/Controller/SelfReferencingUniqueKeysController.php index 303d23342..ab11c3fec 100644 --- a/tests/test_app/App/Controller/SelfReferencingUniqueKeysController.php +++ b/tests/test_app/App/Controller/SelfReferencingUniqueKeysController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $selfReferencingUniqueKey = $this->SelfReferencingUniqueKeys->get($id); diff --git a/tests/test_app/App/Controller/TagsController.php b/tests/test_app/App/Controller/TagsController.php index 73ff9b96e..b257f4a89 100644 --- a/tests/test_app/App/Controller/TagsController.php +++ b/tests/test_app/App/Controller/TagsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $tag = $this->Tags->get($id); diff --git a/tests/test_app/App/Controller/TodoItemsController.php b/tests/test_app/App/Controller/TodoItemsController.php index 29fd5f6af..1f2c1cc80 100644 --- a/tests/test_app/App/Controller/TodoItemsController.php +++ b/tests/test_app/App/Controller/TodoItemsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $todoItem = $this->TodoItems->get($id); diff --git a/tests/test_app/App/Controller/TodoItemsTodoLabelsController.php b/tests/test_app/App/Controller/TodoItemsTodoLabelsController.php index e8abd581f..85376ca55 100644 --- a/tests/test_app/App/Controller/TodoItemsTodoLabelsController.php +++ b/tests/test_app/App/Controller/TodoItemsTodoLabelsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $todoItemsTodoLabel = $this->TodoItemsTodoLabels->get($id); diff --git a/tests/test_app/App/Controller/TodoLabelsController.php b/tests/test_app/App/Controller/TodoLabelsController.php index e3d4d2c54..c2d5277d6 100644 --- a/tests/test_app/App/Controller/TodoLabelsController.php +++ b/tests/test_app/App/Controller/TodoLabelsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $todoLabel = $this->TodoLabels->get($id); diff --git a/tests/test_app/App/Controller/TodoRemindersController.php b/tests/test_app/App/Controller/TodoRemindersController.php index fa5390282..11e5cbb7d 100644 --- a/tests/test_app/App/Controller/TodoRemindersController.php +++ b/tests/test_app/App/Controller/TodoRemindersController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $todoReminder = $this->TodoReminders->get($id); diff --git a/tests/test_app/App/Controller/TodoTasksController.php b/tests/test_app/App/Controller/TodoTasksController.php index 4f30207dc..0c76f8570 100644 --- a/tests/test_app/App/Controller/TodoTasksController.php +++ b/tests/test_app/App/Controller/TodoTasksController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $todoTask = $this->TodoTasks->get($id); diff --git a/tests/test_app/App/Controller/UniqueFieldsController.php b/tests/test_app/App/Controller/UniqueFieldsController.php index 57a05431e..f28b70142 100644 --- a/tests/test_app/App/Controller/UniqueFieldsController.php +++ b/tests/test_app/App/Controller/UniqueFieldsController.php @@ -89,7 +89,7 @@ public function edit($id = null) * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ - public function delete($id = null) + public function delete($id = null): ?\Cake\Http\Response { $this->request->allowMethod(['post', 'delete']); $uniqueField = $this->UniqueFields->get($id); diff --git a/tests/test_app/App/Model/Entity/HiddenField.php b/tests/test_app/App/Model/Entity/HiddenField.php index 1c9f0f139..a028fa9ea 100644 --- a/tests/test_app/App/Model/Entity/HiddenField.php +++ b/tests/test_app/App/Model/Entity/HiddenField.php @@ -20,5 +20,5 @@ class HiddenField extends Entity { - protected array $_hidden = ['password', 'auth_token']; + protected array $hidden = ['password', 'auth_token']; } diff --git a/tests/test_app/Plugin/BakeTest/src/Command/ZerglingCommand.php b/tests/test_app/Plugin/BakeTest/src/Command/ZerglingCommand.php index fa27bdf4f..83184c2ec 100644 --- a/tests/test_app/Plugin/BakeTest/src/Command/ZerglingCommand.php +++ b/tests/test_app/Plugin/BakeTest/src/Command/ZerglingCommand.php @@ -25,9 +25,9 @@ */ class ZerglingCommand extends BakeCommand { - public function execute(Arguments $args, ConsoleIo $io) + public function execute() { - $io->out('Zerg generated.'); - $io->verbose('Loud noises'); + $this->io->out('Zerg generated.'); + $this->io->verbose('Loud noises'); } } diff --git a/tests/test_app/Plugin/BakeTest/src/Controller/TestsController.php b/tests/test_app/Plugin/BakeTest/src/Controller/TestsController.php index 32d1a4859..bbfd33b9e 100644 --- a/tests/test_app/Plugin/BakeTest/src/Controller/TestsController.php +++ b/tests/test_app/Plugin/BakeTest/src/Controller/TestsController.php @@ -34,7 +34,7 @@ public function index() $this->set('test_value', 'It is a variable'); } - public function some_method() + public function some_method(): \Cake\Http\Response { $this->response->body(25); From b2f49c1b9f5f237f2eda44628f44f4686ed7b20e Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Sep 2026 17:57:21 +0530 Subject: [PATCH 2/6] Fix controller files generated during testing not being cleaned up --- tests/TestCase/Command/ControllerAllCommandTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/TestCase/Command/ControllerAllCommandTest.php b/tests/TestCase/Command/ControllerAllCommandTest.php index 70593d418..bca852fe7 100644 --- a/tests/TestCase/Command/ControllerAllCommandTest.php +++ b/tests/TestCase/Command/ControllerAllCommandTest.php @@ -19,9 +19,11 @@ use Bake\Command\ControllerAllCommand; use Bake\Test\App\Model\Table\BakeArticlesTable; use Bake\Test\TestCase\TestCase; +use Bake\Utility\SubsetSchemaCollection; use Cake\Console\CommandInterface; use Cake\Console\ConsoleOptionParser; use Cake\Core\Plugin; +use Cake\Datasource\ConnectionManager; use Cake\Utility\Inflector; /** @@ -55,6 +57,10 @@ protected function setUp(): void $this->compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Controller' . DS; $this->setAppNamespace('Bake\Test\App'); + $connection = ConnectionManager::get('test'); + $subsetCollection = new SubsetSchemaCollection($connection->getSchemaCollection(), $this->tables); + $connection->setSchemaCollection($subsetCollection); + $this->getTableLocator()->get('BakeArticles', [ 'className' => BakeArticlesTable::class, ]); @@ -68,6 +74,9 @@ protected function setUp(): void protected function tearDown(): void { parent::tearDown(); + $connection = ConnectionManager::get('test'); + $connection->setSchemaCollection($connection->getSchemaCollection()->getInnerCollection()); + $this->getTableLocator()->clear(); } From f195c0f4aec363dee19cd72ee195116dda32977e Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Sep 2026 18:05:34 +0530 Subject: [PATCH 3/6] Update GA workflow --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c7ee147d..f0cc1fbd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: - 2.next - 3.x - 3.next + - 4.x pull_request: branches: - '*' @@ -17,9 +18,9 @@ permissions: jobs: testsuite: - uses: cakephp/.github/.github/workflows/testsuite-with-db.yml@5.x + uses: cakephp/.github/.github/workflows/testsuite-with-db.yml@6.x secrets: inherit cs-stan: - uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x + uses: cakephp/.github/.github/workflows/cs-stan.yml@6.x secrets: inherit From 796497ca33e6810872e0a4cc2c8075f37db80a50 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Sep 2026 18:09:56 +0530 Subject: [PATCH 4/6] Update rector config --- rector.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rector.php b/rector.php index b1eb978f0..9348cc7b3 100644 --- a/rector.php +++ b/rector.php @@ -97,7 +97,7 @@ return RectorConfig::configure() ->withPaths([ __DIR__ . '/src', - __DIR__ . '/tests', + __DIR__ . '/tests/TestCase', ]) ->withCache( @@ -157,9 +157,7 @@ RemoveAlwaysTrueIfConditionRector::class, RemoveDeadInstanceOfRector::class, UnwrapFutureCompatibleIfPhpVersionRector::class, - RemoveNullArgOnNullDefaultParamRector::class => [ - __DIR__ . '/tests/TestCase/Database/Expression/QueryExpressionTest.php', - ], + RemoveNullArgOnNullDefaultParamRector::class, RemoveNonExistingVarAnnotationRector::class, RemoveUselessVarTagRector::class, PowToExpRector::class, From 510e053ddb638f480cacfc5dd4d803a47408280b Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Sep 2026 18:12:51 +0530 Subject: [PATCH 5/6] Fix MySQL error for CREATE TABLE --- tests/schema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/schema.php b/tests/schema.php index bc3c3d3cf..2ff11b6c4 100644 --- a/tests/schema.php +++ b/tests/schema.php @@ -301,7 +301,7 @@ 'columns' => [ 'id' => ['type' => 'integer'], 'byte' => ['type' => 'binary', 'length' => 1], - 'data' => ['type' => 'binary', 'length' => 300], + 'data' => ['type' => 'binary', 'length' => 255], ], 'constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]], ], From 259bce8e6db30aa44358fc97fbafd408a894b37b Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 25 Sep 2026 14:24:54 +0530 Subject: [PATCH 6/6] Update docs --- README.md | 4 +- docs/.vitepress/config.js | 11 +- docs/.vitepress/toc_es.json | 2 +- docs/en/development.md | 170 +++++--- docs/en/index.md | 2 +- docs/en/usage.md | 88 +++-- docs/es/development.md | 363 +++++++++++++++++- docs/es/index.md | 22 +- docs/es/usage.md | 186 +++++---- docs/fr/development.md | 239 +++++++----- docs/fr/index.md | 6 +- docs/fr/usage.md | 137 +++++-- docs/ja/development.md | 197 ++++++---- docs/ja/index.md | 11 +- docs/ja/usage.md | 134 +++++-- docs/pt/development.md | 303 ++++++++++----- docs/pt/index.md | 20 +- docs/pt/usage.md | 194 ++++++---- docs/ru/development.md | 313 +++++++++------ docs/ru/index.md | 23 +- docs/ru/usage.md | 209 +++++----- templates/bake/Command/command.twig | 2 +- templates/bake/Plugin/src/Plugin.php.twig | 2 +- tests/comparisons/Command/testBakePlugin.php | 2 +- .../Company/Example/src/ExamplePlugin.php | 2 +- .../SimpleExample/src/SimpleExamplePlugin.php | 2 +- 26 files changed, 1792 insertions(+), 852 deletions(-) diff --git a/README.md b/README.md index a403eae02..8f43d482e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Bake plugin for CakePHP -![Build Status](https://github.com/cakephp/bake/actions/workflows/ci.yml/badge.svg?branch=master) +![Build Status](https://github.com/cakephp/bake/actions/workflows/ci.yml/badge.svg?branch=4.x) [![Latest Stable Version](https://img.shields.io/github/v/release/cakephp/bake?sort=semver&style=flat-square)](https://packagist.org/packages/cakephp/bake) [![Coverage Status](https://img.shields.io/codecov/c/github/cakephp/bake.svg?style=flat-square)](https://codecov.io/github/cakephp/bake) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.txt) @@ -20,7 +20,7 @@ composer require --dev cakephp/bake ## Documentation -You can find the documentation for bake [on its own cookbook](https://book.cakephp.org/bake/3). +You can find the documentation for bake [on its own cookbook](https://book.cakephp.org/bake/4). ## Testing diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 5e8ac6185..48976505d 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -10,9 +10,10 @@ const tocPt = require('./toc_pt.json') const tocRu = require('./toc_ru.json') const versions = { - text: '3.x', + text: '4.x', items: [ - { text: '3.x (current)', link: 'https://book.cakephp.org/bake/3/', target: '_self' }, + { text: '4.x (current)', link: 'https://book.cakephp.org/bake/4/', target: '_self' }, + { text: '3.x', link: 'https://book.cakephp.org/bake/3/', target: '_self' }, { text: '2.x', link: 'https://book.cakephp.org/bake/2.x/', target: '_self' }, { text: '1.x', link: 'https://book.cakephp.org/bake/1.x/', target: '_self' }, ], @@ -23,12 +24,12 @@ export default { srcDir: '.', title: 'Bake', description: 'CakePHP Bake Documentation', - base: '/bake/3/', + base: '/bake/4/', rewrites: { 'en/:slug*': ':slug*', }, sitemap: { - hostname: 'https://book.cakephp.org/bake/3/', + hostname: 'https://book.cakephp.org/bake/4/', }, themeConfig: { siteTitle: false, @@ -37,7 +38,7 @@ export default { { icon: 'github', link: 'https://github.com/cakephp/bake' }, ], editLink: { - pattern: 'https://github.com/cakephp/bake/edit/3.x/docs/:path', + pattern: 'https://github.com/cakephp/bake/edit/4.x/docs/:path', text: 'Edit this page on GitHub', }, sidebar: tocEn, diff --git a/docs/.vitepress/toc_es.json b/docs/.vitepress/toc_es.json index 98b6e2cb0..09165c699 100644 --- a/docs/.vitepress/toc_es.json +++ b/docs/.vitepress/toc_es.json @@ -6,7 +6,7 @@ "items": [ { "text": "Consola Bake", "link": "/es/" }, { "text": "Crear código con Bake", "link": "/es/usage" }, - { "text": "Extending Bake", "link": "/es/development" } + { "text": "Extender Bake", "link": "/es/development" } ] } ] diff --git a/docs/en/development.md b/docs/en/development.md index bc7d608a8..c5363ec76 100644 --- a/docs/en/development.md +++ b/docs/en/development.md @@ -68,7 +68,6 @@ For instance, if you want to add specific actions to your `UsersController` when setDescription(static::getDescription()); } /** - * Implement this method with your command's logic. - * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io - * @return int|null|void The exit code or null for success - */ - public function execute(Arguments $args, ConsoleIo $io) + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } ``` +The `element()` call emits the `args` and `$this->io` instead of receiving them as `execute()` parameters. + The resultant baked class at `src/Command/FooCommand.php` looks like this: ```php @@ -158,37 +182,59 @@ declare(strict_types=1); namespace App\Command; use Cake\Command\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; /** -* Foo command. -*/ + * Foo command. + */ class FooCommand extends Command { /** - * Hook method for defining this command's option parser. - * - * @link https://book.cakephp.org/5/en/console-commands/commands.html#defining-arguments-and-options - * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined - * @return \Cake\Console\ConsoleOptionParser The built parser. - */ - public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + * The name of this command. + * + * @var string + */ + protected string $name = 'cake foo'; + + /** + * Get the default command name. + * + * @return string + */ + public static function defaultName(): string { - $parser = parent::buildOptionParser($parser); + return 'foo'; + } - return $parser; + /** + * Get the command description. + * + * @return string + */ + public static function getDescription(): string + { + return 'Command description here.'; + } + + /** + * Hook method for defining this command's option parser. + * + * @link https://book.cakephp.org/6/en/console-commands/commands.html#defining-arguments-and-options + * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined + * @return \Cake\Console\ConsoleOptionParser The built parser. + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + return parent::buildOptionParser($parser) + ->setDescription(static::getDescription()); } /** - * Implement this method with your command's logic. - * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io - * @return int|null|void The exit code or null for success - */ - public function execute(Arguments $args, ConsoleIo $io) + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } @@ -237,7 +283,7 @@ use Bake\Command\SimpleBakeCommand; class FooCommand extends SimpleBakeCommand { - public $pathFragment = 'FooPath/'; + public string $pathFragment = 'FooPath/'; public function name(): string { @@ -278,26 +324,26 @@ This generates `src/FooPath/ExampleFooOut.php`. If you also want `bake` to create a test file for your `ExampleFooOut` class, override the `bakeTest()` method in `FooCommand`: ```php -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; +use Bake\Command\TestCommand; -public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void +public function bakeTest(string $className): void { - if (!isset($this->Test->classSuffixes[$this->name()])) { - $this->Test->classSuffixes[$this->name()] = 'Foo'; - } - - $name = ucfirst($this->name()); - if (!isset($this->Test->classTypes[$name])) { - $this->Test->classTypes[$name] = 'Foo'; + if ($this->args->getOption('no-test')) { + return; } - parent::bakeTest($className, $args, $io); + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); } ``` -- The **class suffix** is appended to the name provided in your `bake` call. In the example above, that would create `ExampleFooTest.php`. -- The **class type** is the sub-namespace used to reach your file relative to the app or plugin you are baking into. In the example above, that would create the test namespace `App\Test\TestCase\Foo`. +- The **class suffix** is appended to the name provided in your `bake` call. In the example above, that would create `ExampleFooOut` and its test file `tests/TestCase/FooPath/ExampleFooOutTest.php`. +- The **class type** value is the sub-namespace used to reach your file relative to the app or plugin you are baking into. In the example above, that would create the test namespace `App\Test\TestCase\FooPath`. ## Configuring the BakeView Class diff --git a/docs/en/index.md b/docs/en/index.md index 4f8b7808b..32901a74d 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -11,7 +11,7 @@ Before trying to use or extend Bake, make sure it is installed in your applicati Bake is provided as a plugin that you can install with Composer: ```bash -composer require --dev cakephp/bake:"^3.0" +composer require --dev cakephp/bake:"^4.0" ``` The above installs Bake as a development dependency, so it will not be installed during production deployments. diff --git a/docs/en/usage.md b/docs/en/usage.md index 76b226d9f..cbb0a3e7d 100644 --- a/docs/en/usage.md +++ b/docs/en/usage.md @@ -14,39 +14,35 @@ For Windows usage use `bin\cake bake --help`: ```bash $ bin/cake bake --help -Current Paths: - -* app: src/ -* root: /path/to/your/app/ -* core: /path/to/your/app/vendor/cakephp/cakephp/ - -Available Commands: - -Bake: -- bake all -- bake behavior -- bake cell -- bake command -- bake command_helper -- bake component -- bake controller -- bake controller all -- bake enum -- bake fixture -- bake fixture all -- bake form -- bake helper -- bake mailer -- bake middleware -- bake model -- bake model all -- bake plugin -- bake template -- bake template all -- bake test +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. To run a command, type `cake command_name [args|options]` To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` ``` ## Bake Models @@ -64,7 +60,7 @@ For non-conventional relations, you can use references in constraints or foreign ## Bake Enums You can use Bake to generate [backed enums](https://www.php.net/manual/en/language.enumerations.backed.php) for use in your models. -Enums are placed in `src/Model/Enum/` and implement `EnumLabelInterface`, which provides a `label()` method for human-readable display. +Enums are placed in `src/Model/Enum/`, implement `EnumLabelInterface` and use `EnumLabelTrait`, which provides a `label()` method for human-readable display. To bake a string-backed enum: @@ -75,21 +71,24 @@ bin/cake bake enum ArticleStatus draft,published,archived This generates `src/Model/Enum/ArticleStatus.php`: ```php +name)); - } } ``` @@ -102,13 +101,24 @@ bin/cake bake enum Priority low:1,medium:2,high:3 -i This generates an int-backed enum: ```php +on('Bake.initialize', function (EventInterface $event) { + $view = $event->getSubject(); + + // In my bake templates, allow the use of the MySpecial helper + $view->loadHelper('MySpecial', ['some' => 'config']); + + // And add an $author variable so it's always available + $view->set('author', 'Andy'); +}); +``` + +Los eventos de Bake también pueden ser útiles para realizar cambios pequeños en los templates existentes. +Por ejemplo, para cambiar los nombres de variables usados al generar los archivos de controller y template, escuche el evento `Bake.beforeRender`: + +```php +on('Bake.beforeRender', function (EventInterface $event) { + $view = $event->getSubject(); + + // Use $rows for the main data variable in indexes + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // Use $theOne for the main data variable in view/edit + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } +}); +``` + +También puede limitar el alcance de los eventos `Bake.beforeRender` y `Bake.afterRender` a un archivo generado concreto. +Por ejemplo, si quiere añadir acciones concretas a su `UsersController` al generar desde un archivo `Controller/controller.twig`: + +```php +on( + 'Bake.beforeRender.Controller.controller', + function (EventInterface $event) { + $view = $event->getSubject(); + if ($view->get('name') === 'Users') { + // add the login and logout actions to the Users controller + $view->set('actions', [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete', + ]); + } + } +); +``` + +Al limitar los oyentes de eventos a templates bake concretos, puede simplificar la lógica de eventos relacionada con bake y ofrecer callbacks más fáciles de probar. + +## Sintaxis de los templates de Bake + +Los archivos de template de Bake usan la sintaxe de templates [Twig](https://twig.symfony.com/). + +Por ejemplo, al generar un comando como este: + +```bash +bin/cake bake command Foo +``` + +El template usado en `vendor/cakephp/bake/templates/bake/Command/command.twig` es este: + +```php +{{ element('Bake.file_header', { + namespace: "#{namespace}\\Command", + classImports: [ + 'Cake\\Command\\Command', + 'Cake\\Console\\ConsoleOptionParser', + ], +}) }} + +/** + * {{ name }} command. + */ +class {{ name }}Command extends Command +{ + /** + * The name of this command. + * + * @var string + */ + protected string $name = 'cake {{ command_name }}'; + + /** + * Get the default command name. + * + * @return string + */ + public static function defaultName(): string + { + return '{{ command_name }}'; + } + + /** + * Get the command description. + * + * @return string + */ + public static function getDescription(): string + { + return 'Command description here.'; + } + + /** + * Hook method for defining this command's option parser. + * + * @link https://book.cakephp.org/6/en/console-commands/commands.html#defining-arguments-and-options + * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined + * @return \Cake\Console\ConsoleOptionParser The built parser. + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + return parent::buildOptionParser($parser) + ->setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() + { + } +} +``` + +La llamada `element()` emite la cabecera `args` y `$this->io` en lugar de recibirlos como parámetros de `execute()`. + +La clase resultante generada en `src/Command/FooCommand.php` es esta: + +```php +setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() + { + } +} +``` + +## Crear un tema de Bake + +Si desea modificar la salida producida por el comando `bake`, puede crear su propio tema bake, lo que le permite reemplazar algunos o todos los templates que usa Bake. + +1. Genere un nuevo plugin. El nombre del plugin es el nombre del tema bake. Por ejemplo, `bin/cake bake plugin custom_bake`. +2. Cree un nuevo directorio en `plugins/CustomBake/templates/bake`. +3. Copie los templates que quiera sobrescribir desde `vendor/cakephp/bake/templates/bake` a los archivos coincidentes de su plugin. +4. Al ejecutar Bake, use la opción `--theme CustomBake` para usar su tema bake. Para evitar tener que especificar esta opción cada vez, también puede definir su tema personalizado como predeterminado: + +```php +args->getOption('no-test')) { + return; + } + + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); +} +``` + +- El **sufijo de clase** se añade al nombre proporcionado en su llamada a `bake`. En el ejemplo anterior, esto crearía `ExampleFooOut` y su archivo de prueba `tests/TestCase/FooPath/ExampleFooOutTest.php`. +- El valor de **class type** es el sub-namespace usado para acceder a su archivo respecto de la aplicación o plugin en el que genera. En el ejemplo anterior, esto crearía el namespace de pruebas `App\Test\TestCase\FooPath`. + +## Configurar la clase BakeView + +Los comandos Bake usan la clase `BakeView` para renderizar los templates. +Puede acceder a la instancia escuchando el evento `Bake.initialize`: + +```php +on( + 'Bake.initialize', + function ($event, $view) { + $view->loadHelper('Foo'); + } +); +``` diff --git a/docs/es/index.md b/docs/es/index.md index 6e7328672..eb4004de7 100644 --- a/docs/es/index.md +++ b/docs/es/index.md @@ -1,24 +1,24 @@ # Consola Bake -La consola Bake de CakePHP permite preparar y ejecutar CakePHP rápidamente. -Puede crear muchos de los ingredientes básicos de CakePHP, como modelos, -behaviours, vistas, helpers, controladores, componentes, casos de prueba, -fixtures y plugins. +La consola bake de CakePHP es otro esfuerzo para ayudarle a empezar a trabajar con CakePHP rápidamente. +La consola bake puede crear cualquiera de los ingredientes básicos de CakePHP: modelos, behaviors, vistas, helpers, controladores, componentes, casos de prueba, fixtures y plugins. Bake puede generar mucho más que esqueletos de clases y es un paso natural después de crear la base de la aplicación. ## Instalación -Antes de intentar utilizar o extender Bake, asegúrate de que está instalado en tu aplicación. -Bake se distribuye como un plugin que puedes instalar con Composer: +Antes de intentar utilizar o extender Bake, asegúrese de que está instalado en su aplicación. +Bake se distribuye como un plugin que puede instalar con Composer: ```bash -composer require --dev cakephp/bake:~1.0 +composer require --dev cakephp/bake:"^4.0" ``` -La instrucción anterior instalará Bake como una dependencia de desarrollo. -Esto significa que no será instalado cuando hagas despliegues en producción. +La instrucción anterior instalará Bake como una dependencia de desarrollo, por lo que no será instalado cuando haga despliegues en producción. + +Cuando utilice templates Twig, asegúrese de cargar el plugin `Cake/TwigView` con su bootstrap. +También puede omitirlo por completo, con lo que el plugin Bake lo cargará bajo demanda. ## Mapa de documentación -- [Crear código con Bake](/es/usage) cubre la ejecución del CLI, el listado de tareas y los temas de Bake. -- [Extending Bake](/es/development) enlaza al contenido disponible para ampliaciones y personalización. +- [Crear código con Bake](/es/usage) cubre la ejecución de la consola, el listado de comandos, la generación de modelos y enums, y el cambio de temas de bake. +- [Extender Bake](/es/development) cubre los eventos, los templates Twig, los temas personalizados, las sobrescrituras de templates de la aplicación y la creación de comandos bake personalizados. diff --git a/docs/es/usage.md b/docs/es/usage.md index c1862006d..b5df3e036 100644 --- a/docs/es/usage.md +++ b/docs/es/usage.md @@ -1,100 +1,134 @@ # Crear código con Bake -La consola de Cake se ejecuta usando PHP CLI. -Si tiene problemas para ejecutar el script, asegúrese de: +La consola Bake se ejecuta usando PHP CLI. +Si tiene problemas para ejecutar el script, asegúrese de que: -1. Tener instalado PHP CLI y los módulos correspondientes habilitados, por ejemplo MySQL e `intl`. -2. Si el host de la base de datos es `localhost`, intentar la conexión con `127.0.0.1`, ya que en algunos casos PHP CLI tiene problemas al usar `localhost`. -3. Dependiendo de cómo esté configurado su equipo, la ejecución de `bin/cake bake` puede requerir permisos de ejecución. +1. Tiene instalado PHP CLI y que tiene habilitados los módulos adecuados, como MySQL e `intl`. +2. Si el host de la base de datos es `localhost`, intente usar `127.0.0.1` en su lugar, ya que `localhost` puede causar problemas con PHP CLI. +3. Dependiendo de cómo esté configurado su equipo, puede que necesite asignar permisos de ejecución al script shell de Cake para llamarlo usando `bin/cake bake`. -Antes de comenzar, asegúrese de disponer al menos de una conexión a base de datos configurada. +Antes de ejecutar Bake, asegúrese de tener al menos una conexión a base de datos configurada. -Para comenzar con la ejecución del comando puede abrir la consola y ejecutar `Cake bake`. +Puede obtener la lista de comandos bake disponibles ejecutando `bin/cake bake --help`. +En Windows, use `bin\cake bake --help`: -1. Ir a Inicio > Ejecutar. -2. Escribir `cmd` y presionar Enter. -3. Navegar hasta la carpeta de instalación de Cake. -4. Acceder a la carpeta `bin`. -5. Escribir `Cake bake`, lo cual deberá devolver un listado con las tareas disponibles. +```bash +$ bin/cake bake --help +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. + +To run a command, type `cake command_name [args|options]` +To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` +``` -El resultado debería ser algo similar a lo siguiente: +## Modelos Bake -```bash -$ bin/cake bake - -Welcome to CakePHP v3.1.6 Console ---------------------------------------------------------------- -App : src -Path: /var/www/cakephp.dev/src/ -PHP: 5.5.8 ---------------------------------------------------------------- -The following commands can be used to generate skeleton code for your application. - -Available bake commands: - -- all -- behavior -- cell -- component -- controller -- fixture -- form -- helper -- mailer -- migration -- migration_snapshot -- model -- plugin -- template -- test - -By using 'cake bake [name]' you can invoke a specific bake task. +Los modelos se generan de forma genérica a partir de las tablas existentes de la base de datos. +Se aplican las convenciones de CakePHP, por lo que Bake detecta las relaciones a partir de las claves externas `thing_id` hacia las tablas `things` con sus claves primarias `id`. + +Para relaciones no convencionales, puede usar referencias en las restricciones o en las definiciones de claves externas para que Bake detecte las relaciones: + +```php +->addForeignKey('billing_country_id', 'countries') // defaults to `id` +->addForeignKey('shipping_country_id', 'countries', 'cid') ``` -Puede obtener más información sobre lo que realiza cada tarea y sus opciones usando `--help`: +## Enums Bake + +Puede usar Bake para generar [enums respaldados](https://www.php.net/manual/en/language.enumerations.backed.php) para usar en sus modelos. +Los enums se colocan en `src/Model/Enum/`, implementan `EnumLabelInterface` y usan `EnumLabelTrait`, que proporciona un método `label()` para una presentación legible. + +Para generar un enum respaldado por cadenas: ```bash -$ bin/cake bake controller --help +bin/cake bake enum ArticleStatus draft,published,archived +``` + +Esto genera `src/Model/Enum/ArticleStatus.php`: + +```php +] +use Cake\Database\Type\EnumLabelInterface; +use Cake\Database\Type\EnumLabelTrait; -Subcommands: +/** + * ArticleStatus Enum + */ +enum ArticleStatus: string implements EnumLabelInterface +{ + use EnumLabelTrait; -all Bake all controllers with CRUD methods. + case Draft = 'draft'; + case Published = 'published'; + case Archived = 'archived'; +} +``` + +Para enums respaldados por enteros, use la opción `-i` y proporcione los valores separados por dos puntos: + +```bash +bin/cake bake enum Priority low:1,medium:2,high:3 -i +``` -To see help on a subcommand use `cake bake controller [subcommand] --help` +Esto genera un enum respaldado por enteros: -Options: +```php +on('Bake.initialize', function (EventInterface $event) { $view = $event->getSubject(); - // Dans mes templates de bake, permet l'utilisation du helper MySpecial + // In my bake templates, allow the use of the MySpecial helper $view->loadHelper('MySpecial', ['some' => 'config']); - // Et ajoute une variable $author pour qu'elle soit toujours disponible + // And add an $author variable so it's always available $view->set('author', 'Andy'); }); ``` Les events de Bake peuvent aussi servir à faire de petits changements dans les templates existants. -Par exemple, pour changer les noms de variables utilisés lors de la création de fichiers de controller et de template : +Par exemple, pour changer les noms de variables utilisés lors de la génération des fichiers de controller et de template, écoutez l'event `Bake.beforeRender` : ```php on('Bake.beforeRender', function (EventInterface $event) { $view = $event->getSubject(); - // Utilise $rows pour la principale variable de données dans les index + // Use $rows for the main data variable in indexes if ($view->get('pluralName')) { $view->set('pluralName', 'rows'); } @@ -50,7 +50,7 @@ EventManager::instance()->on('Bake.beforeRender', function (EventInterface $even $view->set('pluralVar', 'rows'); } - // Utilise $theOne pour la principale variable de données dans les view/edit + // Use $theOne for the main data variable in view/edit if ($view->get('singularName')) { $view->set('singularName', 'theOne'); } @@ -61,22 +61,21 @@ EventManager::instance()->on('Bake.beforeRender', function (EventInterface $even ``` Vous pouvez aussi scoper les events `Bake.beforeRender` et `Bake.afterRender` à un fichier généré spécifique. -Par exemple, pour ajouter des actions à `UsersController` lors de la génération depuis `Controller/controller.twig` : +Par exemple, pour ajouter des actions spécifiques à votre `UsersController` lors de la génération depuis un fichier `Controller/controller.twig` : ```php on( 'Bake.beforeRender.Controller.controller', function (EventInterface $event) { $view = $event->getSubject(); if ($view->get('name') === 'Users') { - // ajouter les actions login et logout au controller Users + // add the login and logout actions to the Users controller $view->set('actions', [ 'login', 'logout', @@ -106,48 +105,73 @@ bin/cake bake command Foo Le template utilisé dans `vendor/cakephp/bake/templates/bake/Command/command.twig` ressemble à ceci : ```php -setDescription(static::getDescription()); } /** - * Implémentez cette méthode avec la logique de votre commande. - * - * @param \Cake\Console\Arguments $args Les arguments de la commande. - * @param \Cake\Console\ConsoleIo $io La console io - * @return int|null|void Le code de sortie ou null pour un succès - */ - public function execute(Arguments $args, ConsoleIo $io) + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } ``` +L'appel `element()` émet l'en-tête `args` et `$this->io` au lieu de les recevoir en paramètres d'`execute()`. + La classe résultante générée dans `src/Command/FooCommand.php` ressemble à ceci : ```php @@ -157,37 +181,59 @@ declare(strict_types=1); namespace App\Command; use Cake\Command\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; /** -* Commande Foo. -*/ + * Foo command. + */ class FooCommand extends Command { /** - * Méthode hook pour définir le parseur d'option de cette commande. - * - * @link https://book.cakephp.org/5/fr/console-commands/commands.html#defining-arguments-and-options - * @param \Cake\Console\ConsoleOptionParser $parser Le parseur à définir - * @return \Cake\Console\ConsoleOptionParser Le parseur construit. - */ - public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + * The name of this command. + * + * @var string + */ + protected string $name = 'cake foo'; + + /** + * Get the default command name. + * + * @return string + */ + public static function defaultName(): string { - $parser = parent::buildOptionParser($parser); + return 'foo'; + } - return $parser; + /** + * Get the command description. + * + * @return string + */ + public static function getDescription(): string + { + return 'Command description here.'; } /** - * Implémentez cette méthode avec la logique de votre commande. - * - * @param \Cake\Console\Arguments $args Les arguments de la commande. - * @param \Cake\Console\ConsoleIo $io La console io - * @return int|null|void Le code de sortie ou null pour un succès - */ - public function execute(Arguments $args, ConsoleIo $io) + * Hook method for defining this command's option parser. + * + * @link https://book.cakephp.org/6/en/console-commands/commands.html#defining-arguments-and-options + * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined + * @return \Cake\Console\ConsoleOptionParser The built parser. + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + return parent::buildOptionParser($parser) + ->setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } @@ -195,22 +241,23 @@ class FooCommand extends Command ## Créer un thème de Bake -Si vous souhaitez modifier la sortie produite par la commande `bake`, vous pouvez créer votre propre thème afin de remplacer tout ou partie des templates utilisés par Bake. +Si vous souhaitez modifier la sortie produite par la commande `bake`, vous pouvez créer votre propre thème de bake, ce qui vous permet de remplacer tout ou partie des templates utilisés par Bake. -1. Créez un nouveau plugin avec Bake. Le nom du plugin devient le nom du thème. Par exemple `bin/cake bake plugin bake_perso`. -2. Créez un nouveau répertoire `plugins/BakePerso/templates/bake`. +1. Créez un nouveau plugin avec Bake. Le nom du plugin devient le nom du thème de bake. Par exemple `bin/cake bake plugin custom_bake`. +2. Créez un nouveau répertoire `plugins/CustomBake/templates/bake`. 3. Copiez les templates que vous souhaitez surcharger depuis `vendor/cakephp/bake/templates/bake` vers les fichiers correspondants dans votre plugin. -4. Lors de l'exécution de Bake, utilisez l'option `--theme BakePerso`. Pour éviter d'avoir à la répéter à chaque fois, vous pouvez définir le thème par défaut : +4. Lors de l'exécution de Bake, utilisez l'option `--theme CustomBake` pour utiliser votre thème de bake. Pour éviter d'avoir à la spécifier à chaque fois, vous pouvez aussi définir votre thème personnalisé par défaut : ```php Test->classSuffixes[$this->name()])) { - $this->Test->classSuffixes[$this->name()] = 'Foo'; + if ($this->args->getOption('no-test')) { + return; } - $name = ucfirst($this->name()); - if (!isset($this->Test->classTypes[$name])) { - $this->Test->classTypes[$name] = 'Foo'; - } - - return parent::bakeTest($className); + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); } ``` -- Le **suffixe de classe** sera ajouté après le nom passé à `bake`. Dans l'exemple ci-dessus, cela créerait `ExempleFooTest.php`. -- Le **type de classe** sera le sous-namespace utilisé pour atteindre le fichier relatif à l'application ou au plugin. Dans l'exemple ci-dessus, cela créerait le namespace `App\Test\TestCase\Foo`. +- Le **suffixe de classe** est ajouté après le nom fourni dans votre appel à `bake`. Dans l'exemple ci-dessus, cela créerait `ExampleFooOut` et son fichier de test `tests/TestCase/FooPath/ExampleFooOutTest.php`. +- La valeur du **type de classe** est le sous-namespace utilisé pour atteindre votre fichier depuis l'application ou le plugin dans lequel vous générez. Dans l'exemple ci-dessus, cela créerait le namespace de test `App\Test\TestCase\FooPath`. + +## Configurer la classe BakeView + +Les commandes Bake utilisent la classe `BakeView` pour rendre les templates. +Vous pouvez accéder à l'instance en écoutant l'event `Bake.initialize` : + +```php +on( + 'Bake.initialize', + function ($event, $view) { + $view->loadHelper('Foo'); + } +); +``` diff --git a/docs/fr/index.md b/docs/fr/index.md index 07930646f..6d21d2c93 100644 --- a/docs/fr/index.md +++ b/docs/fr/index.md @@ -11,7 +11,7 @@ Avant d'utiliser ou d'étendre Bake, assurez-vous qu'il est installé dans votre Bake est disponible sous forme de plugin que vous pouvez installer avec Composer : ```bash -composer require --dev cakephp/bake:"^2.0" +composer require --dev cakephp/bake:"^4.0" ``` Cela installe Bake comme dépendance de développement, et il ne sera donc pas déployé en production. @@ -21,5 +21,5 @@ Vous pouvez aussi l'omettre complètement, ce qui fera charger ce plugin à la d ## Plan de la documentation -- [Génération de code avec Bake](/fr/usage) couvre l'exécution du CLI, les commandes disponibles et les thèmes Bake. -- [Étendre Bake](/fr/development) couvre les events, les templates Twig, les thèmes et les commandes Bake personnalisées. +- [Génération de code avec Bake](/fr/usage) couvre l'exécution du CLI, la liste des commandes disponibles, la génération de modèles et d'enums, et le changement de thème Bake. +- [Étendre Bake](/fr/development) couvre les events, les templates Twig, les thèmes personnalisés, les surcharges de templates d'application et la création de commandes Bake personnalisées. diff --git a/docs/fr/usage.md b/docs/fr/usage.md index 3515cd8bf..89455d0ef 100644 --- a/docs/fr/usage.md +++ b/docs/fr/usage.md @@ -14,37 +14,118 @@ Pour Windows, utilisez `bin\cake bake --help` : ```bash $ bin/cake bake --help -Current Paths: - -* app: src/ -* root: /path/to/your/app/ -* core: /path/to/your/app/vendor/cakephp/cakephp/ - -Available Commands: - -Bake: -- bake all -- bake behavior -- bake cell -- bake command -- bake component -- bake controller -- bake controller all -- bake fixture -- bake fixture all -- bake form -- bake helper -- bake mailer -- bake middleware -- bake model -- bake model all -- bake plugin -- bake template -- bake template all -- bake test +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. To run a command, type `cake command_name [args|options]` To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` +``` + +## Modèles de Bake + +Les modèles sont générés à partir des tables existantes de la base de données. +Les conventions de CakePHP s'appliquent : Bake détecte donc les relations à partir des clés étrangères `thing_id` vers les tables `things` et leurs clés primaires `id`. + +Pour les relations non conventionnelles, vous pouvez utiliser des références dans les contraintes ou les définitions de clés étrangères afin que Bake détecte les relations : + +```php +->addForeignKey('billing_country_id', 'countries') // defaults to `id` +->addForeignKey('shipping_country_id', 'countries', 'cid') +``` + +## Enums de Bake + +Vous pouvez utiliser Bake pour générer des [enums adossés](https://www.php.net/manual/fr/language.enumerations.backed.php) à utiliser dans vos modèles. +Les enums sont placées dans `src/Model/Enum/`, implémentent `EnumLabelInterface` et utilisent `EnumLabelTrait`, qui fournit une méthode `label()` pour un affichage lisible par l'humain. + +Pour générer une enum adossée à des chaînes : + +```bash +bin/cake bake enum ArticleStatus draft,published,archived +``` + +Cela génère `src/Model/Enum/ArticleStatus.php` : + +```php +on('Bake.initialize', function (EventInterface $event) { $view = $event->getSubject(); - // bake テンプレートの中で MySpecial ヘルパーの使用を可能にします + // In my bake templates, allow the use of the MySpecial helper $view->loadHelper('MySpecial', ['some' => 'config']); - // そして、$author 変数を利用可能にするために追加 + // And add an $author variable so it's always available $view->set('author', 'Andy'); }); ``` -別のプラグインの中から Bake を変更したい場合は、プラグインの `config/bootstrap.php` に Bake イベントを置くのが有効です。 - Bake イベントは、既存テンプレートへの小さな変更にも役立ちます。 たとえば、コントローラーやテンプレートファイルを Bake するときに使う変数名を変更するには `Bake.beforeRender` を利用します。 @@ -44,7 +42,7 @@ use Cake\Event\EventManager; EventManager::instance()->on('Bake.beforeRender', function (EventInterface $event) { $view = $event->getSubject(); - // indexes の中のメインデータ変数に $rows を使用 + // Use $rows for the main data variable in indexes if ($view->get('pluralName')) { $view->set('pluralName', 'rows'); } @@ -52,7 +50,7 @@ EventManager::instance()->on('Bake.beforeRender', function (EventInterface $even $view->set('pluralVar', 'rows'); } - // view と edit の中のメインデータ変数に $theOne を使用 + // Use $theOne for the main data variable in view/edit if ($view->get('singularName')) { $view->set('singularName', 'theOne'); } @@ -69,7 +67,6 @@ EventManager::instance()->on('Bake.beforeRender', function (EventInterface $even on( function (EventInterface $event) { $view = $event->getSubject(); if ($view->get('name') === 'Users') { - // Users コントローラーに login と logout を追加 + // add the login and logout actions to the Users controller $view->set('actions', [ 'login', 'logout', @@ -97,7 +94,7 @@ EventManager::instance()->on( ## Bake テンプレート構文 -Bake テンプレートファイルは [Twig](https://twig.symfony.com/doc/2.x/) 構文を使用します。 +Bake テンプレートファイルは [Twig](https://twig.symfony.com/) 構文を使用します。 たとえば、次のようにコマンドを Bake した場合: @@ -108,48 +105,73 @@ bin/cake bake command Foo `vendor/cakephp/bake/templates/bake/Command/command.twig` のテンプレートは次のようになります。 ```php -setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } ``` +`element()` 呼び出しは `args` と `$this->io` を使用します。 + 生成される `src/Command/FooCommand.php` は次のようになります。 ```php @@ -159,37 +181,59 @@ declare(strict_types=1); namespace App\Command; use Cake\Command\Command; -use Cake\Console\Arguments; -use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; /** -* Foo command. -*/ + * Foo command. + */ class FooCommand extends Command { /** - * Hook method for defining this command's option parser. - * - * @see https://book.cakephp.org/5/en/console-commands/commands.html#defining-arguments-and-options - * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined - * @return \Cake\Console\ConsoleOptionParser The built parser. - */ - public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + * The name of this command. + * + * @var string + */ + protected string $name = 'cake foo'; + + /** + * Get the default command name. + * + * @return string + */ + public static function defaultName(): string { - $parser = parent::buildOptionParser($parser); + return 'foo'; + } - return $parser; + /** + * Get the command description. + * + * @return string + */ + public static function getDescription(): string + { + return 'Command description here.'; + } + + /** + * Hook method for defining this command's option parser. + * + * @link https://book.cakephp.org/6/en/console-commands/commands.html#defining-arguments-and-options + * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined + * @return \Cake\Console\ConsoleOptionParser The built parser. + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + return parent::buildOptionParser($parser) + ->setDescription(static::getDescription()); } /** - * Implement this method with your command's logic. - * - * @param \Cake\Console\Arguments $args The command arguments. - * @param \Cake\Console\ConsoleIo $io The console io - * @return int|null|void The exit code or null for success - */ - public function execute(Arguments $args, ConsoleIo $io) + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() { } } @@ -200,13 +244,13 @@ class FooCommand extends Command `bake` コマンドで生成された出力を変更したい場合は、一部または全部のテンプレートを置き換える独自テーマを作成できます。 1. 新しいプラグインを Bake します。プラグイン名が Bake テーマ名になります。例: `bin/cake bake plugin custom_bake` -2. `plugins/CustomBake/templates/bake/` を作成します。 +2. `plugins/CustomBake/templates/bake` を作成します。 3. 上書きしたいテンプレートを `vendor/cakephp/bake/templates/bake` から対応する場所へコピーします。 -4. Bake 実行時に `--theme CustomBake` を使います。毎回指定したくない場合はデフォルトテーマに設定することもできます。 +4. Bake 実行時に `--theme CustomBake` オプションで bake テーマを使います。毎回指定しなくても、カスタムテーマをデフォルトに設定しておくこともできます。 ```php Test->classSuffixes[$this->name()])) { - $this->Test->classSuffixes[$this->name()] = 'Foo'; - } - - $name = ucfirst($this->name()); - if (!isset($this->Test->classTypes[$name])) { - $this->Test->classTypes[$name] = 'Foo'; + if ($this->args->getOption('no-test')) { + return; } - return parent::bakeTest($className); + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); } ``` -- **class suffix** は `bake` 呼び出しで与えた名前に追加されます。前の例では `ExampleFooTest.php` を作成します。 -- **class type** はファイルに到達するためのサブ名前空間です。前の例では `App\Test\TestCase\Foo` という名前空間でテストを作成します。 +- **class suffix** は `bake` 呼び出しで与えた名前に追加されます。上の例では、`ExampleFooOut` とそのテストファイル `tests/TestCase/FooPath/ExampleFooOutTest.php` が作成されます。 +- **class type** の値は、Bake 対象のアプリケーションまたはプラグインを基準に、ファイルへ到達するために使うサブ名前空間です。上の例では、テストの名前空間 `App\Test\TestCase\FooPath` が作成されます。 ## BakeView クラスの設定 diff --git a/docs/ja/index.md b/docs/ja/index.md index bad397c78..74e8e8c8b 100644 --- a/docs/ja/index.md +++ b/docs/ja/index.md @@ -3,7 +3,7 @@ CakePHP の Bake コンソールは、CakePHP を素早く使い始めるためのツールです。 Bake コンソールは、モデル、ビヘイビアー、ビュー、ヘルパー、コントローラー、コンポーネント、 テストケース、フィクスチャー、プラグインなど、CakePHP の基本的な素材を作成できます。 -単なるスケルトンクラスだけではなく、数分で完全に機能するアプリケーションを作成できます。 +Bake はスケルトンクラスよりもはるかに多くのものを作成でき、アプリケーションのスキャフォールドが整った後の自然な次のステップです。 ## インストール手順 @@ -11,16 +11,15 @@ Bake を使用したり拡張する前に、アプリケーションに Bake を Bake は Composer を使ってインストールするプラグインとして提供されています。 ```bash -composer require --dev cakephp/bake:"^3.0" +composer require --dev cakephp/bake:"^4.0" ``` -このコマンドは、Bake を開発用依存パッケージとしてインストールします。 -そのため、本番環境へのデプロイ時にはインストールされません。 +このコマンドは、Bake を開発用依存パッケージとしてインストールするため、本番環境へのデプロイ時にはインストールされません。 Twig テンプレートを使用する場合、`Cake/TwigView` プラグインをブートストラップとともに読み込んでいることを確認してください。 完全に省略し、Bake プラグインに必要時だけ読み込ませることもできます。 ## ドキュメント一覧 -- [Bake でコード生成](/ja/usage) では CLI の実行、利用可能なコマンド、モデル生成、テーマについて説明します。 -- [Bake の拡張](/ja/development) ではイベント、Twig テンプレート、テーマ、カスタム Bake コマンドについて説明します。 +- [Bake でコード生成](/ja/usage) ではコンソールの実行、コマンドの一覧、モデルと enum の生成、テーマの切り替えについて説明します。 +- [Bake の拡張](/ja/development) ではイベント、Twig テンプレート、カスタムテーマ、アプリケーションテンプレートの上書き、カスタム Bake コマンドの作成について説明します。 diff --git a/docs/ja/usage.md b/docs/ja/usage.md index 09f3ec27d..077eecde6 100644 --- a/docs/ja/usage.md +++ b/docs/ja/usage.md @@ -14,45 +14,41 @@ Windows では `bin\cake bake --help` を使用します。 ```bash $ bin/cake bake --help -Current Paths: - -* app: src/ -* root: /path/to/your/app/ -* core: /path/to/your/app/vendor/cakephp/cakephp/ - -Available Commands: - -Bake: -- bake all -- bake behavior -- bake cell -- bake command -- bake command_helper -- bake component -- bake controller -- bake controller all -- bake enum -- bake fixture -- bake fixture all -- bake form -- bake helper -- bake mailer -- bake middleware -- bake model -- bake model all -- bake plugin -- bake template -- bake template all -- bake test +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. To run a command, type `cake command_name [args|options]` To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` ``` ## Bake モデル -モデルは既存のデータベーステーブルから生成されます。 -規約が適用されるため、外部キー `thing_id` とテーブル `things` の主キー `id` に基づいてリレーションが検出されます。 +モデルは既存のデータベーステーブルから汎用的に生成されます。 +CakePHP の規約が適用されるため、外部キー `thing_id` とテーブル `things` の主キー `id` に基づいてリレーションが検出されます。 規約から外れたリレーションの場合は、制約や外部キー定義の参照を使って Bake にリレーションを検出させることができます。 @@ -61,8 +57,78 @@ To get help on a specific command, type `cake command_name --help` ->addForeignKey('shipping_country_id', 'countries', 'cid') ``` +## Bake Enum + +Bake を使うと、モデルで使用する [backed enum](https://www.php.net/manual/en/language.enumerations.backed.php) を生成できます。 +Enum は `src/Model/Enum/` に配置され、`EnumLabelInterface` を実装して `EnumLabelTrait` を使用します。このトレイトが提供する `label()` メソッドにより、人間が読みやすい表示ができます。 + +文字列をバッキングにした enum を Bake するには次のようにします: + +```bash +bin/cake bake enum ArticleStatus draft,published,archived +``` + +これにより `src/Model/Enum/ArticleStatus.php` が生成されます: + +```php +on('Bake.initialize', function (Event $event) { +// in src/Application::bootstrapCli() + +EventManager::instance()->on('Bake.initialize', function (EventInterface $event) { $view = $event->getSubject(); // In my bake templates, allow the use of the MySpecial helper @@ -29,19 +30,17 @@ EventManager::instance()->on('Bake.initialize', function (Event $event) { }); ``` -Se você deseja modificar o Bake a partir de outro plugin, é recomendável colocar os eventos do plugin no arquivo `config/bootstrap.php`. - -Os eventos do Bake podem ser úteis para pequenas alterações nos templates existentes. -Por exemplo, para alterar os nomes das variáveis usados no controller e template quando executar o Bake: +Os eventos do Bake também podem ser úteis para fazer pequenas alterações nos templates existentes. +Por exemplo, para alterar os nomes das variáveis usadas ao gerar os arquivos de controller e template, escute o evento `Bake.beforeRender`: ```php on('Bake.beforeRender', function (Event $event) { +// in src/Application::bootstrapCli() + +EventManager::instance()->on('Bake.beforeRender', function (EventInterface $event) { $view = $event->getSubject(); // Use $rows for the main data variable in indexes @@ -62,22 +61,21 @@ EventManager::instance()->on('Bake.beforeRender', function (Event $event) { }); ``` -Você também pode aplicar os eventos `Bake.beforeRender` e `Bake.afterRender` a um arquivo específico. -Por exemplo, se quiser adicionar ações ao `UsersController` ao gerar a partir de `Controller/controller.twig`: +Você também pode restringir os eventos `Bake.beforeRender` e `Bake.afterRender` a um arquivo gerado específico. +Por exemplo, se você quiser adicionar ações específicas ao seu `UsersController` ao gerar a partir de um arquivo `Controller/controller.twig`: ```php on( 'Bake.beforeRender.Controller.controller', - function (Event $event) { + function (EventInterface $event) { $view = $event->getSubject(); - if ($view->viewVars['name'] == 'Users') { + if ($view->get('name') === 'Users') { // add the login and logout actions to the Users controller $view->set('actions', [ 'login', @@ -93,170 +91,271 @@ EventManager::instance()->on( ); ``` -Ao adicionar listeners específicos para determinados templates do Bake, você simplifica a lógica relacionada ao Bake e fornece callbacks fáceis de testar. +Ao restringir os listeners de eventos a templates específicos do bake, você simplifica a lógica de eventos relacionada ao bake e fornece callbacks mais fáceis de testar. ## Sintaxe de Templates do Bake -Os arquivos de template do Bake usam a sintaxe [Twig](https://twig.symfony.com/doc/2.x/). +Os arquivos de template do Bake usam a sintaxe de templates [Twig](https://twig.symfony.com/). -Então, por exemplo, quando você executar algo como: +Por exemplo, ao gerar um comando como este: ```bash -bin/cake bake shell Foo +bin/cake bake command Foo ``` -O template usado em `vendor/cakephp/bake/src/Template/Bake/Shell/shell.twig` parece com isto: +O template usado em `vendor/cakephp/bake/templates/bake/Command/command.twig` tem este aspecto: ```php -setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. * - * @return bool|int Success or error code. + * @return int|null|void The exit code or null for success */ - public function main() + public function execute() { } } ``` -E o resultado gerado em `src/Shell/FooShell.php` é semelhante a: +A chamada `element()` emite o cabeçalho `args` e `$this->io` em vez de recebê-los como parâmetros de `execute()`. + +A classe gerada em `src/Command/FooCommand.php` fica assim: ```php setDescription(static::getDescription()); + } -- `<%` abre uma tag PHP de template Bake. -- `%>` fecha uma tag PHP de template Bake. -- `<%=` é a forma short-echo do template Bake. -- `<%-` abre a tag removendo espaços em branco antes dela. -- `-%>` fecha a tag removendo espaços em branco após ela. -::: + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() + { + } +} +``` ## Criando um Tema Bake -Se você deseja modificar a saída produzida com o comando `bake`, pode criar seu próprio tema para substituir alguns ou todos os templates que o Bake usa. +Se você deseja modificar a saída produzida pelo comando `bake`, pode criar seu próprio tema do Bake, o que permite substituir alguns ou todos os templates que o Bake usa. -1. Gere um novo plugin. O nome do plugin é o nome do tema. -2. Crie uma nova pasta em `plugins/[name]/Template/Bake/Template/`. -3. Copie qualquer template que queira modificar de `vendor/cakephp/bake/src/Template/Bake/Template` para a pasta acima e altere conforme sua necessidade. -4. Ao executar o Bake, use a opção `--theme` para especificar o tema. Para evitar repetir isso a cada chamada, também é possível definir o tema padrão: +1. Gere um novo plugin. O nome do plugin é o nome do tema do Bake. Por exemplo, `bin/cake bake plugin custom_bake`. +2. Crie um novo diretório em `plugins/CustomBake/templates/bake`. +3. Copie quaisquer templates que queira sobrescrever de `vendor/cakephp/bake/templates/bake` para arquivos correspondentes no seu plugin. +4. Ao executar o Bake, use a opção `--theme CustomBake` para usar seu tema do bake. Para evitar especificar essa opção toda vez, você também pode definir seu tema personalizado como padrão: ```php Test->classSuffixes[$this->name()])) { - $this->Test->classSuffixes[$this->name()] = 'Foo'; - } +use Bake\Command\TestCommand; - $name = ucfirst($this->name()); - if (!isset($this->Test->classTypes[$name])) { - $this->Test->classTypes[$name] = 'Foo'; +public function bakeTest(string $className): void +{ + if ($this->args->getOption('no-test')) { + return; } - return parent::bakeTest($className); + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); } ``` -- O **sufixo da classe** será anexado ao nome fornecido na chamada ao Bake. No exemplo acima, isso criaria `ExampleFooTest.php`. -- O **tipo de classe** será o subnamespace usado para levar ao arquivo relativo à aplicação ou plugin. No exemplo acima, isso criaria o namespace `App\Test\TestCase\Foo`. +- O **sufixo da classe** é anexado ao nome fornecido na sua chamada ao `bake`. No exemplo acima, isso criaria `ExampleFooOut` e seu arquivo de teste `tests/TestCase/FooPath/ExampleFooOutTest.php`. +- O valor do **tipo de classe** é o sub-namespace usado para acessar seu arquivo em relação ao app ou plugin no qual você está gerando. No exemplo acima, isso criaria o namespace de teste `App\Test\TestCase\FooPath`. + +## Configurando a Classe BakeView + +Os comandos do Bake usam a classe `BakeView` para renderizar templates. +Você pode acessar a instância escutando o evento `Bake.initialize`: + +```php +on( + 'Bake.initialize', + function ($event, $view) { + $view->loadHelper('Foo'); + } +); +``` diff --git a/docs/pt/index.md b/docs/pt/index.md index fb09a83d4..99952c64c 100644 --- a/docs/pt/index.md +++ b/docs/pt/index.md @@ -1,25 +1,25 @@ # Console Bake -O console do Bake é uma ferramenta para você sair produzindo em CakePHP rapidamente. -Ele pode criar os itens básicos do CakePHP, como models, behaviors, views, helpers, -controllers, components, test cases, fixtures e plugins. -Bake pode ir além de classes esqueleto e gerar uma base funcional em poucos minutos. +O console do Bake do CakePHP é mais uma forma de você começar a trabalhar em CakePHP rapidamente. +O console do Bake pode criar qualquer um dos ingredientes básicos do CakePHP: models, +behaviors, views, helpers, controllers, components, test cases, fixtures e plugins. +O Bake pode criar muito mais do que classes esqueleto e é um próximo passo natural depois que uma aplicação passou por scaffolding. ## Instalação Antes de usar ou estender o Bake, tenha certeza de que ele está instalado em sua aplicação. -Bake é distribuído como um plugin que você pode instalar com Composer: +O Bake é distribuído como um plugin que você pode instalar com Composer: ```bash -composer require --dev cakephp/bake:~2.0 +composer require --dev cakephp/bake:"^4.0" ``` -Isso instala o Bake como dependência de desenvolvimento, portanto ele não será instalado em produção. +O comando acima instala o Bake como dependência de desenvolvimento, portanto ele não será instalado em implantações de produção. Ao usar templates Twig, verifique se você está carregando o plugin `Cake/TwigView` com seu bootstrap. -Você também pode omiti-lo completamente, o que faz com que o plugin Bake carregue esse plugin sob demanda. +Você também pode omiti-lo completamente, o que faz com que o plugin Bake o carregue sob demanda. ## Mapa da documentação -- [Geração de código com Bake](/pt/usage) cobre a execução do CLI, os comandos disponíveis e os temas do Bake. -- [Estendendo o Bake](/pt/development) cobre eventos, templates, temas e novos comandos de Bake. +- [Geração de código com Bake](/pt/usage) cobre a execução do console, a listagem de comandos, a geração de models e enums e a troca de temas do bake. +- [Estendendo o Bake](/pt/development) cobre eventos, templates Twig, temas personalizados, sobrescrita de templates pela aplicação e a criação de novos comandos de bake. diff --git a/docs/pt/usage.md b/docs/pt/usage.md index fd89ed1ae..498103144 100644 --- a/docs/pt/usage.md +++ b/docs/pt/usage.md @@ -3,102 +3,132 @@ O console do Bake é executado usando o PHP CLI. Se você tiver problemas para executar o script, assegure-se de que: -1. Você instalou o PHP CLI e possui os módulos apropriados habilitados, por exemplo MySQL e `intl`. -2. Se o host do banco de dados for `localhost`, tente `127.0.0.1`, pois `localhost` pode causar problemas no PHP CLI. -3. Dependendo de como o seu computador está configurado, pode ser necessário definir permissões de execução no script Cake para chamá-lo com `bin/cake bake`. +1. Você tem o PHP CLI instalado e com os módulos apropriados habilitados, como MySQL e `intl`. +2. Se o host do banco de dados for `localhost`, tente `127.0.0.1` em vez disso, pois `localhost` pode causar problemas no PHP CLI. +3. Dependendo de como o seu computador está configurado, pode ser necessário definir permissões de execução no script do Cake para chamá-lo usando `bin/cake bake`. Antes de executar o Bake, você deve ter pelo menos uma conexão de banco de dados configurada. -Para ver as opções disponíveis no Bake, digite: +Você pode obter a lista de comandos de bake disponíveis executando `bin/cake bake --help`. +No Windows, use `bin\cake bake --help`: ```bash $ bin/cake bake --help - -Current Paths: - -* app: src -* root: . -* core: .\vendor\cakephp\cakephp - -Available Commands: - -Bake: - - bake all - - bake behavior - - bake cell - - bake command - - bake component - - bake controller - - bake controller all - - bake fixture - - bake fixture all - - bake form - - bake helper - - bake mailer - - bake middleware - - bake model - - bake model all - - bake plugin - - bake task - - bake template - - bake template all - - bake test +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. To run a command, type `cake command_name [args|options]` To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` +``` + +## Models com Bake + +Os models são gerados a partir das tabelas existentes no banco de dados. +As convenções do CakePHP se aplicam, então o Bake detecta relações baseadas em chaves estrangeiras `thing_id` para tabelas `things` com suas chaves primárias `id`. + +Para relações não convencionais, você pode usar referências nas definições de constraints ou de chaves estrangeiras para que o Bake detecte as relações: + +```php +->addForeignKey('billing_country_id', 'countries') // defaults to `id` +->addForeignKey('shipping_country_id', 'countries', 'cid') +``` + +## Enums com Bake + +Você pode usar o Bake para gerar [enums com valor (backed enums)](https://www.php.net/manual/en/language.enumerations.backed.php) para uso em seus models. +Os enums são colocados em `src/Model/Enum/`, implementam `EnumLabelInterface` e usam `EnumLabelTrait`, que fornece o método `label()` para exibição legível. + +Para gerar um enum com suporte a string: + +```bash +bin/cake bake enum ArticleStatus draft,published,archived +``` + +Isso gera `src/Model/Enum/ArticleStatus.php`: + +```php +] - -Options: - ---connection, -c The datasource connection to get data from. - (default: default) ---display-field The displayField if you would like to choose one. ---fields A comma separated list of fields to make - accessible. ---force, -f Force overwriting existing files without - prompting. ---help, -h Display this help. ---hidden A comma separated list of fields to hide. ---no-associations Disable generating associations. ---no-entity Disable generating an entity class. ---no-fields Disable generating accessible fields in the - entity. ---no-fixture Do not generate a test fixture skeleton. ---no-hidden Disable generating hidden fields in the entity. ---no-rules Disable generating a rules checker. ---no-table Disable generating a table class. ---no-test Do not generate a test case skeleton. ---no-validation Disable generating validation rules. ---plugin, -p Plugin to bake into. ---primary-key The primary key if you would like to manually set - one. Can be a comma separated list if you are - using a composite primary key. ---quiet, -q Enable quiet output. ---table The table name to use if you have - non-conventional table names. ---theme, -t The theme to use when baking code. ---verbose, -v Enable verbose output. - -Arguments: - -name Name of the model to bake (without the Table suffix). You can use - Plugin.name to bake plugin models. (optional) - -Omitting all arguments and options will list the table names you can -generate models for. +bin/cake bake enum MyPlugin.OrderStatus pending,processing,shipped ``` -## Temas para o Bake +## Temas do Bake -A opção `theme` é comum a todos os comandos do Bake e permite mudar os arquivos de template usados por ele. +A opção `theme` é comum a todos os comandos de bake e permite mudar os arquivos de template usados na geração. Para criar seus próprios templates, veja [Criando um Tema Bake](/pt/development#criando-um-tema-bake). diff --git a/docs/ru/development.md b/docs/ru/development.md index 47dda1b25..2ae668f90 100644 --- a/docs/ru/development.md +++ b/docs/ru/development.md @@ -1,50 +1,48 @@ # Расширение возможностей Bake Bake имеет расширяемую архитектуру, которая позволяет вашему приложению или плагинам изменять или дополнять базовую функциональность. -Bake использует специальный класс представления и механизм шаблонизатора [Twig](https://twig.symfony.com/). +Bake использует выделенный класс представления, работающий с движком шаблонов [Twig](https://twig.symfony.com/). ## События Bake -`BakeView`, как и любой другой класс представления, генерирует стандартные события, а также дополнительное событие инициализации. -Стандартные классы представления используют префикс `View.`, а `BakeView` использует префикс `Bake.`. +Как и любой другой класс представления, `BakeView` генерирует те же события, плюс одно дополнительное событие инициализации. +Однако стандартные классы представления используют префикс события `View.`, а `BakeView` — префикс `Bake.`. -Событие `initialize` можно использовать для внесения изменений, которые применяются ко всему выводу Bake. -Например, чтобы добавить helper в класс представления Bake: +Событие инициализации можно использовать для внесения изменений, которые применяются ко всему выводу Bake. +Например, чтобы добавить ещё один helper в класс представления Bake: ```php on('Bake.initialize', function (Event $event) { +// in src/Application::bootstrapCli() + +EventManager::instance()->on('Bake.initialize', function (EventInterface $event) { $view = $event->getSubject(); - // В моих шаблонах bake разрешить использование MySpecial helper + // In my bake templates, allow the use of the MySpecial helper $view->loadHelper('MySpecial', ['some' => 'config']); - // И добавить переменную $author, чтобы она всегда была доступна + // And add an $author variable so it's always available $view->set('author', 'Andy'); }); ``` -Если вы хотите изменить Bake из другого плагина, удобнее всего разместить события плагина в `config/bootstrap.php`. - -События Bake полезны и для небольших изменений существующих шаблонов. -Например, чтобы изменить имена переменных, используемых при генерации controller и template файлов, можно слушать `Bake.beforeRender`: +События Bake также пригодятся для небольших изменений существующих шаблонов. +Например, чтобы изменить имена переменных, используемых при генерации файлов контроллера и шаблона, слушайте событие `Bake.beforeRender`: ```php on('Bake.beforeRender', function (Event $event) { +// in src/Application::bootstrapCli() + +EventManager::instance()->on('Bake.beforeRender', function (EventInterface $event) { $view = $event->getSubject(); - // Использовать $rows для основной переменной данных в index + // Use $rows for the main data variable in indexes if ($view->get('pluralName')) { $view->set('pluralName', 'rows'); } @@ -52,7 +50,7 @@ EventManager::instance()->on('Bake.beforeRender', function (Event $event) { $view->set('pluralVar', 'rows'); } - // Использовать $theOne для основной переменной данных в view/edit + // Use $theOne for the main data variable in view/edit if ($view->get('singularName')) { $view->set('singularName', 'theOne'); } @@ -62,24 +60,23 @@ EventManager::instance()->on('Bake.beforeRender', function (Event $event) { }); ``` -Вы также можете привязать события `Bake.beforeRender` и `Bake.afterRender` к конкретному генерируемому файлу. -Например, если вы хотите добавить действия в `UsersController` при генерации из `Controller/controller.twig`: +Вы также можете ограничить события `Bake.beforeRender` и `Bake.afterRender` конкретным генерируемым файлом. +Например, если вы хотите добавить определённые действия в ваш `UsersController` при генерации из файла `Controller/controller.twig`: ```php on( 'Bake.beforeRender.Controller.controller', - function (Event $event) { + function (EventInterface $event) { $view = $event->getSubject(); - if ($view->viewVars['name'] == 'Users') { - // добавим действия входа и выхода в контроллер Users - $view->viewVars['actions'] = [ + if ($view->get('name') === 'Users') { + // add the login and logout actions to the Users controller + $view->set('actions', [ 'login', 'logout', 'index', @@ -87,177 +84,277 @@ EventManager::instance()->on( 'add', 'edit', 'delete', - ]; + ]); } } ); ``` -Фокусируя обработчики на конкретных шаблонах Bake, вы упрощаете связанную с Bake логику событий и получаете более удобные для тестирования callback-функции. +Привязывая обработчики событий к конкретным шаблонам bake, вы упрощаете связанную с Bake логику событий и получаете более удобные для тестирования callback-функции. ## Синтаксис шаблонов Bake -Файлы шаблонов Bake используют синтаксис [Twig](https://twig.symfony.com/doc/2.x/). +Файлы шаблонов Bake используют синтаксис шаблонов [Twig](https://twig.symfony.com/). -Например, при генерации shell-команды: +Например, при генерации команды следующим образом: ```bash -bin/cake bake shell Foo +bin/cake bake command Foo ``` -Шаблон `vendor/cakephp/bake/src/Template/Bake/Shell/shell.twig` выглядит так: +Шаблон, используемый в `vendor/cakephp/bake/templates/bake/Command/command.twig`, выглядит так: ```php -setDescription(static::getDescription()); + } + + /** + * Implement this method with your command's logic. * - * @return bool|int Success or error code. + * @return int|null|void The exit code or null for success */ - public function main() + public function execute() { } } ``` -И итоговый класс `src/Shell/FooShell.php` будет выглядеть так: +Вызов `element()` выводит заголовок `args` и `$this->io` вместо того, чтобы получать их в качестве параметров `execute()`. + +Итоговый сгенерированный класс в `src/Command/FooCommand.php` выглядит так: ```php setDescription(static::getDescription()); + } -- `<%` открывающий PHP-тег шаблона Bake. -- `%>` закрывающий PHP-тег шаблона Bake. -- `<%=` короткий echo-тег шаблона Bake. -- `<%-` открывающий тег с удалением пробелов перед тегом. -- `-%>` закрывающий тег с удалением пробелов после тега. -::: + /** + * Implement this method with your command's logic. + * + * @return int|null|void The exit code or null for success + */ + public function execute() + { + } +} +``` ## Создание темы Bake -Если вы хотите изменить вывод, создаваемый командой `bake`, вы можете создать собственную тему Bake, которая позволит заменить часть или все шаблоны. +Если вы хотите изменить вывод, создаваемый командой `bake`, вы можете создать собственную тему Bake, которая позволит заменить часть или все шаблоны, используемые Bake. -1. Сгенерируйте новый плагин. Имя плагина станет именем темы Bake. -2. Создайте директорию `plugins/[name]/src/Template/Bake/Template/`. -3. Скопируйте нужные шаблоны из `vendor/cakephp/bake/src/Template/Bake/Template` в соответствующие файлы вашего плагина. -4. При запуске Bake используйте параметр `--theme`, чтобы указать тему. Чтобы не передавать его каждый раз, можно настроить тему по умолчанию: +1. Сгенерируйте новый плагин. Имя плагина станет именем темы Bake. Например, `bin/cake bake plugin custom_bake`. +2. Создайте новую директорию `plugins/CustomBake/templates/bake`. +3. Скопируйте нужные шаблоны из `vendor/cakephp/bake/templates/bake` в соответствующие файлы вашего плагина. +4. При запуске Bake используйте параметр `--theme CustomBake`, чтобы применить вашу тему. Чтобы не указывать его каждый раз, можно сделать вашу собственную тему темой по умолчанию: ```php Test->classSuffixes[$this->name()])) { - $this->Test->classSuffixes[$this->name()] = 'Foo'; - } +use Bake\Command\TestCommand; - $name = ucfirst($this->name()); - if (!isset($this->Test->classTypes[$name])) { - $this->Test->classTypes[$name] = 'Foo'; +public function bakeTest(string $className): void +{ + if ($this->args->getOption('no-test')) { + return; } - return parent::bakeTest($className); + $test = new TestCommand(); + $test->classSuffixes['Foo'] = 'FooOut'; + $test->classTypes['Foo'] = 'FooPath'; + $test->plugin = $this->plugin; + $test->setArgs($this->args); + $test->setIo($this->io); + $test->bake('Foo', $className); } ``` -- **Суффикс класса** добавляется к имени, переданному в вызове `bake`. В примере выше это создаст `ExampleFooTest.php`. -- **Тип класса** определяет подпространство имён, ведущее к файлу относительно приложения или плагина. В примере выше это создаст тест с namespace `App\Test\TestCase\Foo`. +- **Суффикс класса** добавляется к имени, переданному в вашем вызове `bake`. В примере выше это создаст `ExampleFooOut` и его тестовый файл `tests/TestCase/FooPath/ExampleFooOutTest.php`. +- Значение **типа класса** — это подпространство имён, ведущее к вашему файлу относительно приложения или плагина, в который выполняется генерация. В примере выше это создаст namespace теста `App\Test\TestCase\FooPath`. + +## Настройка класса BakeView + +Команды Bake используют класс `BakeView` для отрисовки шаблонов. +Получить доступ к экземпляру можно, слушая событие `Bake.initialize`: + +```php +on( + 'Bake.initialize', + function ($event, $view) { + $view->loadHelper('Foo'); + } +); +``` diff --git a/docs/ru/index.md b/docs/ru/index.md index d330e7319..ae6e4b83f 100644 --- a/docs/ru/index.md +++ b/docs/ru/index.md @@ -1,23 +1,24 @@ # Консоль Bake -Консоль Bake для CakePHP помогает быстро начать разработку. -Она может создать базовые компоненты CakePHP, включая models, behaviors, views, -helpers, controllers, components, test cases, fixtures и plugins. -Bake умеет создавать не только каркас приложения, но и полностью рабочую основу за считанные минуты. +Консоль bake для CakePHP — ещё один способ быстро начать работу с CakePHP. +Консоль bake может создать любые базовые ингредиенты CakePHP: модели, поведения, представления, помощники, контроллеры, компоненты, тесты, фикстуры и плагины. +Bake умеет создавать гораздо больше, чем просто скелеты классов, и является естественным следующим шагом после создания каркаса приложения. ## Установка -Перед тем как использовать Bake, убедитесь, что он установлен в вашем приложении. -Bake распространяется как отдельный плагин, который можно установить через Composer: +Перед тем как использовать или расширять Bake, убедитесь, что он установлен в вашем приложении. +Bake предоставляется в виде плагина, который можно установить через Composer: ```bash -composer require --dev cakephp/bake:~1.0 +composer require --dev cakephp/bake:"^4.0" ``` -Команда выше установит Bake как зависимость для разработки. -Это значит, что Bake не будет установлен при деплое на production. +Команда выше установит Bake как зависимость для разработки, поэтому он не будет установлен при деплое на production. + +При использовании шаблонов Twig убедитесь, что загружаете плагин `Cake/TwigView` вместе с его bootstrap. +Вы также можете опустить это полностью — тогда плагин Bake загрузит его по мере необходимости. ## Карта документации -- [Генерация кода с помощью Bake](/ru/usage) описывает запуск CLI, список задач и темы Bake. -- [Расширение возможностей Bake](/ru/development) описывает события, шаблоны, темы и добавление собственных команд. +- [Генерация кода с помощью Bake](/ru/usage) описывает запуск консоли, список команд, генерацию моделей и enum'ов, а также смену тем bake. +- [Расширение возможностей Bake](/ru/development) описывает события, шаблоны Twig, собственные темы, переопределение шаблонов приложения и создание собственных команд bake. diff --git a/docs/ru/usage.md b/docs/ru/usage.md index 97207aefd..814d6ae7e 100644 --- a/docs/ru/usage.md +++ b/docs/ru/usage.md @@ -1,117 +1,134 @@ # Генерация кода с помощью Bake -Консоль Cake запускается с использованием PHP CLI. +Консоль Bake запускается с использованием PHP CLI. Если у вас возникли проблемы с запуском скрипта, убедитесь, что: 1. У вас установлен PHP CLI и включены нужные модули, например MySQL и `intl`. 2. Если хост базы данных указан как `localhost`, попробуйте `127.0.0.1`, потому что `localhost` может вызывать проблемы в PHP CLI. -3. В зависимости от того, как настроен ваш компьютер, вам может потребоваться выдать права на выполнение скрипта, чтобы запускать `bin/cake bake`. +3. В зависимости от того, как настроен ваш компьютер, вам может потребоваться выдать права на выполнение скрипта Cake, чтобы запускать `bin/cake bake`. Перед запуском Bake вы должны убедиться, что у вас настроено хотя бы одно соединение с базой данных. -При запуске без аргументов `bin/cake bake` выводит список доступных задач. -Вы должны увидеть что-то вроде: +Получить список доступных команд bake можно, запустив `bin/cake bake --help`. +В Windows используйте `bin\cake bake --help`: ```bash -$ bin/cake bake - -Welcome to CakePHP v3.4.6 Console ---------------------------------------------------------------- -App : src -Path: /var/www/cakephp.dev/src/ -PHP : 5.6.20 ---------------------------------------------------------------- -The following commands can be used to generate skeleton code for your application. - -Available bake commands: - -- all -- behavior -- cell -- component -- controller -- fixture -- form -- helper -- mailer -- migration -- migration_diff -- migration_snapshot -- model -- plugin -- seed -- task -- template -- test - -By using `cake bake [name]` you can invoke a specific bake task. +$ bin/cake bake --help +bake: + bake all + bake behavior Create a model behavior and test. + bake cell Create a view cell, template and test. + bake command Create a console command and test. + bake command_helper Create a console command helper and test. + bake component + bake controller Create a controller and test + bake controller all Create all controllers for an application or plugin. + bake enum Create a model Enum + bake fixture Create a test fixture class. + bake fixture all Create all fixtures for an application or plugin. + bake form Create a form class and test. + bake helper Create a view helper and test. + bake mailer Create a mailer and test. + bake middleware Create a middleware class and test. + bake model Create a table class and its related entity, enums, + test fixture and tests. + bake model all Create all models, fixtures and tests in an application + or plugin. + bake plugin Create a plugin. + bake template Create a view template. + bake template all Create all view templates for all controllers in an + application or plugin. + bake test Create a test case skeleton for a class. + +To run a command, type `cake command_name [args|options]` +To get help on a specific command, type `cake command_name --help` +To see full descriptions and plugin grouping, use `cake --help -v` +``` + +## Модели Bake + +Модели генерируются на основе существующих таблиц базы данных. +Применяются соглашения CakePHP, поэтому Bake определяет связи по внешним ключам `thing_id`, ссылающимся на таблицы `things` с их первичными ключами `id`. + +Для нестандартных связей можно использовать ссылки в ограничениях или определениях внешних ключей, чтобы Bake определил связи: + +```php +->addForeignKey('billing_country_id', 'countries') // defaults to `id` +->addForeignKey('shipping_country_id', 'countries', 'cid') ``` -Дополнительную информацию о задачах и доступных параметрах можно получить через `--help`: +## Enum'ы Bake + +С помощью Bake можно генерировать [backed enum'ы](https://www.php.net/manual/en/language.enumerations.backed.php) для использования в ваших моделях. +Enum'ы размещаются в `src/Model/Enum/`, реализуют `EnumLabelInterface` и используют `EnumLabelTrait`, который предоставляет метод `label()` для отображения в человекочитаемом виде. + +Чтобы сгенерировать enum со строковыми значениями: ```bash -$ bin/cake bake --help +bin/cake bake enum ArticleStatus draft,published,archived +``` + +В результате создаётся `src/Model/Enum/ArticleStatus.php`: + +```php +