├── LICENSE ├── README.md ├── annotate-watcher.cjs ├── composer.json ├── config └── app.example.php ├── docs ├── Annotations.md ├── CodeCompletion.md ├── Contributing.md ├── Generator.md ├── Illuminator.md ├── README.md ├── img │ ├── code_completion.png │ ├── configure_autocomplete.png │ ├── fields_autocomplete.png │ ├── model_autocomplete.png │ ├── model_autocomplete_finder.png │ ├── model_autocomplete_loadmodel.png │ ├── model_typehinting.png │ └── validation_autocomplete_validator_require_presence.png └── screenshot.jpg ├── phpcs.xml ├── phpstan.neon ├── src ├── Annotation │ ├── AbstractAnnotation.php │ ├── AnnotationFactory.php │ ├── AnnotationInterface.php │ ├── ExtendsAnnotation.php │ ├── LinkAnnotation.php │ ├── MethodAnnotation.php │ ├── MixinAnnotation.php │ ├── ParamAnnotation.php │ ├── PropertyAnnotation.php │ ├── PropertyReadAnnotation.php │ ├── ReplacableAnnotationInterface.php │ ├── SeeAnnotation.php │ ├── UsesAnnotation.php │ └── VariableAnnotation.php ├── Annotator │ ├── AbstractAnnotator.php │ ├── CallbackAnnotator.php │ ├── CallbackAnnotatorTask │ │ ├── AbstractCallbackAnnotatorTask.php │ │ ├── CallbackAnnotatorTaskInterface.php │ │ ├── TableCallbackAnnotatorTask.php │ │ └── VirtualFieldCallbackAnnotatorTask.php │ ├── CallbackAnnotatorTaskCollection.php │ ├── ClassAnnotator.php │ ├── ClassAnnotatorTask │ │ ├── AbstractClassAnnotatorTask.php │ │ ├── ClassAnnotatorTaskInterface.php │ │ ├── FormClassAnnotatorTask.php │ │ ├── MailerClassAnnotatorTask.php │ │ ├── ModelAwareClassAnnotatorTask.php │ │ └── TestClassAnnotatorTask.php │ ├── ClassAnnotatorTaskCollection.php │ ├── CommandAnnotator.php │ ├── ComponentAnnotator.php │ ├── ControllerAnnotator.php │ ├── EntityAnnotator.php │ ├── HelperAnnotator.php │ ├── ModelAnnotator.php │ ├── Template │ │ └── VariableExtractor.php │ ├── TemplateAnnotator.php │ ├── Traits │ │ ├── ComponentTrait.php │ │ ├── DocBlockTrait.php │ │ ├── FileTrait.php │ │ ├── HelperTrait.php │ │ ├── ModelTrait.php │ │ └── UseStatementsTrait.php │ └── ViewAnnotator.php ├── CodeCompletion │ ├── CodeCompletionGenerator.php │ ├── Task │ │ ├── BehaviorTask.php │ │ ├── ControllerEventsTask.php │ │ ├── ModelEventsTask.php │ │ ├── TaskInterface.php │ │ └── ViewEventsTask.php │ └── TaskCollection.php ├── Command │ ├── Annotate │ │ ├── AllCommand.php │ │ ├── CallbacksCommand.php │ │ ├── ClassesCommand.php │ │ ├── CommandsCommand.php │ │ ├── ComponentsCommand.php │ │ ├── ControllersCommand.php │ │ ├── HelpersCommand.php │ │ ├── ModelsCommand.php │ │ ├── TemplatesCommand.php │ │ └── ViewCommand.php │ ├── AnnotateCommand.php │ ├── Command.php │ ├── GenerateCodeCompletionCommand.php │ ├── GeneratePhpStormMetaCommand.php │ └── IlluminateCommand.php ├── Console │ └── Io.php ├── Filesystem │ └── Folder.php ├── Generator │ ├── Directive │ │ ├── BaseDirective.php │ │ ├── ExitPoint.php │ │ ├── ExpectedArguments.php │ │ ├── ExpectedReturnValues.php │ │ ├── Override.php │ │ └── RegisterArgumentsSet.php │ ├── GeneratorInterface.php │ ├── PhpstormGenerator.php │ ├── Task │ │ ├── BehaviorTask.php │ │ ├── CacheTask.php │ │ ├── CellTask.php │ │ ├── ComponentTask.php │ │ ├── ConfigureTask.php │ │ ├── ConnectionTask.php │ │ ├── ConsoleHelperTask.php │ │ ├── ConsoleTask.php │ │ ├── DatabaseTableColumnNameTask.php │ │ ├── DatabaseTableColumnTypeTask.php │ │ ├── DatabaseTableTask.php │ │ ├── DatabaseTypeTask.php │ │ ├── ElementTask.php │ │ ├── EntityTask.php │ │ ├── EnvTask.php │ │ ├── FixtureTask.php │ │ ├── FormHelperTask.php │ │ ├── HelperTask.php │ │ ├── LayoutTask.php │ │ ├── MailerTask.php │ │ ├── ModelTask.php │ │ ├── PluginTask.php │ │ ├── RequestTask.php │ │ ├── RoutePathTask.php │ │ ├── TableAssociationTask.php │ │ ├── TableFinderTask.php │ │ ├── TaskInterface.php │ │ ├── TranslationKeyTask.php │ │ └── ValidationTask.php │ └── TaskCollection.php ├── IdeHelperPlugin.php ├── Illuminator │ ├── Illuminator.php │ ├── Task │ │ ├── AbstractTask.php │ │ └── EntityFieldTask.php │ └── TaskCollection.php ├── Utility │ ├── App.php │ ├── AppPath.php │ ├── CollectionClass.php │ ├── ControllerActionParser.php │ ├── GenericString.php │ ├── Plugin.php │ ├── PluginPath.php │ └── TranslationParser.php ├── ValueObject │ ├── ArgumentsSet.php │ ├── ClassName.php │ ├── KeyValue.php │ ├── LiteralName.php │ ├── StringName.php │ └── ValueObjectInterface.php └── View │ └── Helper │ └── DocBlockHelper.php └── tests ├── Fixture ├── BarBarsFixture.php ├── CarsFixture.php ├── FoosFixture.php ├── HousesFixture.php ├── WheelsFixture.php └── WindowsFixture.php ├── TestCase ├── Annotation │ ├── AnnotationFactoryTest.php │ ├── ExtendsAnnotationTest.php │ ├── MethodAnnotationTest.php │ ├── MixinAnnotationTest.php │ ├── ParamAnnotationTest.php │ ├── PropertyAnnotationTest.php │ ├── UsesAnnotationTest.php │ └── VariableAnnotationTest.php ├── Annotator │ ├── CallbackAnnotatorTask │ │ └── VirtualFieldCallbackAnnotatorTaskTest.php │ ├── CallbackAnnotatorTest.php │ ├── ClassAnnotatorTask │ │ ├── FormClassAnnotatorTaskTest.php │ │ ├── MailerClassAnnotatorTaskTest.php │ │ └── TestClassAnnotatorTaskTest.php │ ├── ClassAnnotatorTest.php │ ├── CommandAnnotatorTest.php │ ├── ComponentAnnotatorTest.php │ ├── ControllerAnnotatorTest.php │ ├── DiffHelperTrait.php │ ├── EntityAnnotatorTest.php │ ├── HelperAnnotatorTest.php │ ├── ModelAnnotatorSpecificTest.php │ ├── ModelAnnotatorTest.php │ ├── Template │ │ └── VariableExtractorTest.php │ ├── TemplateAnnotatorTest.php │ └── ViewAnnotatorTest.php ├── CodeCompletion │ ├── CodeCompletionGeneratorTest.php │ ├── Task │ │ ├── BehaviorTaskTest.php │ │ ├── ControllerEventsTaskTest.php │ │ ├── ModelEventsTaskTest.php │ │ └── ViewEventsTaskTest.php │ └── TaskCollectionTest.php ├── Command │ ├── AnnotateCommandTest.php │ ├── GenerateCodeCompletionCommandTest.php │ ├── GeneratePhpstormMetaCommandTest.php │ └── IlluminateCommandTest.php ├── Console │ └── IoTest.php ├── Generator │ ├── Directive │ │ ├── ExitPointTest.php │ │ ├── ExpectedArgumentsTest.php │ │ ├── ExpectedReturnValuesTest.php │ │ ├── OverrideTest.php │ │ └── RegisterArgumentsSetTest.php │ ├── PhpstormGeneratorTest.php │ ├── Task │ │ ├── BehaviorTaskTest.php │ │ ├── CacheTaskTest.php │ │ ├── CellTaskTest.php │ │ ├── ComponentTaskTest.php │ │ ├── ConfigureTaskTest.php │ │ ├── ConnectionTaskTest.php │ │ ├── ConsoleHelperTaskTest.php │ │ ├── ConsoleTaskTest.php │ │ ├── DatabaseTableColumnNameTaskTest.php │ │ ├── DatabaseTableColumnTypeTaskTest.php │ │ ├── DatabaseTableTaskTest.php │ │ ├── DatabaseTypeTaskTest.php │ │ ├── ElementTaskTest.php │ │ ├── EntityTaskTest.php │ │ ├── EnvTaskTest.php │ │ ├── FixtureTaskTest.php │ │ ├── FormHelperTaskTest.php │ │ ├── HelperTaskTest.php │ │ ├── LayoutTaskTest.php │ │ ├── MailerTaskTest.php │ │ ├── ModelTaskTest.php │ │ ├── PluginTaskTest.php │ │ ├── RequestTaskTest.php │ │ ├── RoutePathTaskTest.php │ │ ├── TableAssociationTaskTest.php │ │ ├── TableFinderTaskTest.php │ │ ├── TranslationKeyTaskTest.php │ │ └── ValidationTaskTest.php │ └── TaskCollectionTest.php ├── Illuminator │ ├── IlluminatorTest.php │ └── Task │ │ └── EntityFieldTaskTest.php ├── Utility │ ├── AppPathTest.php │ ├── AppTest.php │ ├── GenericStringTest.php │ ├── PluginPathTest.php │ ├── PluginTest.php │ └── TranslationParserTest.php ├── ValueObject │ ├── ClassNameTest.php │ ├── DoubleQuoteStringNameTest.php │ ├── KeyValueTest.php │ ├── LiteralNameTest.php │ └── StringNameTest.php └── View │ └── Helper │ └── DocBlockHelperTest.php ├── bootstrap.php ├── phpstan.neon ├── schema.php └── shim.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mark Sch. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /annotate-watcher.cjs: -------------------------------------------------------------------------------- 1 | // watcher.js 2 | const chokidar = require('chokidar'); 3 | const { exec } = require('child_process'); 4 | 5 | // Helper to parse CLI arguments 6 | function getPathsFromArgs() { 7 | const arg = process.argv.find(arg => arg.startsWith('--path=')); 8 | if (!arg) return ['src/', 'templates/']; // default path 9 | const value = arg.split('=')[1]; 10 | return value.split(',').map(p => p.trim()).filter(Boolean); 11 | } 12 | 13 | const watchPaths = getPathsFromArgs(); 14 | console.log(`🔍 Watching: ${watchPaths.join(', ')}`); 15 | 16 | // Initialize watcher 17 | chokidar.watch(watchPaths, { 18 | ignored: /(^|[\/\\])\../, // ignore dotfiles 19 | persistent: true, 20 | }) 21 | .on('change', path => { 22 | if (!path.endsWith('.php')) return; // skip non-PHP files 23 | 24 | console.log(`📝 File changed: ${path}`); 25 | 26 | // Run CakePHP command 27 | exec('bin/cake annotate all --file ' + `${path}`, (error, stdout, stderr) => { 28 | if (error) { 29 | console.error(`❌ Error executing CakePHP command: ${error.message}`); 30 | return; 31 | } 32 | if (stderr) { 33 | console.error(`⚠️ STDERR: ${stderr}`); 34 | } 35 | console.log(`✅ Output:\n${stdout}`); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /docs/Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Basics 4 | See composer scripts for 5 | ``` 6 | composer cs-check 7 | composer cs-fix 8 | composer test-setup 9 | composer test 10 | ``` 11 | etc 12 | 13 | ## Generator 14 | 15 | ### New meta file 16 | 17 | Run the test with the `--debug` option to generate a new `TMP/.meta.php`: 18 | ``` 19 | php phpunit.phar tests/TestCase/Generator/PhpstormGeneratorTest.php --debug 20 | ``` 21 | This way you can easily copy it over into the test_files/ directory and replace the existing one. 22 | -------------------------------------------------------------------------------- /docs/img/code_completion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/code_completion.png -------------------------------------------------------------------------------- /docs/img/configure_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/configure_autocomplete.png -------------------------------------------------------------------------------- /docs/img/fields_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/fields_autocomplete.png -------------------------------------------------------------------------------- /docs/img/model_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/model_autocomplete.png -------------------------------------------------------------------------------- /docs/img/model_autocomplete_finder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/model_autocomplete_finder.png -------------------------------------------------------------------------------- /docs/img/model_autocomplete_loadmodel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/model_autocomplete_loadmodel.png -------------------------------------------------------------------------------- /docs/img/model_typehinting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/model_typehinting.png -------------------------------------------------------------------------------- /docs/img/validation_autocomplete_validator_require_presence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/img/validation_autocomplete_validator_require_presence.png -------------------------------------------------------------------------------- /docs/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dereuromark/cakephp-ide-helper/8660d61ce4ef157aec648d9b21b53814b84efb33/docs/screenshot.jpg -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | config/ 7 | src/ 8 | tests/ 9 | /tests/test_files/ 10 | /tests/test_app/ 11 | 12 | 13 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | paths: 4 | - src/ 5 | 6 | treatPhpDocTypesAsCertain: false 7 | bootstrapFiles: 8 | - tests/bootstrap.php 9 | - tests/shim.php 10 | ignoreErrors: 11 | - '#Unsafe usage of new static\(\).+#' 12 | - '#Parameter \#1 \$object of function get_class expects object, object\|string given.#' 13 | -------------------------------------------------------------------------------- /src/Annotation/AbstractAnnotation.php: -------------------------------------------------------------------------------- 1 | type = $type; 29 | $this->index = $index; 30 | } 31 | 32 | /** 33 | * @return string 34 | */ 35 | public function __toString(): string { 36 | return static::TAG . ' ' . $this->build(); 37 | } 38 | 39 | /** 40 | * @return string 41 | */ 42 | public function getType(): string { 43 | return $this->type; 44 | } 45 | 46 | /** 47 | * @return bool 48 | */ 49 | public function hasIndex(): bool { 50 | return $this->index !== null; 51 | } 52 | 53 | /** 54 | * @throws \RuntimeException 55 | * @return int 56 | */ 57 | public function getIndex(): int { 58 | $index = $this->index; 59 | if ($index === null) { 60 | throw new RuntimeException('You cannot get an non-defined index. You can check with hasIndex() before calling this method.'); 61 | } 62 | 63 | return $index; 64 | } 65 | 66 | /** 67 | * @param bool $inUse 68 | * 69 | * @return void 70 | */ 71 | public function setInUse(bool $inUse = true): void { 72 | $this->isInUse = $inUse; 73 | } 74 | 75 | /** 76 | * @return bool 77 | */ 78 | public function isInUse(): bool { 79 | return $this->isInUse; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/Annotation/AnnotationInterface.php: -------------------------------------------------------------------------------- 1 | '); 22 | if ($closingBracket) { 23 | $description = substr($type, $closingBracket + 1); 24 | $description = trim($description); 25 | $type = substr($type, 0, $closingBracket + 1); 26 | } 27 | 28 | parent::__construct($type, $index); 29 | 30 | $this->description = $description; 31 | } 32 | 33 | /** 34 | * @return string 35 | */ 36 | public function getDescription(): string { 37 | return $this->description; 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | public function build(): string { 44 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 45 | 46 | return $this->type . $description; 47 | } 48 | 49 | /** 50 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\ExtendsAnnotation $annotation 51 | * 52 | * @return bool 53 | */ 54 | public function matches(AbstractAnnotation $annotation): bool { 55 | if (!$annotation instanceof self) { 56 | return false; 57 | } 58 | 59 | // Always matches as there can only be one per docblock 60 | return true; 61 | } 62 | 63 | /** 64 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\ExtendsAnnotation $annotation 65 | * @return void 66 | */ 67 | public function replaceWith(AbstractAnnotation $annotation): void { 68 | $this->type = $annotation->getType(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/Annotation/LinkAnnotation.php: -------------------------------------------------------------------------------- 1 | description = $description; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | public function getDescription(): string { 33 | return $this->description; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function build(): string { 40 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 41 | 42 | return $this->type . $description; 43 | } 44 | 45 | /** 46 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 47 | * 48 | * @return bool 49 | */ 50 | public function matches(AbstractAnnotation $annotation): bool { 51 | if (!$annotation instanceof self) { 52 | return false; 53 | } 54 | if ($annotation->getType() !== $this->type) { 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | 61 | /** 62 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 63 | * @return void 64 | */ 65 | public function replaceWith(AbstractAnnotation $annotation): void { 66 | $this->type = $annotation->getType(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Annotation/MethodAnnotation.php: -------------------------------------------------------------------------------- 1 | method = $method; 32 | $this->description = $description; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getMethod(): string { 39 | return $this->method; 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function getDescription(): string { 46 | return $this->description; 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function build(): string { 53 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 54 | 55 | return $this->type . ' ' . $this->method . $description; 56 | } 57 | 58 | /** 59 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MethodAnnotation $annotation 60 | * 61 | * @return bool 62 | */ 63 | public function matches(AbstractAnnotation $annotation): bool { 64 | if (!$annotation instanceof self) { 65 | return false; 66 | } 67 | $methodName = substr($annotation->getMethod(), 0, strpos($annotation->getMethod(), '(') ?: 0); 68 | if ($methodName !== substr($this->method, 0, strpos($this->method, '(') ?: 0)) { 69 | return false; 70 | } 71 | 72 | return true; 73 | } 74 | 75 | /** 76 | * @param \IdeHelper\Annotation\MethodAnnotation $annotation 77 | * @return void 78 | */ 79 | public function replaceWith(AbstractAnnotation $annotation): void { 80 | $this->type = $annotation->getType(); 81 | $this->method = $annotation->getMethod(); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/Annotation/MixinAnnotation.php: -------------------------------------------------------------------------------- 1 | description = $description; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | public function getDescription(): string { 33 | return $this->description; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function build(): string { 40 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 41 | 42 | return $this->type . $description; 43 | } 44 | 45 | /** 46 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 47 | * 48 | * @return bool 49 | */ 50 | public function matches(AbstractAnnotation $annotation): bool { 51 | if (!$annotation instanceof self) { 52 | return false; 53 | } 54 | if ($annotation->getType() !== $this->type) { 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | 61 | /** 62 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 63 | * @return void 64 | */ 65 | public function replaceWith(AbstractAnnotation $annotation): void { 66 | $this->type = $annotation->getType(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Annotation/ParamAnnotation.php: -------------------------------------------------------------------------------- 1 | variable = $variable; 30 | $this->description = $description; 31 | } 32 | 33 | /** 34 | * @return string 35 | */ 36 | public function getVariable(): string { 37 | return $this->variable; 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | public function getDescription(): string { 44 | return $this->description; 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function build(): string { 51 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 52 | 53 | return $this->type . ' ' . $this->variable . $description; 54 | } 55 | 56 | /** 57 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\ParamAnnotation $annotation 58 | * 59 | * @return bool 60 | */ 61 | public function matches(AbstractAnnotation $annotation): bool { 62 | if (!$annotation instanceof self) { 63 | return false; 64 | } 65 | if ($annotation->getVariable() !== $this->variable) { 66 | return false; 67 | } 68 | 69 | return true; 70 | } 71 | 72 | /** 73 | * @param \IdeHelper\Annotation\ParamAnnotation $annotation 74 | * @return void 75 | */ 76 | public function replaceWith(AbstractAnnotation $annotation): void { 77 | $this->type = $annotation->getType(); 78 | $this->variable = $annotation->getVariable(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/Annotation/PropertyAnnotation.php: -------------------------------------------------------------------------------- 1 | property = $property; 33 | $this->description = $description; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getProperty(): string { 40 | return $this->property; 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getDescription(): string { 47 | return $this->description; 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function build(): string { 54 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 55 | 56 | return $this->type . ' ' . $this->property . $description; 57 | } 58 | 59 | /** 60 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\PropertyAnnotation $annotation 61 | * 62 | * @return bool 63 | */ 64 | public function matches(AbstractAnnotation $annotation): bool { 65 | if (!$annotation instanceof self) { 66 | return false; 67 | } 68 | if ($annotation->getProperty() !== $this->property) { 69 | return false; 70 | } 71 | 72 | return true; 73 | } 74 | 75 | /** 76 | * @param \IdeHelper\Annotation\PropertyAnnotation $annotation 77 | * @return void 78 | */ 79 | public function replaceWith(AbstractAnnotation $annotation): void { 80 | $this->type = $annotation->getType(); 81 | $this->property = $annotation->getProperty(); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/Annotation/PropertyReadAnnotation.php: -------------------------------------------------------------------------------- 1 | description = $description; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | public function getDescription(): string { 33 | return $this->description; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function build(): string { 40 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 41 | 42 | return $this->type . $description; 43 | } 44 | 45 | /** 46 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 47 | * 48 | * @return bool 49 | */ 50 | public function matches(AbstractAnnotation $annotation): bool { 51 | if (!$annotation instanceof self) { 52 | return false; 53 | } 54 | if ($annotation->getType() !== $this->type) { 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | 61 | /** 62 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 63 | * @return void 64 | */ 65 | public function replaceWith(AbstractAnnotation $annotation): void { 66 | $this->type = $annotation->getType(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Annotation/UsesAnnotation.php: -------------------------------------------------------------------------------- 1 | description = $description; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | public function getDescription(): string { 33 | return $this->description; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function build(): string { 40 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 41 | 42 | return $this->type . $description; 43 | } 44 | 45 | /** 46 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 47 | * 48 | * @return bool 49 | */ 50 | public function matches(AbstractAnnotation $annotation): bool { 51 | if (!$annotation instanceof self) { 52 | return false; 53 | } 54 | if ($annotation->getType() !== $this->type) { 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | 61 | /** 62 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\MixinAnnotation $annotation 63 | * @return void 64 | */ 65 | public function replaceWith(AbstractAnnotation $annotation): void { 66 | $this->type = $annotation->getType(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Annotation/VariableAnnotation.php: -------------------------------------------------------------------------------- 1 | variable = $variable; 31 | $this->description = $description; 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getVariable(): string { 38 | return $this->variable; 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function getDescription(): string { 45 | return $this->description; 46 | } 47 | 48 | /** 49 | * @param bool $value 50 | * 51 | * @return $this 52 | */ 53 | public function setGuessed($value) { 54 | $this->guessed = $value; 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * @return bool 61 | */ 62 | public function getGuessed() { 63 | return $this->guessed; 64 | } 65 | 66 | /** 67 | * @return string 68 | */ 69 | public function build(): string { 70 | $description = $this->description !== '' ? (' ' . $this->description) : ''; 71 | 72 | return $this->type . ' ' . $this->variable . $description; 73 | } 74 | 75 | /** 76 | * @param \IdeHelper\Annotation\AbstractAnnotation|\IdeHelper\Annotation\VariableAnnotation $annotation 77 | * 78 | * @return bool 79 | */ 80 | public function matches(AbstractAnnotation $annotation): bool { 81 | if (!$annotation instanceof self) { 82 | return false; 83 | } 84 | if ($annotation->getVariable() !== $this->variable) { 85 | return false; 86 | } 87 | 88 | return true; 89 | } 90 | 91 | /** 92 | * @param \IdeHelper\Annotation\VariableAnnotation $annotation 93 | * @return void 94 | */ 95 | public function replaceWith(AbstractAnnotation $annotation): void { 96 | $this->type = $annotation->getType(); 97 | $this->variable = $annotation->getVariable(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/Annotator/CallbackAnnotator.php: -------------------------------------------------------------------------------- 1 | invokeTasks($path, $content); 20 | 21 | return true; 22 | } 23 | 24 | /** 25 | * @param string $path 26 | * @param string $content 27 | * 28 | * @return void 29 | */ 30 | protected function invokeTasks(string $path, string $content): void { 31 | $tasks = $this->getTasks($path, $content); 32 | 33 | foreach ($tasks as $task) { 34 | if (!$task->shouldRun($path)) { 35 | continue; 36 | } 37 | 38 | $task->annotate($path); 39 | } 40 | } 41 | 42 | /** 43 | * @param string $path 44 | * @param string $content 45 | * @return array<\IdeHelper\Annotator\CallbackAnnotatorTask\CallbackAnnotatorTaskInterface> 46 | */ 47 | protected function getTasks(string $path, string $content): array { 48 | $taskCollection = new CallbackAnnotatorTaskCollection(); 49 | 50 | return $taskCollection->tasks($this->_io, $this->_config, $path, $content); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/Annotator/CallbackAnnotatorTask/CallbackAnnotatorTaskInterface.php: -------------------------------------------------------------------------------- 1 | , class-string<\IdeHelper\Annotator\CallbackAnnotatorTask\CallbackAnnotatorTaskInterface>> 14 | */ 15 | protected array $defaultTasks = [ 16 | TableCallbackAnnotatorTask::class => TableCallbackAnnotatorTask::class, 17 | VirtualFieldCallbackAnnotatorTask::class => VirtualFieldCallbackAnnotatorTask::class, 18 | ]; 19 | 20 | /** 21 | * @var array> 22 | */ 23 | protected array $tasks; 24 | 25 | /** 26 | * @param array> $tasks 27 | */ 28 | public function __construct(array $tasks = []) { 29 | $defaultTasks = $this->defaultTasks(); 30 | $tasks += $defaultTasks; 31 | 32 | foreach ($tasks as $task) { 33 | if (!$task) { 34 | continue; 35 | } 36 | 37 | $this->tasks = $tasks; 38 | } 39 | } 40 | 41 | /** 42 | * @return array> 43 | */ 44 | public function defaultTasks(): array { 45 | $tasks = (array)Configure::read('IdeHelper.callbackAnnotatorTasks') + $this->defaultTasks; 46 | 47 | foreach ($tasks as $k => $v) { 48 | if (is_numeric($k)) { 49 | $tasks[$v] = $v; 50 | unset($tasks[$k]); 51 | } 52 | } 53 | 54 | return $tasks; 55 | } 56 | 57 | /** 58 | * @param \IdeHelper\Console\Io $io 59 | * @param array $config 60 | * @param string $path 61 | * @param string $content 62 | * @return array<\IdeHelper\Annotator\CallbackAnnotatorTask\CallbackAnnotatorTaskInterface> 63 | */ 64 | public function tasks(Io $io, array $config, string $path, string $content): array { 65 | $tasks = $this->tasks; 66 | 67 | $collection = []; 68 | foreach ($tasks as $task) { 69 | /** @var \IdeHelper\Annotator\CallbackAnnotatorTask\CallbackAnnotatorTaskInterface $object */ 70 | $object = new $task($io, $config, $path, $content); 71 | $collection[] = $object; 72 | } 73 | 74 | return $collection; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/Annotator/ClassAnnotator.php: -------------------------------------------------------------------------------- 1 | invokeTasks($path, $content); 20 | 21 | return true; 22 | } 23 | 24 | /** 25 | * @param string $path 26 | * @param string $content 27 | * 28 | * @return void 29 | */ 30 | protected function invokeTasks(string $path, string $content): void { 31 | $tasks = $this->getTasks($content); 32 | 33 | foreach ($tasks as $task) { 34 | if (!$task->shouldRun($path, $content)) { 35 | continue; 36 | } 37 | 38 | $task->annotate($path); 39 | } 40 | } 41 | 42 | /** 43 | * @param string $content 44 | * @return array<\IdeHelper\Annotator\ClassAnnotatorTask\ClassAnnotatorTaskInterface> 45 | */ 46 | protected function getTasks(string $content): array { 47 | $taskCollection = new ClassAnnotatorTaskCollection(); 48 | 49 | return $taskCollection->tasks($this->_io, $this->_config, $content); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/Annotator/ClassAnnotatorTask/ClassAnnotatorTaskInterface.php: -------------------------------------------------------------------------------- 1 | content instead. 9 | * 10 | * @param string $path 11 | * @param string $content 12 | * @return bool 13 | */ 14 | public function shouldRun(string $path, string $content): bool; 15 | 16 | /** 17 | * @param string $path Path to file. 18 | * @return bool 19 | */ 20 | public function annotate(string $path): bool; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Annotator/ClassAnnotatorTask/FormClassAnnotatorTask.php: -------------------------------------------------------------------------------- 1 | content instead. 16 | * 17 | * @param string $path 18 | * @param string $content 19 | * @return bool 20 | */ 21 | public function shouldRun(string $path, string $content): bool { 22 | if (!str_contains($path, DS . 'src' . DS)) { 23 | return false; 24 | } 25 | 26 | $appNamespace = Configure::read('App.namespace') ?: 'App'; 27 | if (!preg_match('#\buse (\w+)\\\\Form\\\\(.+)Form\b#', $content, $matches)) { 28 | return false; 29 | } 30 | 31 | $varName = lcfirst($matches[2]) . 'Form'; 32 | if (!preg_match('#\$' . $varName . '->execute\(#', $content)) { 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | /** 40 | * @param string $path 41 | * @return bool 42 | */ 43 | public function annotate(string $path): bool { 44 | preg_match('#\buse (\w+)\\\\Form\\\\(.+)Form\b#', $this->content, $matches); 45 | if (empty($matches[1]) || empty($matches[2])) { 46 | return false; 47 | } 48 | 49 | $appNamespace = $matches[1]; 50 | $name = $matches[2] . 'Form'; 51 | 52 | $varName = lcfirst($name); 53 | $rows = explode(PHP_EOL, $this->content); 54 | $rowToAnnotate = null; 55 | foreach ($rows as $i => $row) { 56 | if (!preg_match('#\$' . $varName . '->execute\(#', $row)) { 57 | continue; 58 | } 59 | $rowToAnnotate = $i + 1; 60 | 61 | break; 62 | } 63 | 64 | if (!$rowToAnnotate) { 65 | return false; 66 | } 67 | 68 | $method = $appNamespace . '\\Form\\' . $name . '::_execute()'; 69 | $annotations = $this->buildUsesAnnotations([$method]); 70 | 71 | return $this->annotateInlineContent($path, $this->content, $annotations, $rowToAnnotate); 72 | } 73 | 74 | /** 75 | * @param array $classes 76 | * @return array<\IdeHelper\Annotation\AbstractAnnotation> 77 | */ 78 | protected function buildUsesAnnotations(array $classes): array { 79 | $annotations = []; 80 | 81 | foreach ($classes as $className) { 82 | $annotations[] = AnnotationFactory::createOrFail(UsesAnnotation::TAG, '\\' . $className); 83 | } 84 | 85 | return $annotations; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/Annotator/ClassAnnotatorTask/ModelAwareClassAnnotatorTask.php: -------------------------------------------------------------------------------- 1 | content instead. 15 | * 16 | * @param string $path 17 | * @param string $content 18 | * @return bool 19 | */ 20 | public function shouldRun(string $path, string $content): bool { 21 | if (!str_contains($path, DS . 'src' . DS)) { 22 | return false; 23 | } 24 | if (preg_match('#\buse ModelAwareTrait\b#', $content)) { 25 | return true; 26 | } 27 | 28 | /** @var class-string|null $className */ 29 | $className = $this->getClassName($path, $content); 30 | if (!$className) { 31 | return false; 32 | } 33 | 34 | try { 35 | return (new ReflectionClass($className))->hasMethod('fetchModel'); 36 | } catch (Throwable $exception) { 37 | return false; 38 | } 39 | } 40 | 41 | /** 42 | * @param string $path 43 | * @return bool 44 | */ 45 | public function annotate(string $path): bool { 46 | $models = $this->getUsedModels($this->content); 47 | 48 | $annotations = $this->getModelAnnotations($models, $this->content); 49 | 50 | return $this->annotateContent($path, $this->content, $annotations); 51 | } 52 | 53 | /** 54 | * @param string $content 55 | * 56 | * @return array 57 | */ 58 | protected function getUsedModels(string $content): array { 59 | preg_match_all('/\$this-\>fetchModel\(\'([a-z.]+)\'/i', $content, $matches); 60 | if (empty($matches[1])) { 61 | return []; 62 | } 63 | 64 | $models = $matches[1]; 65 | 66 | return array_unique($models); 67 | } 68 | 69 | /** 70 | * @param string $path 71 | * @param string $content 72 | * 73 | * @return string|null 74 | */ 75 | protected function getClassName(string $path, string $content): ?string { 76 | preg_match('#^namespace (.+)\b#m', $content, $matches); 77 | if (!$matches) { 78 | return null; 79 | } 80 | 81 | $className = pathinfo($path, PATHINFO_FILENAME); 82 | 83 | return $matches[1] . '\\' . $className; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/Annotator/CommandAnnotator.php: -------------------------------------------------------------------------------- 1 | getPrimaryModelClass($content); 27 | $usedModels = $this->getUsedModels($content); 28 | if ($primaryModelClass) { 29 | $usedModels[] = $primaryModelClass; 30 | } 31 | $usedModels = array_unique($usedModels); 32 | 33 | $annotations = $this->getModelAnnotations($usedModels, $content); 34 | 35 | return $this->annotateContent($path, $content, $annotations); 36 | } 37 | 38 | /** 39 | * @param string $content 40 | * 41 | * @return string|null 42 | */ 43 | protected function getPrimaryModelClass(string $content): ?string { 44 | if (!preg_match('/\bprotected \?string \$defaultTable = \'([a-z.\/]+)\'/i', $content, $matches)) { 45 | return null; 46 | } 47 | 48 | $modelName = $matches[1]; 49 | 50 | return $modelName; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/Annotator/HelperAnnotator.php: -------------------------------------------------------------------------------- 1 | getConfig(static::CONFIG_PLUGIN); 29 | 30 | /** @phpstan-var class-string|null $className */ 31 | $className = App::className(($plugin ? $plugin . '.' : '') . $name, 'View/Helper', 'Helper'); 32 | if (!$className) { 33 | return false; 34 | } 35 | 36 | if ($this->_isAbstract($className)) { 37 | return false; 38 | } 39 | 40 | try { 41 | $helper = new $className(new View()); 42 | } catch (Throwable $e) { 43 | if ($this->getConfig(static::CONFIG_VERBOSE)) { 44 | $this->_io->warn(' Skipping helper annotations: ' . $e->getMessage()); 45 | } 46 | 47 | return false; 48 | } 49 | 50 | /** @uses \Cake\View\Helper::helpers */ 51 | $helperMap = $this->invokeProperty($helper, 'helpers'); 52 | 53 | $content = file_get_contents($path); 54 | if ($content === false) { 55 | throw new RuntimeException('Cannot read file'); 56 | } 57 | 58 | $annotations = $this->getHelperAnnotations($helperMap); 59 | 60 | return $this->annotateContent($path, $content, $annotations); 61 | } 62 | 63 | /** 64 | * @param array> $helperMap 65 | * @return array<\IdeHelper\Annotation\AbstractAnnotation> 66 | */ 67 | protected function getHelperAnnotations(array $helperMap): array { 68 | if (!$helperMap) { 69 | return []; 70 | } 71 | 72 | $helperAnnotations = []; 73 | foreach ($helperMap as $helper => $config) { 74 | $className = $this->findClassName($config['className'] ?? $helper, !$this->getConfig(static::CONFIG_PLUGIN)); 75 | if (!$className) { 76 | continue; 77 | } 78 | 79 | $helperAnnotations[] = AnnotationFactory::createOrFail(PropertyAnnotation::TAG, '\\' . $className, '$' . $helper); 80 | } 81 | 82 | return $helperAnnotations; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/Annotator/Traits/ComponentTrait.php: -------------------------------------------------------------------------------- 1 | config = $config; 30 | $phpcs->init(); 31 | 32 | $ruleset = new Ruleset($config); 33 | 34 | $fileObject = new File($file, $ruleset, $config); 35 | $fileObject->setContent($content ?? (string)file_get_contents($file)); 36 | $fileObject->parse(); 37 | 38 | return $fileObject; 39 | } 40 | 41 | /** 42 | * @param \PHP_CodeSniffer\Files\File $file 43 | * 44 | * @return \PHP_CodeSniffer\Fixer 45 | */ 46 | protected function getFixer(File $file): Fixer { 47 | $fixer = new Fixer(); 48 | 49 | $fixer->startFile($file); 50 | 51 | return $fixer; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/Annotator/Traits/HelperTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected function getUsedModels(string $content): array { 16 | preg_match_all('/\$this->([a-z]+)\s*=\s*\$this->fetchTable\(\'([a-z.]+)\'/i', $content, $matches); 17 | if (empty($matches[1])) { 18 | return []; 19 | } 20 | 21 | $properties = $matches[1]; 22 | $tables = $matches[2]; 23 | $models = array_combine($properties, $tables); 24 | 25 | preg_match_all('/\b(public|protected|private) \$([a-z]+)\b/i', $content, $propertyMatches); 26 | $excluded = $propertyMatches[2]; 27 | foreach ($excluded as $property) { 28 | if (isset($models[$property])) { 29 | unset($models[$property]); 30 | } 31 | } 32 | 33 | return $models; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/CodeCompletion/CodeCompletionGenerator.php: -------------------------------------------------------------------------------- 1 | taskCollection = $taskCollection; 16 | } 17 | 18 | /** 19 | * @return array 20 | */ 21 | public function generate(): array { 22 | $map = $this->taskCollection->getMap(); 23 | 24 | foreach ($map as $namespace => $array) { 25 | $content = $this->buildContent($array); 26 | 27 | $template = <<path(); 38 | $filename = $path . 'CodeCompletion' . $this->type($namespace) . '.php'; 39 | 40 | if (!file_exists($filename) || md5_file($filename) !== md5($template)) { 41 | file_put_contents($filename, $template); 42 | } 43 | } 44 | 45 | return array_keys($map); 46 | } 47 | 48 | /** 49 | * @param array $array 50 | * 51 | * @return string 52 | */ 53 | protected function buildContent(array $array): string { 54 | return implode('', $array); 55 | } 56 | 57 | /** 58 | * @param string $namespace 59 | * 60 | * @return string 61 | */ 62 | protected function type(string $namespace): string { 63 | return (string)preg_replace('/[^\da-z]/i', '', $namespace); 64 | } 65 | 66 | /** 67 | * @return string 68 | */ 69 | protected function path(): string { 70 | $path = Configure::read('IdeHelper.codeCompletionPath') ?: TMP; 71 | if (!is_dir($path)) { 72 | mkdir($path, 0770, true); 73 | } 74 | 75 | return $path; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/CodeCompletion/Task/ControllerEventsTask.php: -------------------------------------------------------------------------------- 1 | events($returnType ?? false); 29 | $componentEvents = $this->events($returnType ?? true); 30 | 31 | return <<getOption('plugin') && !$args->getOption('filter')) { 38 | $types[] = ViewCommand::class; 39 | } 40 | 41 | if ($args->getOption('remove')) { 42 | $io->verbose('Skipping "classes" and "callbacks" annotations, they do not support removing.'); 43 | } else { 44 | $types[] = ClassesCommand::class; 45 | $types[] = CallbacksCommand::class; 46 | } 47 | 48 | if (!$args->getOption('interactive')) { 49 | $this->interactive = false; 50 | } 51 | 52 | $changes = false; 53 | foreach ($types as $key => $type) { 54 | if ($key !== 0) { 55 | $io->out(''); 56 | } 57 | $shortName = App::shortName($type, 'Command', 'Command'); 58 | $shortName = str_replace('IdeHelper.Annotate/', '', $shortName); 59 | if (!$this->interactive) { 60 | $io->out('[' . $shortName . ']'); 61 | } else { 62 | $in = $io->askChoice($shortName . '?', ['y', 'n', 'a'], 'y'); 63 | if ($in === 'a') { 64 | $this->abort(); 65 | } 66 | if ($in !== 'y') { 67 | continue; 68 | } 69 | } 70 | 71 | $commandInstance = new $type(); 72 | $commandInstance->execute($args, $io); 73 | 74 | if ($this->_annotatorMadeChanges()) { 75 | $changes = true; 76 | } 77 | } 78 | 79 | if ($args->getOption('ci') && $changes) { 80 | return static::CODE_CHANGES; 81 | } 82 | 83 | return static::CODE_SUCCESS; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/Command/Annotate/CommandsCommand.php: -------------------------------------------------------------------------------- 1 | getPaths('Command'); 28 | 29 | foreach ($paths as $plugin => $pluginPaths) { 30 | $this->setPlugin($plugin); 31 | foreach ($pluginPaths as $path) { 32 | $this->_commands($path); 33 | } 34 | } 35 | 36 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 37 | return static::CODE_CHANGES; 38 | } 39 | 40 | return static::CODE_SUCCESS; 41 | } 42 | 43 | /** 44 | * @param string $folder 45 | * @return void 46 | */ 47 | protected function _commands(string $folder) { 48 | $this->io->out(str_replace(ROOT, '', $folder), 1, ConsoleIo::VERBOSE); 49 | 50 | $folderContent = glob($folder . '*') ?: []; 51 | foreach ($folderContent as $path) { 52 | if (is_dir($path)) { 53 | continue; 54 | } 55 | $name = pathinfo($path, PATHINFO_FILENAME); 56 | if ($this->_shouldSkip($name, $path)) { 57 | continue; 58 | } 59 | 60 | $this->io->out('-> ' . $name, 1, ConsoleIo::VERBOSE); 61 | $annotator = $this->getAnnotator(CommandAnnotator::class); 62 | $annotator->annotate($path); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/Annotate/ComponentsCommand.php: -------------------------------------------------------------------------------- 1 | getPaths('Controller/Component'); 28 | foreach ($paths as $plugin => $pluginPaths) { 29 | $this->setPlugin($plugin); 30 | foreach ($pluginPaths as $path) { 31 | $this->_components($path); 32 | } 33 | } 34 | 35 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 36 | return static::CODE_CHANGES; 37 | } 38 | 39 | return static::CODE_SUCCESS; 40 | } 41 | 42 | /** 43 | * @param string $folder 44 | * @return void 45 | */ 46 | protected function _components(string $folder) { 47 | $this->io->out(str_replace(ROOT, '', $folder), 1, ConsoleIo::VERBOSE); 48 | 49 | $folderContent = glob($folder . '*') ?: []; 50 | foreach ($folderContent as $path) { 51 | if (is_dir($path)) { 52 | $this->_components($path); 53 | } else { 54 | $name = pathinfo($path, PATHINFO_FILENAME); 55 | if ($this->_shouldSkip($name, $path)) { 56 | continue; 57 | } 58 | 59 | $this->io->out('-> ' . $name, 1, ConsoleIo::VERBOSE); 60 | $annotator = $this->getAnnotator(ComponentAnnotator::class); 61 | $annotator->annotate($path); 62 | } 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/Annotate/ControllersCommand.php: -------------------------------------------------------------------------------- 1 | getPaths('Controller'); 29 | 30 | foreach ($paths as $plugin => $pluginPaths) { 31 | $this->setPlugin($plugin); 32 | foreach ($pluginPaths as $path) { 33 | $this->_controllers($path); 34 | } 35 | } 36 | 37 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 38 | return static::CODE_CHANGES; 39 | } 40 | 41 | return static::CODE_SUCCESS; 42 | } 43 | 44 | /** 45 | * @param string $folder 46 | * @return void 47 | */ 48 | protected function _controllers(string $folder) { 49 | $this->io->out(str_replace(ROOT, '', $folder), 1, ConsoleIo::VERBOSE); 50 | 51 | $folderContent = glob($folder . '*') ?: []; 52 | foreach ($folderContent as $path) { 53 | 54 | if (is_dir($path)) { 55 | $subFolder = pathinfo($path, PATHINFO_BASENAME); 56 | if ($subFolder === 'Component') { 57 | continue; 58 | } 59 | 60 | $prefixes = (array)Configure::read('IdeHelper.prefixes') ?: null; 61 | 62 | if ($prefixes !== null && !in_array($subFolder, $prefixes, true)) { 63 | continue; 64 | } 65 | 66 | $this->_controllers($folder . $subFolder . DS); 67 | } else { 68 | $name = pathinfo($path, PATHINFO_FILENAME); 69 | if ($this->_shouldSkip($name, $path)) { 70 | continue; 71 | } 72 | 73 | $this->io->out('-> ' . $name, 1, ConsoleIo::VERBOSE); 74 | 75 | $annotator = $this->getAnnotator(ControllerAnnotator::class); 76 | $annotator->annotate($path); 77 | } 78 | 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/Command/Annotate/HelpersCommand.php: -------------------------------------------------------------------------------- 1 | getPaths('View/Helper'); 28 | foreach ($paths as $plugin => $pluginPaths) { 29 | $this->setPlugin($plugin); 30 | foreach ($pluginPaths as $path) { 31 | $this->_helpers($path); 32 | } 33 | } 34 | 35 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 36 | return static::CODE_CHANGES; 37 | } 38 | 39 | return static::CODE_SUCCESS; 40 | } 41 | 42 | /** 43 | * @param string $folder 44 | * @return void 45 | */ 46 | protected function _helpers($folder) { 47 | $this->io->out(str_replace(ROOT, '', $folder), 1, ConsoleIo::VERBOSE); 48 | 49 | $folderContent = glob($folder . '*') ?: []; 50 | foreach ($folderContent as $path) { 51 | if (is_dir($path)) { 52 | $this->_helpers($path); 53 | } else { 54 | $name = pathinfo($path, PATHINFO_FILENAME); 55 | if ($this->_shouldSkip($name, $path)) { 56 | continue; 57 | } 58 | 59 | $this->io->out('-> ' . $name, 1, ConsoleIo::VERBOSE); 60 | $annotator = $this->getAnnotator(HelperAnnotator::class); 61 | $annotator->annotate($path); 62 | } 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/Annotate/ModelsCommand.php: -------------------------------------------------------------------------------- 1 | getPaths('Model/Table'); 28 | foreach ($paths as $plugin => $pluginPaths) { 29 | foreach ($pluginPaths as $path) { 30 | $this->setPlugin($plugin); 31 | $this->_models($path); 32 | } 33 | } 34 | 35 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 36 | return static::CODE_CHANGES; 37 | } 38 | 39 | return static::CODE_SUCCESS; 40 | } 41 | 42 | /** 43 | * @param string $folder 44 | * @return void 45 | */ 46 | protected function _models(string $folder) { 47 | $this->io->out(str_replace(ROOT, '', $folder), 1, ConsoleIo::VERBOSE); 48 | 49 | $folderContent = glob($folder . '*') ?: []; 50 | foreach ($folderContent as $path) { 51 | if (!is_file($path)) { 52 | continue; 53 | } 54 | $name = pathinfo($path, PATHINFO_FILENAME); 55 | if ($this->_shouldSkip($name, $path)) { 56 | continue; 57 | } 58 | 59 | $this->io->out('-> ' . $name, 1, ConsoleIo::VERBOSE); 60 | 61 | $annotator = $this->getAnnotator(ModelAnnotator::class); 62 | $annotator->annotate($path); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/Annotate/ViewCommand.php: -------------------------------------------------------------------------------- 1 | getOption('plugin') || $args->getOption('filter')) { 29 | $io->err('Plugin or filter option not supported for this command'); 30 | $this->abort(); 31 | } 32 | 33 | $className = App::className('App', 'View', 'View'); 34 | $file = APP . 'View' . DS . 'AppView.php'; 35 | if (!$className || !file_exists($file)) { 36 | $io->warning('You need to create `AppView.php` first in `' . APP_DIR . DS . 'View' . DS . '`.'); 37 | 38 | return static::CODE_SUCCESS; 39 | } 40 | 41 | $folder = pathinfo($file, PATHINFO_DIRNAME); 42 | $io->out(str_replace(ROOT, '', $folder)); 43 | $io->out(' -> ' . pathinfo($file, PATHINFO_BASENAME)); 44 | 45 | $annotator = $this->getAnnotator(ViewAnnotator::class); 46 | $annotator->annotate($file); 47 | 48 | if ($args->getOption('ci') && $this->_annotatorMadeChanges()) { 49 | return static::CODE_CHANGES; 50 | } 51 | 52 | return static::CODE_SUCCESS; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/Command/GenerateCodeCompletionCommand.php: -------------------------------------------------------------------------------- 1 | getGenerator(); 30 | 31 | if ($args->getOption('dry-run')) { 32 | return static::CODE_SUCCESS; 33 | } 34 | 35 | $types = $codeCompletionGenerator->generate(); 36 | 37 | $io->out('CodeCompletion files generated: ' . implode(', ', $types)); 38 | 39 | return static::CODE_SUCCESS; 40 | } 41 | 42 | /** 43 | * @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined 44 | * 45 | * @return \Cake\Console\ConsoleOptionParser The built parser. 46 | */ 47 | protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { 48 | $parser = parent::buildOptionParser($parser); 49 | $options = [ 50 | 'dry-run' => [ 51 | 'short' => 'd', 52 | 'help' => 'Dry run the generation. This will not actually generate any files.', 53 | 'boolean' => true, 54 | ], 55 | ]; 56 | 57 | return $parser 58 | ->setDescription(static::getDescription()) 59 | ->addOptions($options); 60 | } 61 | 62 | /** 63 | * @return \IdeHelper\CodeCompletion\CodeCompletionGenerator 64 | */ 65 | protected function getGenerator(): CodeCompletionGenerator { 66 | $taskCollection = new TaskCollection(); 67 | 68 | return new CodeCompletionGenerator($taskCollection); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/Generator/Directive/BaseDirective.php: -------------------------------------------------------------------------------- 1 | toArray() 11 | */ 12 | abstract class BaseDirective { 13 | 14 | /** 15 | * Key for sorting inside collection. 16 | * 17 | * @return string 18 | */ 19 | abstract public function key(); 20 | 21 | /** 22 | * Final PHP pseudo code. 23 | * 24 | * @return string 25 | */ 26 | abstract public function build(); 27 | 28 | /** 29 | * @param array $array 30 | * @param int $indentation 31 | * 32 | * @return string 33 | */ 34 | protected function buildList(array $array, int $indentation = 2): string { 35 | $result = []; 36 | foreach ($array as $value) { 37 | if ($value instanceof ValueObjectInterface) { 38 | $element = (string)$value; 39 | } else { 40 | $element = $value; 41 | } 42 | $result[] = str_repeat("\t", $indentation) . $element; 43 | } 44 | 45 | $string = implode(',' . PHP_EOL, $result); 46 | if ($string) { 47 | $string .= ','; 48 | } 49 | 50 | return $string; 51 | } 52 | 53 | /** 54 | * @param array $array 55 | * @param int $indentation 56 | * 57 | * @return string 58 | */ 59 | protected function buildKeyValueMap(array $array, int $indentation = 3): string { 60 | $result = []; 61 | foreach ($array as $alias => $value) { 62 | if ($value instanceof KeyValue) { 63 | $key = $value->key(); 64 | $value = $value->value(); 65 | } else { 66 | $key = "'" . str_replace("'", "\'", $alias) . "'"; 67 | } 68 | $result[] = str_repeat("\t", $indentation) . $key . ' => ' . $value . ','; 69 | } 70 | 71 | return implode(PHP_EOL, $result); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Generator/Directive/ExitPoint.php: -------------------------------------------------------------------------------- 1 | method = $method; 30 | } 31 | 32 | /** 33 | * Key for sorting inside collection. 34 | * 35 | * @return string 36 | */ 37 | public function key() { 38 | return $this->method . '@' . static::NAME; 39 | } 40 | 41 | /** 42 | * @return array 43 | */ 44 | public function toArray() { 45 | return [ 46 | 'method' => $this->method, 47 | ]; 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function build() { 54 | $method = $this->method; 55 | 56 | $result = << 42 | */ 43 | protected array $list; 44 | 45 | /** 46 | * @param string $method 47 | * @param int $position Position, 0-based. 48 | * @param array $list 49 | */ 50 | public function __construct($method, $position, array $list) { 51 | $this->method = $method; 52 | $this->position = $position; 53 | $this->list = $list; 54 | } 55 | 56 | /** 57 | * Key for sorting inside collection. 58 | * 59 | * @return string 60 | */ 61 | public function key() { 62 | return $this->method . '@' . $this->position . '@' . static::NAME; 63 | } 64 | 65 | /** 66 | * @return array 67 | */ 68 | public function toArray() { 69 | return [ 70 | 'method' => $this->method, 71 | 'position' => $this->position, 72 | 'list' => $this->list, 73 | ]; 74 | } 75 | 76 | /** 77 | * @return string 78 | */ 79 | public function build() { 80 | $method = $this->method; 81 | $position = $this->position; 82 | 83 | $list = $this->buildList($this->list); 84 | $result = << 36 | */ 37 | protected array $list; 38 | 39 | /** 40 | * @param string $method 41 | * @param array $list 42 | */ 43 | public function __construct($method, array $list) { 44 | $this->method = $method; 45 | $this->list = $list; 46 | } 47 | 48 | /** 49 | * Key for sorting inside collection. 50 | * 51 | * @return string 52 | */ 53 | public function key() { 54 | return $this->method . '@' . static::NAME; 55 | } 56 | 57 | /** 58 | * @return array 59 | */ 60 | public function toArray() { 61 | return [ 62 | 'method' => $this->method, 63 | 'list' => $this->list, 64 | ]; 65 | } 66 | 67 | /** 68 | * @return string 69 | */ 70 | public function build() { 71 | $method = $this->method; 72 | $list = $this->buildList($this->list); 73 | 74 | $result = << \MyClass::class, 14 | * '' => '@|\Iterator', 15 | * ]) 16 | * ); 17 | * 18 | * @see https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html#override 19 | */ 20 | class Override extends BaseDirective { 21 | 22 | /** 23 | * @var string 24 | */ 25 | public const NAME = 'override'; 26 | 27 | protected string $method; 28 | 29 | /** 30 | * @var array 31 | */ 32 | protected array $map; 33 | 34 | /** 35 | * @param string $method 36 | * @param array $map 37 | */ 38 | public function __construct($method, array $map) { 39 | $this->method = $method; 40 | $this->map = $map; 41 | } 42 | 43 | /** 44 | * @return array 45 | */ 46 | public function toArray() { 47 | return [ 48 | 'method' => $this->method, 49 | 'map' => $this->map, 50 | ]; 51 | } 52 | 53 | /** 54 | * Key for sorting inside collection. 55 | * 56 | * @return string 57 | */ 58 | public function key() { 59 | return $this->method . '@' . static::NAME; 60 | } 61 | 62 | /** 63 | * @return string 64 | */ 65 | public function build() { 66 | $method = $this->method; 67 | $mapDefinitions = $this->buildKeyValueMap($this->map); 68 | 69 | $result = << 31 | */ 32 | protected array $list; 33 | 34 | /** 35 | * @param string $set 36 | * @param array $list 37 | */ 38 | public function __construct($set, array $list) { 39 | $this->set = $set; 40 | $this->list = $list; 41 | } 42 | 43 | /** 44 | * Key for sorting inside collection. 45 | * 46 | * @return string 47 | */ 48 | public function key() { 49 | return $this->set . '@' . static::NAME; 50 | } 51 | 52 | /** 53 | * @return array 54 | */ 55 | public function toArray() { 56 | return [ 57 | 'set' => $this->set, 58 | 'list' => $this->list, 59 | ]; 60 | } 61 | 62 | /** 63 | * @return string 64 | */ 65 | public function build() { 66 | $set = "'" . $this->set . "'"; 67 | $list = $this->buildList($this->list); 68 | 69 | $result = <<set . '\')'; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/Generator/GeneratorInterface.php: -------------------------------------------------------------------------------- 1 | taskCollection = $taskCollection; 20 | $this->io = $io; 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public function generate(): string { 27 | $map = $this->taskCollection->getMap(); 28 | 29 | $this->outputSetInfo($map); 30 | 31 | return $this->build($map); 32 | } 33 | 34 | /** 35 | * @param array<\IdeHelper\Generator\Directive\BaseDirective> $map 36 | * 37 | * @return string 38 | */ 39 | protected function build(array $map): string { 40 | $overrides = []; 41 | foreach ($map as $directive) { 42 | $overrides[] = $directive->build(); 43 | } 44 | $overrides = implode(PHP_EOL . PHP_EOL, $overrides); 45 | 46 | $template = << $map 62 | * 63 | * @return void 64 | */ 65 | protected function outputSetInfo(array $map): void { 66 | if (!$this->io) { 67 | return; 68 | } 69 | 70 | $sets = []; 71 | foreach ($map as $directive) { 72 | if ($directive instanceof RegisterArgumentsSet) { 73 | $sets[] = $directive->toArray()['set']; 74 | } 75 | } 76 | 77 | $this->io->verbose('The following sets are available for re-use:'); 78 | foreach ($sets as $set) { 79 | $this->io->verbose('- ' . $set); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/Generator/Task/CacheTask.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | protected array $aliases = [ 23 | '\\' . self::CLASS_CACHE . '::clear()' => 0, 24 | '\\' . self::CLASS_CACHE . '::read()' => 1, 25 | '\\' . self::CLASS_CACHE . '::readMany()' => 1, 26 | '\\' . self::CLASS_CACHE . '::delete()' => 1, 27 | '\\' . self::CLASS_CACHE . '::deleteMany()' => 1, 28 | '\\' . self::CLASS_CACHE . '::clearGroup()' => 1, 29 | '\\' . self::CLASS_CACHE . '::add()' => 2, 30 | '\\' . self::CLASS_CACHE . '::write()' => 2, 31 | '\\' . self::CLASS_CACHE . '::increment()' => 2, 32 | '\\' . self::CLASS_CACHE . '::decrement()' => 2, 33 | '\\' . self::CLASS_CACHE . '::remember()' => 2, 34 | ]; 35 | 36 | /** 37 | * @return array 38 | */ 39 | public function collect(): array { 40 | $result = []; 41 | 42 | $list = $this->collectCacheEngines(); 43 | $registerArgumentsSet = new RegisterArgumentsSet(static::SET_CACHE_ENGINES, $list); 44 | $result[$registerArgumentsSet->key()] = $registerArgumentsSet; 45 | 46 | foreach ($this->aliases as $alias => $position) { 47 | $directive = new ExpectedArguments($alias, $position, [$registerArgumentsSet]); 48 | $result[$directive->key()] = $directive; 49 | } 50 | 51 | return $result; 52 | } 53 | 54 | /** 55 | * @return array<\IdeHelper\ValueObject\StringName> 56 | */ 57 | protected function collectCacheEngines(): array { 58 | $cacheEngines = Cache::configured(); 59 | 60 | $result = []; 61 | foreach ($cacheEngines as $cacheEngine) { 62 | $result[$cacheEngine] = StringName::create($cacheEngine); 63 | } 64 | 65 | ksort($result); 66 | 67 | return $result; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/Generator/Task/ConnectionTask.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | public function collect(): array { 20 | $result = []; 21 | 22 | $keys = $this->connectionKeys(); 23 | 24 | ksort($keys); 25 | 26 | $directive = new ExpectedArguments(static::METHOD_GET, 0, $keys); 27 | $result[$directive->key()] = $directive; 28 | 29 | return $result; 30 | } 31 | 32 | /** 33 | * @return array<\IdeHelper\ValueObject\StringName> 34 | */ 35 | protected function connectionKeys(): array { 36 | $configured = ConnectionManager::configured(); 37 | 38 | $list = []; 39 | foreach ($configured as $key) { 40 | $list[$key] = StringName::create($key); 41 | } 42 | 43 | return $list; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Generator/Task/ConsoleTask.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | public function collect(): array { 19 | $result = []; 20 | 21 | $directive = new ExitPoint(static::METHOD_ABORT); 22 | $result[$directive->key()] = $directive; 23 | 24 | return $result; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/Generator/Task/DatabaseTypeTask.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function collect(): array { 23 | $result = []; 24 | 25 | $types = $this->getTypes(); 26 | 27 | $map = []; 28 | foreach ($types as $type => $className) { 29 | $map[$type] = ClassName::create($className); 30 | } 31 | ksort($map); 32 | 33 | $method = '\\' . static::CLASS_TYPE . '::build(0)'; 34 | $directive = new Override($method, $map); 35 | $result[$directive->key()] = $directive; 36 | 37 | $list = []; 38 | foreach ($types as $type => $className) { 39 | $list[$type] = StringName::create($type); 40 | } 41 | ksort($list); 42 | 43 | $method = '\\' . static::CLASS_TYPE . '::map()'; 44 | $directive = new ExpectedArguments($method, 0, $list); 45 | $result[$directive->key()] = $directive; 46 | 47 | return $result; 48 | } 49 | 50 | /** 51 | * @return array 52 | */ 53 | protected function getTypes(): array { 54 | $types = []; 55 | 56 | try { 57 | $allTypes = TypeFactory::buildAll(); 58 | } catch (Throwable $exception) { 59 | return $types; 60 | } 61 | 62 | foreach ($allTypes as $key => $type) { 63 | if (str_starts_with($key, 'enum-')) { 64 | continue; 65 | } 66 | 67 | $types[$key] = get_class($type); 68 | } 69 | 70 | ksort($types); 71 | 72 | return $types; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/Generator/Task/ElementTask.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function collect(): array { 23 | $result = []; 24 | 25 | $elements = $this->collectElements(); 26 | $list = []; 27 | foreach ($elements as $element) { 28 | $list[$element] = StringName::create($element); 29 | } 30 | 31 | ksort($list); 32 | 33 | $method = '\\' . static::CLASS_VIEW . '::element()'; 34 | $directive = new ExpectedArguments($method, 0, $list); 35 | $result[$directive->key()] = $directive; 36 | 37 | return $result; 38 | } 39 | 40 | /** 41 | * @return array 42 | */ 43 | protected function collectElements(): array { 44 | $paths = App::path('templates'); 45 | 46 | $result = []; 47 | $result = $this->addElements($result, $paths); 48 | 49 | $plugins = Plugin::all(); 50 | foreach ($plugins as $plugin) { 51 | $paths = App::path('templates', $plugin); 52 | $result = $this->addElements($result, $paths, $plugin); 53 | } 54 | 55 | sort($result); 56 | 57 | return $result; 58 | } 59 | 60 | /** 61 | * @param array $result 62 | * @param array $paths 63 | * @param string|null $plugin 64 | * 65 | * @return array 66 | */ 67 | protected function addElements(array $result, array $paths, ?string $plugin = null): array { 68 | foreach ($paths as $path) { 69 | $path .= 'element' . DS; 70 | if (!is_dir($path)) { 71 | continue; 72 | } 73 | 74 | $Directory = new RecursiveDirectoryIterator($path); 75 | $Iterator = new RecursiveIteratorIterator($Directory); 76 | $Regex = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH); 77 | 78 | foreach ($Regex as $file) { 79 | $name = str_replace($path, '', $file[0]); 80 | $name = substr($name, 0, -4); 81 | $name = str_replace(DS, '/', $name); 82 | if ($plugin) { 83 | $name = $plugin . '.' . $name; 84 | } 85 | $result[] = $name; 86 | } 87 | } 88 | 89 | return $result; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Generator/Task/EnvTask.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected static array $keys = [ 21 | 'HTTP_HOST', 22 | 'HTTPS', 23 | 'REMOTE_ADDR', 24 | 'REMOTE_PORT', 25 | 'DOCUMENT_ROOT', 26 | 'DOCUMENT_URI', 27 | 'PHP_SELF', 28 | 'CGI_MODE', 29 | 'SCRIPT_NAME', 30 | 'HTTP_ACCEPT_LANGUAGE', 31 | 'HTTP_ACCEPT_ENCODING', 32 | 'HTTP_ACCEPT', 33 | 'HTTP_COOKIE', 34 | 'HTTP_USER_AGENT', 35 | 'HTTP_CONNECTION', 36 | 'HOME', 37 | 'REDIRECT_STATUS', 38 | 'SERVER_NAME', 39 | 'SERVER_PORT', 40 | 'SERVER_PROTOCOL', 41 | 'GATEWAY_INTERFACE', 42 | 'REQUEST_SCHEME', 43 | 'REQUEST_URI', 44 | 'REQUEST_METHOD', 45 | 'CONTENT_LENGTH', 46 | 'CONTENT_TYPE', 47 | 'QUERY_STRING', 48 | 'REQUEST_TIME', 49 | 'SCRIPT_FILENAME', 50 | ]; 51 | 52 | /** 53 | * @return array 54 | */ 55 | public function collect(): array { 56 | $result = []; 57 | 58 | $keys = $this->envKeys(); 59 | 60 | ksort($keys); 61 | 62 | $method = static::METHOD_ENV; 63 | $directive = new ExpectedArguments($method, 0, $keys); 64 | $result[$directive->key()] = $directive; 65 | 66 | return $result; 67 | } 68 | 69 | /** 70 | * @return array<\IdeHelper\ValueObject\StringName> 71 | */ 72 | protected function envKeys(): array { 73 | $keys = array_keys($_SERVER); 74 | $keys = array_merge($keys, static::$keys); 75 | $keys = array_unique($keys); 76 | 77 | $list = []; 78 | 79 | foreach ($keys as $key) { 80 | if (str_starts_with($key, '_')) { 81 | continue; 82 | } 83 | 84 | $list[$key] = StringName::create($key); 85 | } 86 | 87 | return $list; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/Generator/Task/FormHelperTask.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | public function collect(): array { 21 | $result = []; 22 | 23 | $list = $this->collectFieldNames(); 24 | 25 | ksort($list); 26 | 27 | $method = '\\' . static::CLASS_FORM_HELPER . '::control()'; 28 | $directive = new ExpectedArguments($method, 0, $list); 29 | $result[$directive->key()] = $directive; 30 | 31 | return $result; 32 | } 33 | 34 | /** 35 | * @return array 36 | */ 37 | protected function collectFieldNames(): array { 38 | $models = $this->collectModels(); 39 | 40 | $allFields = []; 41 | foreach ($models as $model => $className) { 42 | /** @phpstan-var class-string|null $tableClass */ 43 | $tableClass = App::className($model, 'Model/Table', 'Table'); 44 | if (!$tableClass) { 45 | continue; 46 | } 47 | 48 | $tableReflection = new ReflectionClass($tableClass); 49 | if (!$tableReflection->isInstantiable()) { 50 | continue; 51 | } 52 | 53 | try { 54 | $modelObject = TableRegistry::getTableLocator()->get($model); 55 | $fields = $modelObject->getSchema()->columns(); 56 | 57 | } catch (Throwable $exception) { 58 | continue; 59 | } 60 | 61 | $allFields = array_merge($allFields, $fields); 62 | } 63 | 64 | $allFields = array_unique($allFields); 65 | 66 | $list = []; 67 | foreach ($allFields as $field) { 68 | $list[$field] = StringName::create($field); 69 | } 70 | 71 | return $list; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Generator/Task/LayoutTask.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | public function collect(): array { 22 | $result = []; 23 | 24 | $layouts = $this->collectLayouts(); 25 | $list = []; 26 | foreach ($layouts as $layout) { 27 | $list[$layout] = StringName::create($layout); 28 | } 29 | 30 | ksort($list); 31 | 32 | $method = '\\' . static::CLASS_VIEW_BUILDER . '::setLayout()'; 33 | $directive = new ExpectedArguments($method, 0, $list); 34 | $result[$directive->key()] = $directive; 35 | 36 | return $result; 37 | } 38 | 39 | /** 40 | * @return array 41 | */ 42 | protected function collectLayouts(): array { 43 | $paths = App::path('templates'); 44 | 45 | $result = []; 46 | $result = $this->addLayouts($result, $paths); 47 | 48 | $plugins = Plugin::all(); 49 | foreach ($plugins as $plugin) { 50 | $paths = App::path('templates', $plugin); 51 | $result = $this->addLayouts($result, $paths, $plugin); 52 | } 53 | 54 | sort($result); 55 | 56 | return $result; 57 | } 58 | 59 | /** 60 | * @param array $result 61 | * @param array $paths 62 | * @param string|null $plugin 63 | * 64 | * @return array 65 | */ 66 | protected function addLayouts(array $result, array $paths, ?string $plugin = null): array { 67 | foreach ($paths as $path) { 68 | $path .= 'layout' . DS; 69 | if (!is_dir($path)) { 70 | continue; 71 | } 72 | 73 | $directory = new DirectoryIterator($path); 74 | $regexIterator = new RegexIterator($directory, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH); 75 | 76 | foreach ($regexIterator as $file) { 77 | $name = str_replace($path, '', $file[0]); 78 | $name = substr($name, 0, -4); 79 | $name = str_replace(DS, '/', $name); 80 | if ($plugin) { 81 | $name = $plugin . '.' . $name; 82 | } 83 | $result[] = $name; 84 | } 85 | } 86 | 87 | return $result; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/Generator/Task/MailerTask.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function collect(): array { 23 | $map = []; 24 | 25 | $mailers = $this->collectMailers(); 26 | foreach ($mailers as $name => $className) { 27 | $map[$name] = ClassName::create($className); 28 | } 29 | 30 | ksort($map); 31 | 32 | $result = []; 33 | if ($map) { 34 | $directive = new Override(static::$alias, $map); 35 | $result[$directive->key()] = $directive; 36 | } 37 | 38 | return $result; 39 | } 40 | 41 | /** 42 | * @return array 43 | */ 44 | protected function collectMailers(): array { 45 | $mailers = []; 46 | 47 | $folders = AppPath::get('Mailer'); 48 | foreach ($folders as $folder) { 49 | $mailers = $this->addMailers($mailers, $folder); 50 | } 51 | 52 | $plugins = Plugin::all(); 53 | foreach ($plugins as $plugin) { 54 | $folders = AppPath::get('Mailer', $plugin); 55 | foreach ($folders as $folder) { 56 | $mailers = $this->addMailers($mailers, $folder, $plugin); 57 | } 58 | } 59 | 60 | return $mailers; 61 | } 62 | 63 | /** 64 | * @param array $components 65 | * @param string $folder 66 | * @param string|null $plugin 67 | * 68 | * @return array 69 | */ 70 | protected function addMailers(array $components, $folder, $plugin = null) { 71 | $folderContent = (new Folder($folder))->read(Folder::SORT_NAME, true); 72 | 73 | foreach ($folderContent[1] as $file) { 74 | preg_match('/^(.+)Mailer\.php$/', $file, $matches); 75 | if (!$matches) { 76 | continue; 77 | } 78 | $name = $matches[1]; 79 | if ($plugin) { 80 | $name = $plugin . '.' . $name; 81 | } 82 | 83 | $className = App::className($name, 'Mailer', 'Mailer'); 84 | if (!$className) { 85 | continue; 86 | } 87 | 88 | $components[$name] = $className; 89 | } 90 | 91 | return $components; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/Generator/Task/PluginTask.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | protected array $aliases = [ 24 | '\\' . self::INTERFACE_APPLICATION . '::addPlugin(0)', 25 | ]; 26 | 27 | /** 28 | * @return array 29 | */ 30 | public function collect(): array { 31 | $map = []; 32 | 33 | $plugins = $this->collectPlugins(); 34 | foreach ($plugins as $name) { 35 | $map[$name] = ClassName::create(static::CLASS_APPLICATION); 36 | } 37 | 38 | ksort($map); 39 | 40 | $result = []; 41 | foreach ($this->aliases as $alias) { 42 | $directive = new Override($alias, $map); 43 | $result[$directive->key()] = $directive; 44 | } 45 | 46 | return $result; 47 | } 48 | 49 | /** 50 | * Read from PluginCollection loaded config. 51 | * 52 | * @return array 53 | */ 54 | protected function collectPlugins(): array { 55 | $plugins = (array)Configure::read('plugins'); 56 | 57 | $names = array_keys($plugins); 58 | 59 | sort($names); 60 | 61 | return $names; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/Generator/Task/TableAssociationTask.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected array $aliases = [ 21 | '\\' . self::CLASS_TABLE . '::belongsTo(0)' => BelongsTo::class, 22 | '\\' . self::CLASS_TABLE . '::hasOne(0)' => HasOne::class, 23 | '\\' . self::CLASS_TABLE . '::hasMany(0)' => HasMany::class, 24 | '\\' . self::CLASS_TABLE . '::belongToMany(0)' => BelongsToMany::class, 25 | ]; 26 | 27 | /** 28 | * @return array 29 | */ 30 | public function collect(): array { 31 | $models = $this->collectModels(); 32 | 33 | $result = []; 34 | foreach ($this->aliases as $alias => $className) { 35 | $map = []; 36 | foreach ($models as $model => $modelClassName) { 37 | $map[$model] = ClassName::create($className); 38 | } 39 | 40 | ksort($map); 41 | 42 | $directive = new Override($alias, $map); 43 | $result[$directive->key()] = $directive; 44 | } 45 | 46 | return $result; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/Generator/Task/TaskInterface.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | public function collect(): array; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/Generator/Task/ValidationTask.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected static array $methods = [ 21 | 'requirePresence' => 1, 22 | 'allowEmptyFor' => 2, 23 | 'allowEmptyString' => 2, 24 | 'allowEmptyFile' => 2, 25 | 'allowEmptyArray' => 2, 26 | 'allowEmptyDate' => 2, 27 | 'allowEmptyTime' => 2, 28 | 'allowEmptyDateTime' => 2, 29 | 'notEmptyString' => 2, 30 | 'notEmptyFile' => 2, 31 | 'notEmptyArray' => 2, 32 | 'notEmptyDate' => 2, 33 | 'notEmptyTime' => 2, 34 | 'notEmptyDateTime' => 2, 35 | ]; 36 | 37 | /** 38 | * @return array 39 | */ 40 | public function collect(): array { 41 | $result = []; 42 | 43 | $list = $this->getValidatorRequirePresence(); 44 | $registerArgumentsSet = new RegisterArgumentsSet(static::SET_VALIDATION_WHEN, $list); 45 | $result[$registerArgumentsSet->key()] = $registerArgumentsSet; 46 | 47 | foreach (static::$methods as $method => $position) { 48 | $method = '\\' . Validator::class . '::' . $method . '()'; 49 | $directive = new ExpectedArguments($method, $position, [$registerArgumentsSet]); 50 | $result[$directive->key()] = $directive; 51 | } 52 | 53 | return $result; 54 | } 55 | 56 | /** 57 | * @return array<\IdeHelper\ValueObject\ValueObjectInterface> 58 | */ 59 | protected function getValidatorRequirePresence(): array { 60 | return [ 61 | StringName::create('create'), 62 | StringName::create('update'), 63 | ]; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/IdeHelperPlugin.php: -------------------------------------------------------------------------------- 1 | add('annotate models', ModelsCommand::class); 34 | $commands->add('annotate view', ViewCommand::class); 35 | $commands->add('annotate helpers', HelpersCommand::class); 36 | $commands->add('annotate components', ComponentsCommand::class); 37 | $commands->add('annotate templates', TemplatesCommand::class); 38 | $commands->add('annotate controllers', ControllersCommand::class); 39 | $commands->add('annotate commands', CommandsCommand::class); 40 | $commands->add('annotate classes', ClassesCommand::class); 41 | $commands->add('annotate callbacks', CallbacksCommand::class); 42 | $commands->add('annotate all', AllCommand::class); 43 | 44 | $commands->add('generate code_completion', GenerateCodeCompletionCommand::class); 45 | $commands->add('generate phpstorm', GeneratePhpStormMetaCommand::class); 46 | $commands->add('illuminate', IlluminateCommand::class); 47 | 48 | return $commands; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/Illuminator/Illuminator.php: -------------------------------------------------------------------------------- 1 | taskCollection = $taskCollection; 16 | } 17 | 18 | /** 19 | * @param string $path 20 | * @param string|null $filter 21 | * @return int 22 | */ 23 | public function illuminate($path, $filter) { 24 | $files = $this->getFiles($path); 25 | 26 | $count = 0; 27 | foreach ($files as $file) { 28 | $name = pathinfo($file, PATHINFO_FILENAME); 29 | if ($this->shouldSkip($name, $filter)) { 30 | continue; 31 | } 32 | 33 | if (!$this->taskCollection->run($file)) { 34 | continue; 35 | } 36 | 37 | $count++; 38 | } 39 | 40 | return $count; 41 | } 42 | 43 | /** 44 | * @param string $fileName 45 | * @param string|null $filter 46 | * 47 | * @return bool 48 | */ 49 | protected function shouldSkip($fileName, $filter) { 50 | if (!$filter) { 51 | return false; 52 | } 53 | 54 | return !preg_match('/' . preg_quote($filter, '/') . '/i', $fileName); 55 | } 56 | 57 | /** 58 | * @param string $path 59 | * @return array 60 | */ 61 | protected function getFiles($path) { 62 | $folder = new Folder($path); 63 | $result = $folder->findRecursive('.*\.php', true); 64 | 65 | return $result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/Illuminator/Task/AbstractTask.php: -------------------------------------------------------------------------------- 1 | 56 | */ 57 | protected array $_defaultConfig = [ 58 | ]; 59 | 60 | /** 61 | * @param array $config 62 | */ 63 | public function __construct(array $config) { 64 | $this->setConfig($config); 65 | 66 | $namespace = $this->getConfig(static::CONFIG_PLUGIN) ?: Configure::read('App.namespace', 'App'); 67 | $namespace = str_replace('/', '\\', $namespace); 68 | $this->setConfig(static::CONFIG_NAMESPACE, $namespace); 69 | } 70 | 71 | /** 72 | * @param string $path 73 | * @return bool 74 | */ 75 | abstract public function shouldRun(string $path): bool; 76 | 77 | /** 78 | * @param string $content 79 | * @param string $path 80 | * @return string 81 | */ 82 | abstract public function run(string $content, string $path): string; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/Utility/App.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public static function get(string $type, ?string $plugin = null): array { 17 | try { 18 | return App::classPath($type, $plugin); 19 | } catch (MissingPluginException $exception) { 20 | } 21 | 22 | return App::classPath($type, $plugin); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/Utility/CollectionClass.php: -------------------------------------------------------------------------------- 1 | |null 15 | */ 16 | protected static $appControllerActions; 17 | 18 | /** 19 | * @param string $path 20 | * 21 | * @return array 22 | */ 23 | public function parse(string $path): array { 24 | $actions = $this->parseFile($path); 25 | 26 | if (static::$appControllerActions === null) { 27 | try { 28 | $class = new ReflectionClass(AppController::class); 29 | $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); 30 | } catch (Throwable $exception) { 31 | return []; 32 | } 33 | 34 | static::$appControllerActions = []; 35 | foreach ($methods as $method) { 36 | static::$appControllerActions[] = $method->getName(); 37 | } 38 | } 39 | 40 | $actions = array_diff($actions, static::$appControllerActions); 41 | 42 | return array_values($actions); 43 | } 44 | 45 | /** 46 | * @param string $path 47 | * 48 | * @return array 49 | */ 50 | protected function parseFile($path): array { 51 | $content = file_get_contents($path); 52 | if ($content === false) { 53 | throw new RuntimeException('Cannot read file'); 54 | } 55 | 56 | preg_match_all('/public function (.+)\(/', $content, $matches); 57 | if (empty($matches[1])) { 58 | return []; 59 | } 60 | 61 | return $matches[1]; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/Utility/GenericString.php: -------------------------------------------------------------------------------- 1 | ', $value); 19 | } 20 | if (Configure::read('IdeHelper.objectAsGenerics') && $type !== null) { 21 | return sprintf($type . '<%s>', $value); 22 | } 23 | 24 | if ($type !== null && str_starts_with($type, '\\')) { 25 | $typeCheck = substr($type, 1); 26 | } else { 27 | $typeCheck = $type; 28 | } 29 | 30 | if ($typeCheck === ResultSetInterface::class) { 31 | if (Configure::read('IdeHelper.concreteEntitiesInParam')) { 32 | return sprintf($type . '<%s>', $value); 33 | } 34 | 35 | return $value . '[]|' . $type . '<' . $value . '>'; 36 | } 37 | 38 | $value .= '[]'; 39 | if ($type) { 40 | $value .= '|' . $type; 41 | } 42 | 43 | return $value; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Utility/Plugin.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | public static function all(): array { 14 | $plugins = static::loaded(); 15 | $plugins = array_combine($plugins, $plugins); 16 | 17 | $pluginMap = (array)Configure::read('IdeHelper.plugins'); 18 | foreach ($pluginMap as $plugin) { 19 | if (str_starts_with($plugin, '-')) { 20 | $plugin = substr($plugin, 1); 21 | unset($plugins[$plugin]); 22 | 23 | continue; 24 | } 25 | 26 | $plugins[$plugin] = $plugin; 27 | } 28 | 29 | return $plugins; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/Utility/PluginPath.php: -------------------------------------------------------------------------------- 1 | poFileParser = new PoFileParser(); 13 | } 14 | 15 | /** 16 | * @param string $path File path 17 | * 18 | * @return array 19 | */ 20 | public function parse(string $path): array { 21 | $result = $this->poFileParser->parse($path); 22 | $resultKeys = array_keys($result); 23 | 24 | $domainKeys = []; 25 | foreach ($resultKeys as $resultKey) { 26 | $resultKey = $this->escapeSlashes($resultKey); 27 | 28 | $domainKeys[$resultKey] = $resultKey; 29 | } 30 | 31 | return $domainKeys; 32 | } 33 | 34 | /** 35 | * @param string $key 36 | * 37 | * @return string 38 | */ 39 | protected function escapeSlashes(string $key): string { 40 | return addcslashes($key, '\''); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/ValueObject/ArgumentsSet.php: -------------------------------------------------------------------------------- 1 | value = $value; 21 | } 22 | 23 | /** 24 | * Creates itself from a string. 25 | * 26 | * @param string $value 27 | * 28 | * @return static 29 | */ 30 | public static function create(string $value) { 31 | return new static($value); 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function raw(): string { 38 | return $this->value; 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function __toString(): string { 45 | return 'argumentsSet(\'' . $this->value . '\')'; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/ValueObject/ClassName.php: -------------------------------------------------------------------------------- 1 | className = $className; 17 | } 18 | 19 | /** 20 | * Creates itself from a fully qualified class name. 21 | * 22 | * @param string $className 23 | * @return static 24 | */ 25 | public static function create(string $className) { 26 | if (str_starts_with($className, '\\')) { 27 | $className = substr($className, 1); 28 | } 29 | 30 | return new static($className); 31 | } 32 | 33 | /** 34 | * @return string 35 | */ 36 | public function raw(): string { 37 | return $this->className; 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | public function __toString(): string { 44 | return '\\' . $this->className . '::class'; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/ValueObject/KeyValue.php: -------------------------------------------------------------------------------- 1 | key = $key; 20 | $this->value = $value; 21 | } 22 | 23 | /** 24 | * Creates itself from a ValueObjectInterface key and value. 25 | * 26 | * @param \IdeHelper\ValueObject\ValueObjectInterface $key 27 | * @param \IdeHelper\ValueObject\ValueObjectInterface $value 28 | * 29 | * @return static 30 | */ 31 | public static function create(ValueObjectInterface $key, ValueObjectInterface $value) { 32 | return new static($key, $value); 33 | } 34 | 35 | /** 36 | * @return \IdeHelper\ValueObject\ValueObjectInterface 37 | */ 38 | public function key(): ValueObjectInterface { 39 | return $this->key; 40 | } 41 | 42 | /** 43 | * @return \IdeHelper\ValueObject\ValueObjectInterface 44 | */ 45 | public function value(): ValueObjectInterface { 46 | return $this->value; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/ValueObject/LiteralName.php: -------------------------------------------------------------------------------- 1 | value = $value; 17 | } 18 | 19 | /** 20 | * Creates itself from a string. 21 | * 22 | * @param string $value 23 | * 24 | * @return static 25 | */ 26 | public static function create(string $value) { 27 | return new static($value); 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public function raw(): string { 34 | return $this->value; 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function __toString(): string { 41 | return $this->raw(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/ValueObject/StringName.php: -------------------------------------------------------------------------------- 1 | value = $value; 17 | } 18 | 19 | /** 20 | * Creates itself from a string. 21 | * 22 | * @param string $value 23 | * 24 | * @return static 25 | */ 26 | public static function create(string $value) { 27 | return new static($value); 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public function raw(): string { 34 | return $this->value; 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function __toString(): string { 41 | return '\'' . $this->value . '\''; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/ValueObject/ValueObjectInterface.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 14 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 15 | 'content' => ['type' => 'text', 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 16 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], 17 | '_constraints' => [ 18 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 19 | ], 20 | '_options' => [ 21 | 'engine' => 'InnoDB', 22 | 'collation' => 'utf8_general_ci', 23 | ], 24 | ]; 25 | 26 | /** 27 | * Records 28 | */ 29 | public array $records = [ 30 | [ 31 | 'id' => 1, 32 | 'name' => 'Lorem ipsum dolor sit amet', 33 | 'content' => 'Lorem ipsum dolor sit amet', 34 | 'created' => '2016-06-23 14:59:54', 35 | ], 36 | ]; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /tests/Fixture/CarsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 15 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 16 | 'content' => ['type' => 'text', 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 17 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], 18 | 'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 19 | 'status' => ['type' => 'tinyinteger', 'length' => 2, 'null' => false, 'default' => '0'], 20 | '_constraints' => [ 21 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 22 | ], 23 | '_options' => [ 24 | 'engine' => 'InnoDB', 25 | 'collation' => 'utf8_general_ci', 26 | ], 27 | ]; 28 | 29 | /** 30 | * Records 31 | */ 32 | public array $records = [ 33 | [ 34 | 'id' => 1, 35 | 'name' => 'Lorem ipsum dolor sit amet', 36 | 'content' => 'Lorem ipsum dolor sit amet', 37 | 'created' => '2016-06-23 14:59:54', 38 | 'modified' => '2016-06-23 14:59:54', 39 | 'status' => CarStatus::NEW, 40 | ], 41 | ]; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /tests/Fixture/FoosFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 14 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 15 | 'content' => ['type' => 'text', 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 16 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], 17 | 'params' => ['type' => 'json', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 18 | '_constraints' => [ 19 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 20 | ], 21 | '_options' => [ 22 | 'engine' => 'InnoDB', 23 | 'collation' => 'utf8_general_ci', 24 | ], 25 | ]; 26 | 27 | /** 28 | * Records 29 | */ 30 | public array $records = [ 31 | [ 32 | 'id' => 1, 33 | 'name' => 'Lorem ipsum dolor sit amet', 34 | 'content' => 'Lorem ipsum dolor sit amet', 35 | 'created' => '2016-06-23 14:59:54', 36 | 'params' => '[]', 37 | ], 38 | ]; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /tests/Fixture/HousesFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 14 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 15 | '_constraints' => [ 16 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 17 | ], 18 | '_options' => [ 19 | 'engine' => 'InnoDB', 20 | 'collation' => 'utf8_general_ci', 21 | ], 22 | ]; 23 | 24 | /** 25 | * Records 26 | */ 27 | public array $records = [ 28 | [ 29 | 'id' => 1, 30 | 'name' => 'Lorem ipsum dolor sit amet', 31 | ], 32 | ]; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/Fixture/WheelsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 14 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 15 | 'content' => ['type' => 'text', 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 16 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], 17 | '_constraints' => [ 18 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 19 | ], 20 | '_options' => [ 21 | 'engine' => 'InnoDB', 22 | 'collation' => 'utf8_general_ci', 23 | ], 24 | ]; 25 | 26 | /** 27 | * Records 28 | */ 29 | public array $records = [ 30 | [ 31 | 'id' => 1, 32 | 'name' => 'Lorem ipsum dolor sit amet', 33 | 'content' => 'Lorem ipsum dolor sit amet', 34 | 'created' => '2016-06-23 14:59:54', 35 | ], 36 | ]; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /tests/Fixture/WindowsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 14 | 'name' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 15 | '_constraints' => [ 16 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 17 | ], 18 | '_options' => [ 19 | 'engine' => 'InnoDB', 20 | 'collation' => 'utf8_general_ci', 21 | ], 22 | ]; 23 | 24 | /** 25 | * Records 26 | */ 27 | public array $records = [ 28 | [ 29 | 'id' => 1, 30 | 'name' => 'Lorem ipsum dolor sit amet', 31 | ], 32 | ]; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/TestCase/Annotation/ParamAnnotationTest.php: -------------------------------------------------------------------------------- 1 | assertSame('@param \\Foo\\Model\\Table\\Bar $baz', $result); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testReplaceWith() { 25 | $replacementAnnotation = new ParamAnnotation('\\Something\\Model\\Table\\Else', '$baz'); 26 | 27 | $annotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 28 | $annotation->replaceWith($replacementAnnotation); 29 | 30 | $result = (string)$annotation; 31 | $this->assertSame('@param \\Something\\Model\\Table\\Else $baz', $result); 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public function testMatches() { 38 | $annotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 39 | $comparisonAnnotation = new ParamAnnotation('\\Something\\Else', '$baz'); 40 | $result = $annotation->matches($comparisonAnnotation); 41 | $this->assertTrue($result); 42 | 43 | $annotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 44 | $comparisonAnnotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$bbb'); 45 | $result = $annotation->matches($comparisonAnnotation); 46 | $this->assertFalse($result); 47 | 48 | $annotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 49 | $comparisonAnnotation = new MethodAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 50 | $result = $annotation->matches($comparisonAnnotation); 51 | $this->assertFalse($result); 52 | } 53 | 54 | /** 55 | * @return void 56 | */ 57 | public function testMatchesWithDescription() { 58 | $annotation = new ParamAnnotation('\\Foo\\Model\\Table\\Bar', '$baz !'); 59 | $comparisonAnnotation = new ParamAnnotation('\\Something\\Else', '$baz'); 60 | $result = $annotation->matches($comparisonAnnotation); 61 | 62 | $this->assertTrue($result); 63 | $this->assertSame('!', $annotation->getDescription()); 64 | $this->assertSame('', $comparisonAnnotation->getDescription()); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tests/TestCase/Annotation/VariableAnnotationTest.php: -------------------------------------------------------------------------------- 1 | assertSame('@var \\Foo\\Model\\Table\\Bar $baz', $result); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testReplaceWith() { 25 | $replacementAnnotation = new VariableAnnotation('\\Something\\Model\\Table\\Else', '$baz'); 26 | 27 | $annotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 28 | $annotation->replaceWith($replacementAnnotation); 29 | 30 | $result = (string)$annotation; 31 | $this->assertSame('@var \\Something\\Model\\Table\\Else $baz', $result); 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public function testMatches() { 38 | $annotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 39 | $comparisonAnnotation = new VariableAnnotation('\\Something\\Else', '$baz'); 40 | $result = $annotation->matches($comparisonAnnotation); 41 | $this->assertTrue($result); 42 | 43 | $annotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 44 | $comparisonAnnotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$bbb'); 45 | $result = $annotation->matches($comparisonAnnotation); 46 | $this->assertFalse($result); 47 | 48 | $annotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 49 | $comparisonAnnotation = new MethodAnnotation('\\Foo\\Model\\Table\\Bar', '$baz'); 50 | $result = $annotation->matches($comparisonAnnotation); 51 | $this->assertFalse($result); 52 | } 53 | 54 | /** 55 | * @return void 56 | */ 57 | public function testMatchesWithDescription() { 58 | $annotation = new VariableAnnotation('\\Foo\\Model\\Table\\Bar', '$baz !'); 59 | $comparisonAnnotation = new VariableAnnotation('\\Something\\Else', '$baz'); 60 | $result = $annotation->matches($comparisonAnnotation); 61 | 62 | $this->assertTrue($result); 63 | $this->assertSame('!', $annotation->getDescription()); 64 | $this->assertSame('', $comparisonAnnotation->getDescription()); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tests/TestCase/Annotator/CallbackAnnotatorTest.php: -------------------------------------------------------------------------------- 1 | out = new ConsoleOutput(); 28 | $this->err = new ConsoleOutput(); 29 | $consoleIo = new ConsoleIo($this->out, $this->err); 30 | $this->io = new Io($consoleIo); 31 | 32 | $file = TMP . 'CallbacksTable.php'; 33 | if (file_exists($file)) { 34 | unlink($file); 35 | } 36 | } 37 | 38 | /** 39 | * @return void 40 | */ 41 | protected function tearDown(): void { 42 | parent::tearDown(); 43 | 44 | $file = TMP . 'CallbacksTable.php'; 45 | if (file_exists($file)) { 46 | unlink($file); 47 | } 48 | } 49 | 50 | /** 51 | * @return void 52 | */ 53 | public function testAnnotate() { 54 | $annotator = $this->_getAnnotatorMock([]); 55 | 56 | $path = APP . 'Model/Table/CallbacksTable.php'; 57 | $execPath = TMP . 'CallbacksTable.php'; 58 | copy($path, $execPath); 59 | 60 | $annotator->annotate($execPath); 61 | 62 | $content = file_get_contents($execPath); 63 | if ($content === false) { 64 | throw new RuntimeException('Cannot read file'); 65 | } 66 | 67 | $testPath = TEST_FILES . 'Model/Table/CallbacksTable.php'; 68 | $expectedContent = file_get_contents($testPath); 69 | if ($expectedContent === false) { 70 | throw new RuntimeException('Cannot read file'); 71 | } 72 | $this->assertTextEquals($expectedContent, $content); 73 | 74 | $output = $this->out->output(); 75 | 76 | $this->assertTextContains(' -> 2 annotations updated.', $output); 77 | } 78 | 79 | /** 80 | * @param array $params 81 | * @return \IdeHelper\Annotator\CallbackAnnotator 82 | */ 83 | protected function _getAnnotatorMock(array $params) { 84 | $params += [ 85 | AbstractAnnotator::CONFIG_VERBOSE => true, 86 | ]; 87 | 88 | return new CallbackAnnotator($this->io, $params); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /tests/TestCase/Annotator/ClassAnnotatorTest.php: -------------------------------------------------------------------------------- 1 | out = new ConsoleOutput(); 27 | $this->err = new ConsoleOutput(); 28 | $consoleIo = new ConsoleIo($this->out, $this->err); 29 | $this->io = new Io($consoleIo); 30 | 31 | $file = TMP . 'src' . DS . 'CustomClass.php'; 32 | if (file_exists($file)) { 33 | unlink($file); 34 | rmdir(TMP . 'src' . DS); 35 | } 36 | } 37 | 38 | /** 39 | * @return void 40 | */ 41 | protected function tearDown(): void { 42 | parent::tearDown(); 43 | 44 | $file = TMP . 'src' . DS . 'CustomClass.php'; 45 | if (file_exists($file)) { 46 | unlink($file); 47 | rmdir(TMP . 'src' . DS); 48 | } 49 | } 50 | 51 | /** 52 | * @return void 53 | */ 54 | public function testAnnotate() { 55 | $annotator = $this->_getAnnotatorMock([]); 56 | 57 | $path = APP . 'Custom' . DS . 'CustomClass.php'; 58 | if (!is_dir(TMP . 'src')) { 59 | mkdir(TMP . 'src', 0770, true); 60 | } 61 | $execPath = TMP . 'src' . DS . 'CustomClass.php'; 62 | copy($path, $execPath); 63 | 64 | $annotator->annotate($execPath); 65 | 66 | $content = file_get_contents($execPath); 67 | 68 | $testPath = TEST_FILES . 'Custom' . DS . 'CustomClass.php'; 69 | $expectedContent = file_get_contents($testPath); 70 | $this->assertTextEquals($expectedContent, $content); 71 | 72 | $output = $this->out->output(); 73 | 74 | $this->assertTextContains(' -> 1 annotation added, 1 annotation removed.', $output); 75 | } 76 | 77 | /** 78 | * @param array $params 79 | * @return \IdeHelper\Annotator\ClassAnnotator 80 | */ 81 | protected function _getAnnotatorMock(array $params) { 82 | $params += [ 83 | AbstractAnnotator::CONFIG_REMOVE => true, 84 | AbstractAnnotator::CONFIG_VERBOSE => true, 85 | ]; 86 | 87 | return new ClassAnnotator($this->io, $params); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /tests/TestCase/Annotator/CommandAnnotatorTest.php: -------------------------------------------------------------------------------- 1 | out = new ConsoleOutput(); 34 | $this->err = new ConsoleOutput(); 35 | $consoleIo = new ConsoleIo($this->out, $this->err); 36 | $this->io = new Io($consoleIo); 37 | } 38 | 39 | /** 40 | * @return void 41 | */ 42 | public function testAnnotate() { 43 | $annotator = $this->_getAnnotatorMock([]); 44 | 45 | $expectedContent = str_replace("\r\n", "\n", file_get_contents(TEST_FILES . 'Command/MyCommand.php')); 46 | $callback = function($value) use ($expectedContent) { 47 | $value = str_replace(["\r\n", "\r"], "\n", $value); 48 | if ($value !== $expectedContent) { 49 | $this->_displayDiff($expectedContent, $value); 50 | } 51 | 52 | return $value === $expectedContent; 53 | }; 54 | $annotator->expects($this->once())->method('storeFile')->with($this->anything(), $this->callback($callback)); 55 | 56 | $path = APP . 'Command/MyCommand.php'; 57 | $annotator->annotate($path); 58 | 59 | $output = $this->out->output(); 60 | 61 | $this->assertTextContains(' -> 2 annotations added.', $output); 62 | } 63 | 64 | /** 65 | * @param array $params 66 | * @return \IdeHelper\Annotator\CommandAnnotator|\PHPUnit\Framework\MockObject\MockObject 67 | */ 68 | protected function _getAnnotatorMock(array $params) { 69 | $params += [ 70 | AbstractAnnotator::CONFIG_REMOVE => true, 71 | AbstractAnnotator::CONFIG_DRY_RUN => true, 72 | ]; 73 | 74 | return $this->getMockBuilder(CommandAnnotator::class)->onlyMethods(['storeFile'])->setConstructorArgs([$this->io, $params])->getMock(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /tests/TestCase/Annotator/DiffHelperTrait.php: -------------------------------------------------------------------------------- 1 | diffToArray($expected, $actual); 21 | 22 | $begin = null; 23 | $end = null; 24 | foreach ($array as $key => $row) { 25 | if ($row[1] === 0) { 26 | continue; 27 | } 28 | 29 | if ($begin === null) { 30 | $begin = $key; 31 | } 32 | $end = $key; 33 | } 34 | if ($begin === null) { 35 | return; 36 | } 37 | $firstLineOfOutput = $begin > 0 ? $begin - 1 : 0; 38 | $lastLineOfOutput = count($array) - 1 > $end ? $end + 1 : $end; 39 | 40 | $out = []; 41 | for ($i = $firstLineOfOutput; $i <= $lastLineOfOutput; $i++) { 42 | $row = $array[$i]; 43 | $char = ' '; 44 | if ($row[1] === 1) { 45 | $char = '+'; 46 | $out[] = $char . $row[0]; 47 | } elseif ($row[1] === 2) { 48 | $char = '-'; 49 | $out[] = $char . $row[0]; 50 | } else { 51 | $out[] = $char . $row[0]; 52 | } 53 | } 54 | 55 | echo PHP_EOL . '####### diff #######' . PHP_EOL . (implode(PHP_EOL, $out)) . PHP_EOL . '##### diff end #####' . PHP_EOL; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /tests/TestCase/Annotator/HelperAnnotatorTest.php: -------------------------------------------------------------------------------- 1 | out = new ConsoleOutput(); 29 | $this->err = new ConsoleOutput(); 30 | $consoleIo = new ConsoleIo($this->out, $this->err); 31 | $this->io = new Io($consoleIo); 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public function testAnnotate() { 38 | $annotator = $this->_getAnnotatorMock([]); 39 | 40 | $expectedContent = str_replace("\r\n", "\n", file_get_contents(TEST_FILES . 'View/Helper/MyHelper.php')); 41 | $callback = function($value) use ($expectedContent) { 42 | $value = str_replace(["\r\n", "\r"], "\n", $value); 43 | if ($value !== $expectedContent) { 44 | $this->_displayDiff($expectedContent, $value); 45 | } 46 | 47 | return $value === $expectedContent; 48 | }; 49 | $annotator->expects($this->once())->method('storeFile')->with($this->anything(), $this->callback($callback)); 50 | 51 | $path = APP . 'View/Helper/MyHelper.php'; 52 | $annotator->annotate($path); 53 | 54 | $output = $this->out->output(); 55 | 56 | $this->assertTextContains(' -> 3 annotations added', $output); 57 | } 58 | 59 | /** 60 | * @param array $params 61 | * @return \IdeHelper\Annotator\HelperAnnotator|\PHPUnit\Framework\MockObject\MockObject 62 | */ 63 | protected function _getAnnotatorMock(array $params) { 64 | $params += [ 65 | AbstractAnnotator::CONFIG_REMOVE => true, 66 | AbstractAnnotator::CONFIG_DRY_RUN => true, 67 | ]; 68 | 69 | return $this->getMockBuilder(HelperAnnotator::class)->onlyMethods(['storeFile'])->setConstructorArgs([$this->io, $params])->getMock(); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /tests/TestCase/CodeCompletion/Task/BehaviorTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['MyNamespace/MyPlugin', 'Shim']); 19 | $this->task = new BehaviorTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->create(); 27 | 28 | $expected = <<<'TXT' 29 | abstract class BehaviorRegistry extends \Cake\Core\ObjectRegistry { 30 | 31 | /** 32 | * MyNamespace/MyPlugin.My behavior. 33 | * 34 | * @var \MyNamespace\MyPlugin\Model\Behavior\MyBehavior 35 | */ 36 | public $My; 37 | 38 | /** 39 | * Shim.Nullable behavior. 40 | * 41 | * @var \Shim\Model\Behavior\NullableBehavior 42 | */ 43 | public $Nullable; 44 | 45 | } 46 | 47 | TXT; 48 | $this->assertTextEquals($expected, $result); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /tests/TestCase/CodeCompletion/Task/ViewEventsTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ViewEventsTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->create(); 26 | 27 | $expected = <<<'TXT' 28 | 29 | use Cake\Event\EventInterface; 30 | 31 | if (false) { 32 | class Helper { 33 | public function beforeRenderFile(EventInterface $event): void {} 34 | public function afterRenderFile(EventInterface $event): void {} 35 | public function beforeRender(EventInterface $event): void {} 36 | public function afterRender(EventInterface $event): void {} 37 | public function beforeLayout(EventInterface $event): void {} 38 | public function afterLayout(EventInterface $event): void {} 39 | } 40 | } 41 | 42 | TXT; 43 | 44 | $this->assertTextEquals($expected, $result); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase/CodeCompletion/TaskCollectionTest.php: -------------------------------------------------------------------------------- 1 | taskCollection = new TaskCollection(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testTasks() { 25 | $result = $this->taskCollection->tasks(); 26 | 27 | $this->assertNotEmpty($result); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestCase/Command/GenerateCodeCompletionCommandTest.php: -------------------------------------------------------------------------------- 1 | files as $file) { 25 | if (file_exists($file)) { 26 | unlink($file); 27 | } 28 | } 29 | $this->loadPlugins(['IdeHelper']); 30 | } 31 | 32 | /** 33 | * @return void 34 | */ 35 | protected function tearDown(): void { 36 | parent::tearDown(); 37 | 38 | foreach ($this->files as $file) { 39 | if (file_exists($file)) { 40 | unlink($file); 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * @return void 47 | */ 48 | public function testGenerate() { 49 | $this->exec('generate code_completion'); 50 | $this->assertOutputContains('CodeCompletion files generated: Cake\Controller, Cake\ORM, Cake\View'); 51 | $this->assertExitSuccess(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /tests/TestCase/Command/IlluminateCommandTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['IdeHelper']); 17 | $this->exec('illuminate -d -v'); 18 | 19 | $this->assertExitCode(2); 20 | $this->assertOutputContains('# /src/Model/Entity/Foo.php'); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Directive/ExitPointTest.php: -------------------------------------------------------------------------------- 1 | build(); 18 | $expected = <<<'TXT' 19 | exitPoint(\Cake\Console\ConsoleIo::abort()); 20 | TXT; 21 | $this->assertSame($expected, $result); 22 | $this->assertSame('\\' . ConsoleIo::class . '::abort()@exitPoint', $directive->key()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Directive/ExpectedArgumentsTest.php: -------------------------------------------------------------------------------- 1 | build(); 22 | $expected = <<<'TXT' 23 | expectedArguments( 24 | \Cake\ORM\Table::addBehavior(), 25 | 0, 26 | \Foo\Bar::class, 27 | "string", 28 | ); 29 | TXT; 30 | $this->assertSame($expected, $result); 31 | $this->assertSame('\\' . Table::class . '::addBehavior()@0@expectedArguments', $directive->key()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Directive/ExpectedReturnValuesTest.php: -------------------------------------------------------------------------------- 1 | build(); 22 | $expected = <<<'TXT' 23 | expectedReturnValues( 24 | \Cake\ORM\Table::addBehavior(), 25 | \Foo\Bar::class, 26 | "string", 27 | ); 28 | TXT; 29 | $this->assertSame($expected, $result); 30 | $this->assertSame('\\' . Table::class . '::addBehavior()@expectedReturnValues', $directive->key()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Directive/OverrideTest.php: -------------------------------------------------------------------------------- 1 | ClassName::create(Table::class), 19 | 'CounterCache' => ClassName::create(Table::class), 20 | ]; 21 | $directive = new Override('\\' . Table::class . '::addBehavior(0)', $map); 22 | 23 | $result = $directive->build(); 24 | $expected = <<<'TXT' 25 | override( 26 | \Cake\ORM\Table::addBehavior(0), 27 | map([ 28 | 'Tree' => \Cake\ORM\Table::class, 29 | 'CounterCache' => \Cake\ORM\Table::class, 30 | ]), 31 | ); 32 | TXT; 33 | $this->assertSame($expected, $result); 34 | $this->assertSame('\\' . Table::class . '::addBehavior(0)@override', $directive->key()); 35 | } 36 | 37 | /** 38 | * @return void 39 | */ 40 | public function testBuildLiteralKey() { 41 | $key = ClassName::create(Table::class); 42 | 43 | $value = ClassName::create(Table::class); 44 | $keyValue = KeyValue::create($key, $value); 45 | $map = [ 46 | '\\' . Table::class . '::class' => $keyValue, 47 | ]; 48 | $directive = new Override('\\' . Table::class . '::addBehavior(0)', $map); 49 | 50 | $result = $directive->build(); 51 | $expected = <<<'TXT' 52 | override( 53 | \Cake\ORM\Table::addBehavior(0), 54 | map([ 55 | \Cake\ORM\Table::class => \Cake\ORM\Table::class, 56 | ]), 57 | ); 58 | TXT; 59 | $this->assertSame($expected, $result); 60 | $this->assertSame('\\' . Table::class . '::addBehavior(0)@override', $directive->key()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Directive/RegisterArgumentsSetTest.php: -------------------------------------------------------------------------------- 1 | build(); 23 | $expected = <<<'TXT' 24 | registerArgumentsSet( 25 | 'foo', 26 | \Foo\Bar::class, 27 | "string", 28 | ); 29 | TXT; 30 | $this->assertSame($expected, $result); 31 | $this->assertSame('foo@registerArgumentsSet', $directive->key()); 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public function testToString() { 38 | $list = [ 39 | '\Foo\Bar::class', 40 | ]; 41 | $directive = new RegisterArgumentsSet('fooBar', $list); 42 | 43 | $result = (string)$directive; 44 | $this->assertSame('argumentsSet(\'fooBar\')', $result); 45 | } 46 | 47 | /** 48 | * @return void 49 | */ 50 | public function testSetInsideArguments() { 51 | $list = [ 52 | '\Foo\Bar::class', 53 | '"string"', 54 | ]; 55 | $argumentsSet = new RegisterArgumentsSet('fooBar', $list); 56 | 57 | $list = [ 58 | $argumentsSet, 59 | ]; 60 | $directive = new ExpectedArguments('\My\Class::someMethod()', 1, $list); 61 | 62 | $result = $directive->build(); 63 | $expected = <<<'TXT' 64 | expectedArguments( 65 | \My\Class::someMethod(), 66 | 1, 67 | argumentsSet('fooBar'), 68 | ); 69 | TXT; 70 | $this->assertSame($expected, $result); 71 | } 72 | 73 | /** 74 | * @return void 75 | */ 76 | public function testArgumentsSetInsideReturnValues() { 77 | $list = [ 78 | '\Foo\Bar::class', 79 | '"string"', 80 | ]; 81 | $argumentsSet = new RegisterArgumentsSet('fooBar', $list); 82 | 83 | $list = [ 84 | $argumentsSet, 85 | ]; 86 | $directive = new ExpectedReturnValues('\My\Class::someMethod()', $list); 87 | 88 | $result = $directive->build(); 89 | $expected = <<<'TXT' 90 | expectedReturnValues( 91 | \My\Class::someMethod(), 92 | argumentsSet('fooBar'), 93 | ); 94 | TXT; 95 | $this->assertSame($expected, $result); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/PhpstormGeneratorTest.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected array $fixtures = [ 21 | 'plugin.IdeHelper.Cars', 22 | 'plugin.IdeHelper.Wheels', 23 | ]; 24 | 25 | protected ?PhpstormGenerator $generator = null; 26 | 27 | /** 28 | * @return void 29 | */ 30 | protected function setUp(): void { 31 | parent::setUp(); 32 | $this->loadPlugins(['Awesome', 'Controllers', 'MyNamespace/MyPlugin', 'Relations', 'Shim', 'IdeHelper']); 33 | 34 | $taskCollection = new TaskCollection([ 35 | EnvTask::class => TestEnvTask::class, 36 | FixtureTask::class => TestFixtureTask::class, 37 | ]); 38 | $this->generator = new PhpstormGenerator($taskCollection); 39 | 40 | $file = TMP . '.meta.php'; 41 | if (file_exists($file)) { 42 | unlink($file); 43 | } 44 | } 45 | 46 | /** 47 | * @return void 48 | */ 49 | protected function tearDown(): void { 50 | parent::tearDown(); 51 | 52 | $file = TMP . '.meta.php'; 53 | if (file_exists($file)) { 54 | unlink($file); 55 | } 56 | } 57 | 58 | /** 59 | * @return void 60 | */ 61 | public function testCollect() { 62 | Configure::write('IdeHelper.skipDatabaseTables', ['/^(?!wheels)/']); 63 | 64 | $result = $this->generator->generate(); 65 | file_put_contents(TMP . '.meta.php', $result); 66 | 67 | $isLowest = version_compare(Configure::version(), '5.2.0', '<'); 68 | $fileName = $isLowest ? '.meta_lowest.php' : '.meta.php'; 69 | $file = Plugin::path('IdeHelper') . 'tests' . DS . 'test_files' . DS . 'meta' . DS . 'phpstorm' . DS . $fileName; 70 | 71 | // Trick to let the test file get updated: --debug is for PHPUnit 11+, --cache-result for PHPUnit 10 72 | if (!empty($_SERVER['argv']) && (in_array('--debug', $_SERVER['argv'], true) || in_array('--cache-result', $_SERVER['argv'], true))) { 73 | debug('Adding results to ' . $fileName); 74 | file_put_contents($file, $result); 75 | } 76 | 77 | $expected = file_get_contents($file); 78 | 79 | $this->assertTextEquals($expected, $result); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/BehaviorTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Shim']); 19 | $this->task = new BehaviorTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(4, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame('\Cake\ORM\Table::addBehavior()', $directive->toArray()['method']); 33 | 34 | $list = $directive->toArray()['list']; 35 | 36 | $expected = '\'Timestamp\''; 37 | $this->assertSame($expected, (string)$list['Timestamp']); 38 | 39 | $expected = '\'Shim.Nullable\''; 40 | $this->assertSame($expected, (string)$list['Shim.Nullable']); 41 | 42 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 43 | $directive = array_shift($result); 44 | $this->assertSame('\Cake\ORM\Table::removeBehavior()', $directive->toArray()['method']); 45 | 46 | $list = $directive->toArray()['list']; 47 | 48 | $expected = '\'Timestamp\''; 49 | $this->assertSame($expected, (string)$list['Timestamp']); 50 | 51 | $expected = '\'Nullable\''; 52 | $this->assertSame($expected, (string)$list['Nullable']); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/CacheTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new CacheTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(12, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 31 | $directive = array_shift($result); 32 | $this->assertInstanceOf(RegisterArgumentsSet::class, $directive); 33 | $this->assertSame(CacheTask::SET_CACHE_ENGINES, $directive->toArray()['set']); 34 | 35 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 36 | $directive = array_shift($result); 37 | $this->assertSame('\Cake\Cache\Cache::clear()', $directive->toArray()['method']); 38 | 39 | $list = $directive->toArray()['list']; 40 | $list = array_map(function ($className) { 41 | return (string)$className; 42 | }, $list); 43 | 44 | $expected = [ 45 | 'argumentsSet(\'cacheEngines\')', 46 | ]; 47 | $this->assertSame($expected, $list); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/CellTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new CellTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\View\CellTrait::cell()', $directive->toArray()['method']); 32 | 33 | $map = $directive->toArray()['map']; 34 | 35 | $expected = '\TestApp\View\Cell\TestCell::class'; 36 | $this->assertSame($expected, (string)$map['Test']); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ComponentTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ComponentTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(2, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Controller\Controller::loadComponent(0)', $directive->toArray()['method']); 32 | 33 | $map = $directive->toArray()['map']; 34 | 35 | $expected = '\Cake\Controller\Component\FormProtectionComponent::class'; 36 | $this->assertSame($expected, (string)$map['FormProtection']); 37 | 38 | $expected = '\TestApp\Controller\Component\MyOtherComponent::class'; 39 | $this->assertSame($expected, (string)$map['MyOther']); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ConfigureTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ConfigureTask(); 23 | } 24 | 25 | /** 26 | * @return void 27 | */ 28 | public function testCollect() { 29 | $result = $this->task->collect(); 30 | 31 | $this->assertCount(8, $result); 32 | 33 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 34 | $directive = array_shift($result); 35 | $this->assertInstanceOf(RegisterArgumentsSet::class, $directive); 36 | $this->assertSame(ConfigureTask::SET_CONFIGURE_KEYS, $directive->toArray()['set']); 37 | 38 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 39 | $directive = array_shift($result); 40 | $this->assertSame('\Cake\Core\Configure::read()', $directive->toArray()['method']); 41 | 42 | $list = $directive->toArray()['list']; 43 | $list = array_map(function ($className) { 44 | return (string)$className; 45 | }, $list); 46 | 47 | $expected = [ 48 | 'argumentsSet(\'configureKeys\')', 49 | ]; 50 | $this->assertSame($expected, $list); 51 | } 52 | 53 | /** 54 | * @return void 55 | */ 56 | public function testCollectKeys(): void { 57 | $result = $this->invokeMethod($this->task, 'collectKeys'); 58 | 59 | $this->assertArrayHasKey('App.paths.templates', $result); 60 | $this->assertArrayNotHasKey('paths', $result); 61 | $this->assertArrayNotHasKey('templates', $result); 62 | 63 | $this->assertSame('\'debug\'', (string)$result['debug']); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ConnectionTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ConnectionTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Datasource\ConnectionManager::get()', $directive->toArray()['method']); 32 | 33 | $list = $directive->toArray()['list']; 34 | $list = array_map(function ($className) { 35 | return (string)$className; 36 | }, $list); 37 | 38 | $expected = [ 39 | 'test' => "'test'", 40 | ]; 41 | $this->assertSame($expected, $list); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ConsoleHelperTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ConsoleHelperTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Console\ConsoleIo::helper(0)', $directive->toArray()['method']); 32 | 33 | $map = $directive->toArray()['map']; 34 | 35 | $expected = '\Cake\Command\Helper\ProgressHelper::class'; 36 | $this->assertSame($expected, (string)$map['Progress']); 37 | 38 | $expected = '\Cake\Command\Helper\TableHelper::class'; 39 | $this->assertSame($expected, (string)$map['Table']); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ConsoleTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ConsoleTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\ExitPoint $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Console\ConsoleIo::abort()', $directive->toArray()['method']); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/DatabaseTableTaskTest.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected array $fixtures = [ 15 | 'plugin.IdeHelper.Cars', 16 | 'plugin.IdeHelper.Wheels', 17 | ]; 18 | 19 | protected DatabaseTableTask $task; 20 | 21 | /** 22 | * @return void 23 | */ 24 | protected function setUp(): void { 25 | parent::setUp(); 26 | 27 | $this->fetchTable('Cars'); 28 | $this->fetchTable('Wheels'); 29 | 30 | $this->task = new DatabaseTableTask(); 31 | } 32 | 33 | /** 34 | * @return void 35 | */ 36 | protected function tearDown(): void { 37 | parent::tearDown(); 38 | 39 | unset($this->task); 40 | } 41 | 42 | /** 43 | * @return void 44 | */ 45 | public function testCollect() { 46 | $result = $this->task->collect(); 47 | 48 | $this->assertCount(3, $result); 49 | 50 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 51 | $directive = array_shift($result); 52 | $this->assertInstanceOf(RegisterArgumentsSet::class, $directive); 53 | $this->assertSame(DatabaseTableTask::SET_TABLE_NAMES, $directive->toArray()['set']); 54 | 55 | $list = $directive->toArray()['list']; 56 | $expectedList = [ 57 | 'cars' => "'cars'", 58 | 'wheels' => "'wheels'", 59 | ]; 60 | foreach ($expectedList as $key => $value) { 61 | $this->assertArrayHasKey($key, $list); 62 | $this->assertSame($value, (string)$list[$key]); 63 | } 64 | 65 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 66 | $directive = array_shift($result); 67 | $this->assertSame('\Migrations\BaseMigration::table()', $directive->toArray()['method']); 68 | 69 | $list = $directive->toArray()['list']; 70 | $list = array_map(function ($className) { 71 | return (string)$className; 72 | }, $list); 73 | 74 | $expectedList = [ 75 | 'argumentsSet(\'tableNames\')', 76 | ]; 77 | $this->assertSame($expectedList, $list); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/DatabaseTypeTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new DatabaseTypeTask(); 21 | } 22 | 23 | /** 24 | * @return void 25 | */ 26 | public function testCollect() { 27 | TypeFactory::set('uuid', new UuidType()); 28 | 29 | $result = $this->task->collect(); 30 | 31 | $this->assertCount(2, $result); 32 | 33 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 34 | $directive = array_shift($result); 35 | $this->assertSame('\Cake\Database\TypeFactory::build(0)', $directive->toArray()['method']); 36 | 37 | $map = $directive->toArray()['map']; 38 | 39 | $expected = '\Cake\Database\Type\BinaryType::class'; 40 | $this->assertSame($expected, (string)$map['binary']); 41 | 42 | $expected = '\TestApp\Database\Type\UuidType::class'; 43 | $this->assertSame($expected, (string)$map['uuid']); 44 | 45 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 46 | $directive = array_shift($result); 47 | $this->assertSame('\Cake\Database\TypeFactory::map()', $directive->toArray()['method']); 48 | 49 | $list = $directive->toArray()['list']; 50 | $this->assertSame('\'json\'', (string)$list['json']); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ElementTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Awesome']); 22 | $this->task = new ElementTask(); 23 | } 24 | 25 | /** 26 | * @return void 27 | */ 28 | public function testCollect() { 29 | $result = $this->task->collect(); 30 | 31 | $this->assertCount(1, $result); 32 | 33 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 34 | $directive = array_shift($result); 35 | $this->assertSame('\Cake\View\View::element()', $directive->toArray()['method']); 36 | 37 | $list = $directive->toArray()['list']; 38 | $list = array_map(function ($className) { 39 | return (string)$className; 40 | }, $list); 41 | 42 | $expectedMap = [ 43 | 'Awesome.pagination' => '\'Awesome.pagination\'', 44 | 'deeply/nested' => '\'deeply/nested\'', 45 | 'example' => '\'example\'', 46 | ]; 47 | $this->assertSame($expectedMap, $list); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/EntityTaskTest.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected array $fixtures = [ 16 | 'plugin.IdeHelper.Cars', 17 | 'plugin.IdeHelper.Wheels', 18 | ]; 19 | 20 | protected EntityTask $task; 21 | 22 | /** 23 | * @return void 24 | */ 25 | protected function setUp(): void { 26 | parent::setUp(); 27 | 28 | $this->loadPlugins(['Awesome', 'Controllers', 'MyNamespace/MyPlugin', 'Relations', 'Shim', 'IdeHelper']); 29 | $this->task = new EntityTask(); 30 | } 31 | 32 | /** 33 | * @return void 34 | */ 35 | public function testCollect() { 36 | $result = $this->task->collect(); 37 | 38 | $this->assertCount(99, $result); 39 | 40 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 41 | $directive = array_shift($result); 42 | $this->assertInstanceOf(RegisterArgumentsSet::class, $directive); 43 | $this->assertStringContainsString(EntityTask::SET_ENTITY_FIELDS, $directive->toArray()['set']); 44 | 45 | $list = $directive->toArray()['list']; 46 | $list = array_map(function ($className) { 47 | return (string)$className; 48 | }, $list); 49 | 50 | $expected = [ 51 | 'content' => "'content'", 52 | 'created' => "'created'", 53 | 'foo' => "'foo'", 54 | 'houses' => "'houses'", 55 | 'id' => "'id'", 56 | 'name' => "'name'", 57 | ]; 58 | $this->assertSame($expected, $list); 59 | 60 | $directive = array_shift($result); 61 | $this->assertInstanceOf(ExpectedArguments::class, $directive); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/EnvTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new EnvTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\env()', $directive->toArray()['method']); 32 | 33 | $list = $directive->toArray()['list']; 34 | $list = array_map(function ($className) { 35 | return (string)$className; 36 | }, $list); 37 | 38 | $expected = [ 39 | 'HTTP_HOST' => "'HTTP_HOST'", 40 | 'REMOTE_ADDR' => "'REMOTE_ADDR'", 41 | ]; 42 | foreach ($expected as $key => $value) { 43 | $this->assertSame($value, $list[$key]); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/FixtureTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['MyNamespace/MyPlugin', 'IdeHelper']); 19 | $this->task = new FixtureTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(1, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame('\\' . TestCase::class . '::addFixture()', $directive->toArray()['method']); 33 | 34 | $list = $directive->toArray()['list']; 35 | $list = array_map(function ($className) { 36 | return (string)$className; 37 | }, $list); 38 | 39 | $expected = [ 40 | 'app.SmallWindows' => '\'app.SmallWindows\'', 41 | 'core.Posts' => '\'core.Posts\'', 42 | 'plugin.IdeHelper.Windows' => '\'plugin.IdeHelper.Windows\'', 43 | 'plugin.MyNamespace/MyPlugin.Sub/My' => '\'plugin.MyNamespace/MyPlugin.Sub/My\'', 44 | ]; 45 | foreach ($expected as $key => $value) { 46 | $this->assertSame($value, $list[$key]); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/FormHelperTaskTest.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected array $fixtures = [ 15 | 'plugin.IdeHelper.Cars', 16 | 'plugin.IdeHelper.Wheels', 17 | ]; 18 | 19 | protected FormHelperTask $task; 20 | 21 | /** 22 | * @return void 23 | */ 24 | protected function setUp(): void { 25 | parent::setUp(); 26 | 27 | $this->loadPlugins(['Awesome', 'Controllers', 'MyNamespace/MyPlugin', 'Relations', 'Shim', 'IdeHelper']); 28 | $this->fetchTable('Cars'); 29 | $this->fetchTable('Wheels'); 30 | 31 | $this->task = new FormHelperTask(); 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | protected function tearDown(): void { 38 | parent::tearDown(); 39 | 40 | unset($this->task); 41 | } 42 | 43 | /** 44 | * @return void 45 | */ 46 | public function testCollect() { 47 | $result = $this->task->collect(); 48 | 49 | $this->assertCount(1, $result); 50 | 51 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 52 | $directive = array_shift($result); 53 | $this->assertInstanceOf(ExpectedArguments::class, $directive); 54 | 55 | $list = $directive->toArray()['list']; 56 | $list = array_map(function ($className) { 57 | return (string)$className; 58 | }, $list); 59 | 60 | $expectedList = [ 61 | 'content' => "'content'", 62 | 'created' => "'created'", 63 | 'id' => "'id'", 64 | 'modified' => "'modified'", 65 | 'name' => "'name'", 66 | 'params' => "'params'", 67 | 'status' => "'status'", 68 | 'user_id' => "'user_id'", 69 | ]; 70 | $this->assertSame($expectedList, $list); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/HelperTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Shim']); 19 | $this->task = new HelperTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(3, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame('\Cake\View\View::loadHelper(0)', $directive->toArray()['method']); 33 | 34 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 35 | $directive = array_shift($result); 36 | $this->assertSame('\Cake\View\View::addHelper(0)', $directive->toArray()['method']); 37 | 38 | $map = $directive->toArray()['map']; 39 | 40 | $expected = '\Cake\View\Helper\FormHelper::class'; 41 | $this->assertSame($expected, (string)$map['Form']); 42 | 43 | $expected = '\Shim\View\Helper\ConfigureHelper::class'; 44 | $this->assertSame($expected, (string)$map['Shim.Configure']); 45 | 46 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 47 | $directive = array_shift($result); 48 | $this->assertSame('\Cake\View\ViewBuilder::addHelper()', $directive->toArray()['method']); 49 | 50 | $list = $directive->toArray()['list']; 51 | 52 | $expected = "'Form'"; 53 | $this->assertSame($expected, (string)$list['Form']); 54 | 55 | $expected = "'Shim.Configure'"; 56 | $this->assertSame($expected, (string)$list['Shim.Configure']); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/LayoutTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new LayoutTask(); 22 | } 23 | 24 | /** 25 | * @return void 26 | */ 27 | public function testCollect() { 28 | $result = $this->task->collect(); 29 | 30 | $this->assertCount(1, $result); 31 | 32 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 33 | $directive = array_shift($result); 34 | $this->assertSame('\Cake\View\ViewBuilder::setLayout()', $directive->toArray()['method']); 35 | 36 | $list = $directive->toArray()['list']; 37 | $list = array_map(function ($className) { 38 | return (string)$className; 39 | }, $list); 40 | 41 | $expectedMap = [ 42 | 'ajax' => '\'ajax\'', 43 | ]; 44 | $this->assertSame($expectedMap, $list); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/MailerTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new MailerTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(1, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Mailer\MailerAwareTrait::getMailer(0)', $directive->toArray()['method']); 32 | 33 | $map = $directive->toArray()['map']; 34 | 35 | $expected = '\TestApp\Mailer\UserMailer::class'; 36 | $this->assertSame($expected, (string)$map['User']); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ModelTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Awesome', 'Controllers', 'MyNamespace/MyPlugin', 'Relations']); 19 | $this->task = new ModelTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(3, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame('\Cake\ORM\Locator\LocatorInterface::get(0)', $directive->toArray()['method']); 33 | 34 | $map = $directive->toArray()['map']; 35 | $map = array_map(function ($className) { 36 | return (string)$className; 37 | }, $map); 38 | 39 | $expectedMap = [ 40 | 'Awesome.Houses' => '\Awesome\Model\Table\HousesTable::class', 41 | 'Awesome.Windows' => '\Awesome\Model\Table\WindowsTable::class', 42 | 'BarBars' => '\TestApp\Model\Table\BarBarsTable::class', 43 | 'BarBarsAbstract' => '\TestApp\Model\Table\BarBarsAbstractTable::class', 44 | 'Callbacks' => '\TestApp\Model\Table\CallbacksTable::class', 45 | 'Cars' => '\TestApp\Model\Table\CarsTable::class', 46 | 'Controllers.Houses' => '\Controllers\Model\Table\HousesTable::class', 47 | 'CustomFinder' => '\TestApp\Model\Table\CustomFinderTable::class', 48 | 'Exceptions' => '\TestApp\Model\Table\ExceptionsTable::class', 49 | 'Foos' => '\TestApp\Model\Table\FoosTable::class', 50 | 'MyNamespace/MyPlugin.My' => '\MyNamespace\MyPlugin\Model\Table\MyTable::class', 51 | 'Relations.Bars' => '\Relations\Model\Table\BarsTable::class', 52 | 'Relations.Foos' => '\Relations\Model\Table\FoosTable::class', 53 | 'Relations.Users' => '\Relations\Model\Table\UsersTable::class', 54 | 'SkipMe' => '\TestApp\Model\Table\SkipMeTable::class', 55 | 'SkipSome' => '\TestApp\Model\Table\SkipSomeTable::class', 56 | 'Wheels' => '\TestApp\Model\Table\WheelsTable::class', 57 | 'WheelsExtra' => '\TestApp\Model\Table\WheelsExtraTable::class', 58 | ]; 59 | $this->assertSame($expectedMap, $map); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/PluginTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Bake', 'Migrations', 'Shim']); 20 | $this->task = new PluginTask(); 21 | } 22 | 23 | /** 24 | * @return void 25 | */ 26 | public function testCollect() { 27 | $result = $this->task->collect(); 28 | 29 | $this->assertCount(1, $result); 30 | 31 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 32 | $directive = array_shift($result); 33 | $this->assertSame('\Cake\Core\PluginApplicationInterface::addPlugin(0)', $directive->toArray()['method']); 34 | 35 | $map = $directive->toArray()['map']; 36 | $map = array_map(function ($className) { 37 | return (string)$className; 38 | }, $map); 39 | 40 | $expected = [ 41 | 'Bake' => '\Cake\Http\BaseApplication::class', 42 | 'Cake/TwigView' => '\Cake\Http\BaseApplication::class', 43 | 'Migrations' => '\Cake\Http\BaseApplication::class', 44 | 'Shim' => '\Cake\Http\BaseApplication::class', 45 | ]; 46 | if (version_compare(Configure::version(), '5.1.0', '<')) { 47 | $expected = []; 48 | } 49 | $this->assertSame($expected, $map); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/RequestTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new RequestTask(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testCollect() { 25 | $result = $this->task->collect(); 26 | 27 | $this->assertCount(2, $result); 28 | 29 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 30 | $directive = array_shift($result); 31 | $this->assertSame('\Cake\Http\ServerRequest::getParam()', $directive->toArray()['method']); 32 | 33 | $list = $directive->toArray()['list']; 34 | $list = array_map(function ($className) { 35 | return (string)$className; 36 | }, $list); 37 | 38 | $expected = [ 39 | '_ext' => "'_ext'", 40 | '_matchedRoute' => "'_matchedRoute'", 41 | 'action' => "'action'", 42 | 'controller' => "'controller'", 43 | 'pass' => "'pass'", 44 | 'plugin' => "'plugin'", 45 | 'prefix' => "'prefix'", 46 | ]; 47 | $this->assertSame($expected, $list); 48 | 49 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 50 | $directive = array_shift($result); 51 | $this->assertSame('\Cake\Http\ServerRequest::getAttribute(0)', $directive->toArray()['method']); 52 | 53 | $map = $directive->toArray()['map']; 54 | 55 | $expected = '\Cake\Http\Session::class'; 56 | $this->assertSame($expected, (string)$map['session']); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/RoutePathTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['Awesome']); 19 | $this->task = new RoutePathTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(5, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame(RoutePathTask::SET_ROUTE_PATHS, $directive->toArray()['set']); 33 | 34 | $list = $directive->toArray()['list']; 35 | $list = array_map(function ($value) { 36 | return (string)$value; 37 | }, $list); 38 | 39 | $expected = [ 40 | 'Awesome.Admin/AwesomeHouses::openDoor' => "'Awesome.Admin/AwesomeHouses::openDoor'", 41 | 'Bar::index' => "'Bar::index'", 42 | ]; 43 | $this->assertSame($expected, $list); 44 | 45 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 46 | $directive = array_shift($result); 47 | $this->assertSame('\Cake\Routing\Router::pathUrl()', $directive->toArray()['method']); 48 | 49 | $list = $directive->toArray()['list']; 50 | $list = array_map(function ($value) { 51 | return (string)$value; 52 | }, $list); 53 | 54 | $expected = [ 55 | 'argumentsSet(\'routePaths\')', 56 | ]; 57 | $this->assertSame($expected, $list); 58 | 59 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 60 | $directive = array_shift($result); 61 | $this->assertSame('\Cake\View\Helper\UrlHelper::buildFromPath()', $directive->toArray()['method']); 62 | 63 | /** @var \IdeHelper\Generator\Directive\ExpectedArguments $directive */ 64 | $directive = array_shift($result); 65 | $this->assertSame('\Cake\View\Helper\HtmlHelper::linkFromPath()', $directive->toArray()['method']); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/TableAssociationTaskTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['IdeHelper', 'Shim', 'Awesome', 'Controllers', 'Relations', 'MyNamespace/MyPlugin']); 19 | $this->task = new TableAssociationTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(4, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 31 | $directive = array_shift($result); 32 | $this->assertSame('\Cake\ORM\Table::belongsTo(0)', $directive->toArray()['method']); 33 | 34 | $map = $directive->toArray()['map']; 35 | $map = array_map(function ($className) { 36 | return (string)$className; 37 | }, $map); 38 | 39 | $expectedMap = [ 40 | 'Awesome.Houses' => '\Cake\ORM\Association\BelongsTo::class', 41 | 'Awesome.Windows' => '\Cake\ORM\Association\BelongsTo::class', 42 | 'BarBars' => '\Cake\ORM\Association\BelongsTo::class', 43 | 'BarBarsAbstract' => '\Cake\ORM\Association\BelongsTo::class', 44 | 'Callbacks' => '\Cake\ORM\Association\BelongsTo::class', 45 | 'Cars' => '\Cake\ORM\Association\BelongsTo::class', 46 | 'Controllers.Houses' => '\Cake\ORM\Association\BelongsTo::class', 47 | 'CustomFinder' => '\Cake\ORM\Association\BelongsTo::class', 48 | 'Exceptions' => '\Cake\ORM\Association\BelongsTo::class', 49 | 'Foos' => '\Cake\ORM\Association\BelongsTo::class', 50 | 'MyNamespace/MyPlugin.My' => '\Cake\ORM\Association\BelongsTo::class', 51 | 'Relations.Bars' => '\Cake\ORM\Association\BelongsTo::class', 52 | 'Relations.Foos' => '\Cake\ORM\Association\BelongsTo::class', 53 | 'Relations.Users' => '\Cake\ORM\Association\BelongsTo::class', 54 | 'SkipMe' => '\Cake\ORM\Association\BelongsTo::class', 55 | 'SkipSome' => '\Cake\ORM\Association\BelongsTo::class', 56 | 'Wheels' => '\Cake\ORM\Association\BelongsTo::class', 57 | 'WheelsExtra' => '\Cake\ORM\Association\BelongsTo::class', 58 | ]; 59 | $this->assertSame($expectedMap, $map); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/Task/ValidationTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new ValidationTask(); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testCollect() { 26 | $result = $this->task->collect(); 27 | 28 | $this->assertCount(15, $result); 29 | 30 | /** @var \IdeHelper\Generator\Directive\RegisterArgumentsSet $directive */ 31 | $directive = array_shift($result); 32 | $this->assertInstanceOf(RegisterArgumentsSet::class, $directive); 33 | $this->assertSame(ValidationTask::SET_VALIDATION_WHEN, $directive->toArray()['set']); 34 | 35 | $list = $directive->toArray()['list']; 36 | $list = array_map(function ($className) { 37 | return (string)$className; 38 | }, $list); 39 | 40 | $expected = [ 41 | "'create'", 42 | "'update'", 43 | ]; 44 | $this->assertSame($expected, $list); 45 | 46 | /** @var \IdeHelper\Generator\Directive\Override $directive */ 47 | $directive = array_shift($result); 48 | $this->assertSame('\Cake\Validation\Validator::requirePresence()', $directive->toArray()['method']); 49 | 50 | $list = $directive->toArray()['list']; 51 | $list = array_map(function ($className) { 52 | return (string)$className; 53 | }, $list); 54 | 55 | $expected = [ 56 | 'argumentsSet(\'validationWhen\')', 57 | ]; 58 | $this->assertSame($expected, $list); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /tests/TestCase/Generator/TaskCollectionTest.php: -------------------------------------------------------------------------------- 1 | taskCollection = new TaskCollection(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testTasks() { 25 | $result = $this->taskCollection->tasks(); 26 | 27 | $this->assertNotEmpty($result); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestCase/Illuminator/IlluminatorTest.php: -------------------------------------------------------------------------------- 1 | out = new ConsoleOutput(); 29 | $this->err = new ConsoleOutput(); 30 | $consoleIo = new ConsoleIo($this->out, $this->err); 31 | $consoleIo->level($consoleIo::VERBOSE); 32 | $this->io = new Io($consoleIo); 33 | 34 | $taskCollection = new TaskCollection($this->io, ['dry-run' => true]); 35 | 36 | $this->illuminator = new Illuminator($taskCollection); 37 | } 38 | 39 | /** 40 | * @return void 41 | */ 42 | public function testIlluminate() { 43 | $path = TEST_FILES; 44 | $count = $this->illuminator->illuminate($path, null); 45 | 46 | $this->assertSame(13, $count); 47 | 48 | $out = $this->out->output(); 49 | 50 | $this->assertTextContains('public const FIELD_ID = \'id\';', $out); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/AppPathTest.php: -------------------------------------------------------------------------------- 1 | assertCount(1, $result); 16 | 17 | $path = array_shift($result); 18 | $this->assertTextContains('/tests/test_app/src/View/Helper/', $path); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/AppTest.php: -------------------------------------------------------------------------------- 1 | assertNull($result); 17 | 18 | $result = App::className('IdeHelper.DocBlock', 'View/Helper', 'Helper'); 19 | $this->assertSame(DocBlockHelper::class, $result); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/GenericStringTest.php: -------------------------------------------------------------------------------- 1 | assertSame('Foo[]', $result); 17 | 18 | Configure::write('IdeHelper.arrayAsGenerics', true); 19 | 20 | $result = GenericString::generate('Foo'); 21 | 22 | Configure::delete('IdeHelper.arrayAsGenerics'); 23 | 24 | $this->assertSame('array', $result); 25 | } 26 | 27 | /** 28 | * @return void 29 | */ 30 | public function testClassNameObject() { 31 | $result = GenericString::generate('\Foo', '\Bar'); 32 | $this->assertSame('\Foo[]|\Bar', $result); 33 | 34 | Configure::write('IdeHelper.objectAsGenerics', true); 35 | 36 | $result = GenericString::generate('\Foo', '\Bar'); 37 | 38 | Configure::delete('IdeHelper.objectAsGenerics'); 39 | 40 | $this->assertSame('\Bar<\Foo>', $result); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/PluginPathTest.php: -------------------------------------------------------------------------------- 1 | assertTextContains('cakephp-ide-helper/vendor/dereuromark/cakephp-shim/', $result); 18 | 19 | Plugin::getCollection()->remove('Awesome'); 20 | 21 | $plugin = 'Awesome'; 22 | $result = PluginPath::get($plugin); 23 | $this->assertTextContains('cakephp-ide-helper/tests/test_app/plugins/Awesome/', $result); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/PluginTest.php: -------------------------------------------------------------------------------- 1 | loadPlugins(['IdeHelper', 'Awesome', 'MyNamespace/MyPlugin']); 18 | Configure::delete('IdeHelper.plugins'); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | protected function tearDown(): void { 25 | parent::tearDown(); 26 | 27 | Configure::delete('IdeHelper.plugins'); 28 | } 29 | 30 | /** 31 | * @return void 32 | */ 33 | public function testAll() { 34 | $result = Plugin::all(); 35 | $this->assertArrayHasKey('IdeHelper', $result); 36 | $this->assertArrayHasKey('Awesome', $result); 37 | $this->assertArrayHasKey('MyNamespace/MyPlugin', $result); 38 | $this->assertArrayNotHasKey('FooBar', $result); 39 | 40 | Configure::write('IdeHelper.plugins', ['FooBar', '-MyNamespace/MyPlugin']); 41 | 42 | $result = Plugin::all(); 43 | $this->assertArrayHasKey('FooBar', $result); 44 | $this->assertArrayNotHasKey('MyNamespace/MyPlugin', $result); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase/Utility/TranslationParserTest.php: -------------------------------------------------------------------------------- 1 | translationParser = new TranslationParser(); 19 | } 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function testParse() { 25 | $path = TEST_FILES . 'locales' . DS . 'default.po'; 26 | 27 | $result = $this->translationParser->parse($path); 28 | 29 | $expected = [ 30 | 'A "quoted" string' => 'A "quoted" string', 31 | 'A ""escape-quoted"" string' => 'A ""escape-quoted"" string', 32 | 'A \\\'literally quoted\\\' string' => 'A \\\'literally quoted\\\' string', 33 | 'A variable \\\'\\\'{0}\\\'\\\' be replaced.' => 'A variable \\\'\\\'{0}\\\'\\\' be replaced.', 34 | ]; 35 | $this->assertSame($expected, $result); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /tests/TestCase/ValueObject/ClassNameTest.php: -------------------------------------------------------------------------------- 1 | assertSame($className, $result->raw()); 17 | 18 | $result = ClassName::create('\\' . $className); 19 | $this->assertSame($className, $result->raw()); 20 | } 21 | 22 | /** 23 | * @return void 24 | */ 25 | public function testToString(): void { 26 | $className = 'Foo\\Bar\\Baz'; 27 | $object = ClassName::create($className); 28 | 29 | $result = (string)$object; 30 | $this->assertSame('\\' . $className . '::class', $result); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/TestCase/ValueObject/DoubleQuoteStringNameTest.php: -------------------------------------------------------------------------------- 1 | assertSame($stringName, $result->raw()); 17 | } 18 | 19 | /** 20 | * @return void 21 | */ 22 | public function testToString(): void { 23 | $stringName = 'Foo.Baz'; 24 | $object = DoubleQuoteStringName::create($stringName); 25 | 26 | $result = (string)$object; 27 | $this->assertSame('"' . $stringName . '"', $result); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestCase/ValueObject/KeyValueTest.php: -------------------------------------------------------------------------------- 1 | assertSame($key, $result->key()); 21 | $this->assertSame($value, $result->value()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tests/TestCase/ValueObject/LiteralNameTest.php: -------------------------------------------------------------------------------- 1 | assertSame($stringName, $result->raw()); 17 | } 18 | 19 | /** 20 | * @return void 21 | */ 22 | public function testToString(): void { 23 | $stringName = 'Foo.Baz'; 24 | $object = LiteralName::create($stringName); 25 | 26 | $result = (string)$object; 27 | $this->assertSame($stringName, $result); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestCase/ValueObject/StringNameTest.php: -------------------------------------------------------------------------------- 1 | assertSame($stringName, $result->raw()); 17 | } 18 | 19 | /** 20 | * @return void 21 | */ 22 | public function testToString(): void { 23 | $stringName = 'Foo.Baz'; 24 | $object = StringName::create($stringName); 25 | 26 | $result = (string)$object; 27 | $this->assertSame('\'' . $stringName . '\'', $result); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | paths: 4 | - TestCase/ 5 | bootstrapFiles: 6 | - bootstrap.php 7 | - shim.php 8 | earlyTerminatingMethodCalls: 9 | Cake\Console\BaseCommand: 10 | - abort 11 | ignoreErrors: 12 | - identifier: missingType.iterableValue 13 | -------------------------------------------------------------------------------- /tests/schema.php: -------------------------------------------------------------------------------- 1 | $iterator 9 | */ 10 | $iterator = new DirectoryIterator(__DIR__ . DS . 'Fixture'); 11 | foreach ($iterator as $file) { 12 | if (!preg_match('/(\w+)Fixture.php$/', (string)$file, $matches)) { 13 | continue; 14 | } 15 | 16 | $name = $matches[1]; 17 | $tableName = Inflector::underscore($name); 18 | $class = 'IdeHelper\\Test\\Fixture\\' . $name . 'Fixture'; 19 | try { 20 | $object = (new ReflectionClass($class))->getProperty('fields'); 21 | } catch (ReflectionException $e) { 22 | continue; 23 | } 24 | 25 | $array = $object->getDefaultValue(); 26 | $constraints = $array['_constraints'] ?? []; 27 | $indexes = $array['_indexes'] ?? []; 28 | unset($array['_constraints'], $array['_indexes'], $array['_options']); 29 | $table = [ 30 | 'table' => $tableName, 31 | 'columns' => $array, 32 | 'constraints' => $constraints, 33 | 'indexes' => $indexes, 34 | ]; 35 | $tables[$tableName] = $table; 36 | } 37 | 38 | return $tables; 39 | -------------------------------------------------------------------------------- /tests/shim.php: -------------------------------------------------------------------------------- 1 |