biiiiiigmonster /
laravel-enum
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace BiiiiiigMonster\LaravelEnum\Commands; |
||||
| 4 | |||||
| 5 | use BiiiiiigMonster\LaravelEnum\ClassVisitor; |
||||
| 6 | use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits; |
||||
|
0 ignored issues
–
show
|
|||||
| 7 | use BiiiiiigMonster\LaravelEnum\Concerns\Meta; |
||||
| 8 | use BiiiiiigMonster\LaravelEnum\Reader; |
||||
| 9 | use Illuminate\Console\Command; |
||||
| 10 | use Illuminate\Contracts\Filesystem\FileNotFoundException; |
||||
| 11 | use Illuminate\Filesystem\Filesystem; |
||||
| 12 | use Illuminate\Support\Arr; |
||||
| 13 | use InvalidArgumentException; |
||||
| 14 | use Laminas\Code\Generator\DocBlock\Tag\MethodTag; |
||||
| 15 | use Laminas\Code\Generator\DocBlock\Tag\TagInterface; |
||||
| 16 | use Laminas\Code\Generator\DocBlockGenerator; |
||||
| 17 | use Laminas\Code\Reflection\DocBlockReflection; |
||||
| 18 | use ReflectionEnum; |
||||
|
0 ignored issues
–
show
The type
ReflectionEnum was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 19 | use ReflectionEnumUnitCase; |
||||
|
0 ignored issues
–
show
The type
ReflectionEnumUnitCase was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 20 | use ReflectionException; |
||||
| 21 | use ReflectionIntersectionType; |
||||
|
0 ignored issues
–
show
The type
ReflectionIntersectionType was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 22 | use ReflectionMethod; |
||||
| 23 | use ReflectionNamedType; |
||||
| 24 | use ReflectionUnionType; |
||||
| 25 | use Symfony\Component\Console\Attribute\AsCommand; |
||||
| 26 | use Symfony\Component\Finder\Finder; |
||||
| 27 | use UnitEnum; |
||||
|
0 ignored issues
–
show
The type
UnitEnum was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 28 | |||||
| 29 | #[AsCommand(name: 'enum:phpdoc')] |
||||
| 30 | class EnumPhpdocCommand extends Command |
||||
| 31 | { |
||||
| 32 | protected $signature = 'enum:phpdoc |
||||
| 33 | {enum?* : The enum class to generate PHPDoc for} |
||||
| 34 | {--folder=* : The folder to scan for enums to generate PHPDoc}'; |
||||
| 35 | |||||
| 36 | protected $description = 'Generate PHP DocBlock of static case method and meta method for enum classes'; |
||||
| 37 | |||||
| 38 | protected Filesystem $filesystem; |
||||
| 39 | |||||
| 40 | /** |
||||
| 41 | * @throws ReflectionException|FileNotFoundException |
||||
| 42 | */ |
||||
| 43 | public function handle(Filesystem $filesystem): void |
||||
| 44 | { |
||||
| 45 | $this->filesystem = $filesystem; |
||||
| 46 | |||||
| 47 | if ($classNames = (array) $this->argument('enum')) { |
||||
| 48 | foreach ($classNames as $className) { |
||||
| 49 | /** @var class-string $className */ |
||||
| 50 | if (! enum_exists($className)) { |
||||
|
0 ignored issues
–
show
The function
enum_exists was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 51 | throw new InvalidArgumentException( |
||||
| 52 | sprintf('The given class must be an instance of %s: %s', UnitEnum::class, $className) |
||||
| 53 | ); |
||||
| 54 | } |
||||
| 55 | |||||
| 56 | if (! in_array(EnumTraits::class, class_uses_recursive($className))) { |
||||
| 57 | throw new InvalidArgumentException( |
||||
| 58 | sprintf('The given class must be use trait of %s: %s', EnumTraits::class, $className) |
||||
| 59 | ); |
||||
| 60 | } |
||||
| 61 | $this->phpdoc($className); |
||||
| 62 | } |
||||
| 63 | |||||
| 64 | return; |
||||
| 65 | } |
||||
| 66 | |||||
| 67 | foreach ($this->getClassFinder() as $file) { |
||||
| 68 | new Reader($file, $classVisitor = new ClassVisitor()); |
||||
| 69 | $className = $classVisitor->getName(); |
||||
| 70 | if (enum_exists($className) && in_array(EnumTraits::class, class_uses_recursive($className))) { |
||||
| 71 | $this->phpdoc($className); |
||||
| 72 | } |
||||
| 73 | } |
||||
| 74 | } |
||||
| 75 | |||||
| 76 | /** |
||||
| 77 | * @throws ReflectionException|FileNotFoundException |
||||
| 78 | */ |
||||
| 79 | protected function phpdoc(string $className): void |
||||
| 80 | { |
||||
| 81 | $reflection = new ReflectionEnum($className); |
||||
| 82 | |||||
| 83 | $this->writeDocComment($reflection, $this->getDocBlock($reflection)); |
||||
| 84 | } |
||||
| 85 | |||||
| 86 | protected function getDocBlock(ReflectionEnum $reflection): DocBlockGenerator |
||||
| 87 | { |
||||
| 88 | $docBlock = $reflection->getDocComment() |
||||
| 89 | ? DocBlockGenerator::fromReflection(new DocBlockReflection($reflection)) |
||||
| 90 | : new DocBlockGenerator(); |
||||
| 91 | |||||
| 92 | $retainedTags = collect($docBlock->getTags()) |
||||
|
0 ignored issues
–
show
$docBlock->getTags() of type Laminas\Code\Generator\DocBlock\Tag\TagInterface[] is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 93 | ->reject(fn (TagInterface $tag) => $tag instanceof MethodTag) |
||||
| 94 | ->all(); |
||||
| 95 | |||||
| 96 | $caseTags = []; |
||||
| 97 | $enumBackingType = 'string'; |
||||
| 98 | $rft = $reflection->getBackingType(); |
||||
| 99 | if ($rft instanceof ReflectionNamedType) { |
||||
| 100 | $enumBackingType = $rft->getName(); |
||||
| 101 | } |
||||
| 102 | |||||
| 103 | $metaTags = collect($reflection->getCases()) |
||||
| 104 | ->flatMap(function (ReflectionEnumUnitCase $reflectionEnumUnitCase) use (&$caseTags, $enumBackingType) { |
||||
| 105 | $case = $reflectionEnumUnitCase->getValue(); |
||||
| 106 | $caseTags[] = new MethodTag($case->name, [$enumBackingType], isStatic: true); |
||||
| 107 | |||||
| 108 | return array_map(function (Meta $meta) { |
||||
| 109 | $rfm = new ReflectionMethod($meta, 'transform'); |
||||
| 110 | $types = []; |
||||
| 111 | $rft = $rfm->getReturnType(); |
||||
| 112 | if ($rft instanceof ReflectionNamedType) { |
||||
| 113 | $types[] = $rft->getName(); |
||||
| 114 | } elseif ($rft instanceof ReflectionUnionType) { |
||||
| 115 | $types = Arr::map($rft->getTypes(), fn (ReflectionNamedType $type) => $type->getName()); |
||||
| 116 | } elseif ($rft instanceof ReflectionIntersectionType) { |
||||
| 117 | $types[] = collect($rft->getTypes())->map(fn (ReflectionNamedType $type) => $type->getName())->implode('&'); |
||||
|
0 ignored issues
–
show
The method
getTypes() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionUnionType.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 118 | } |
||||
| 119 | |||||
| 120 | return [$meta::method() => $types]; |
||||
| 121 | }, $case->metas()); |
||||
| 122 | }) |
||||
| 123 | ->collapse() |
||||
| 124 | ->map(fn (array $types, string $methodName) => new MethodTag($methodName, $types)) // @phpstan-ignore-line |
||||
| 125 | ->values() |
||||
| 126 | ->all(); |
||||
| 127 | |||||
| 128 | return new DocBlockGenerator( |
||||
| 129 | $docBlock->getShortDescription(), |
||||
| 130 | $docBlock->getLongDescription(), |
||||
| 131 | array_merge($retainedTags, $caseTags, $metaTags) |
||||
| 132 | ); |
||||
| 133 | } |
||||
| 134 | |||||
| 135 | /** |
||||
| 136 | * @throws FileNotFoundException |
||||
| 137 | */ |
||||
| 138 | protected function writeDocComment(ReflectionEnum $reflection, DocBlockGenerator $docBlock): void |
||||
| 139 | { |
||||
| 140 | $fileName = (string) $reflection->getFileName(); |
||||
| 141 | $shortName = $reflection->getShortName(); |
||||
| 142 | $classDeclaration = "enum $shortName"; |
||||
| 143 | $contents = $this->filesystem->get($fileName); |
||||
| 144 | |||||
| 145 | // Remove existing docblock |
||||
| 146 | $contents = (string) preg_replace( |
||||
| 147 | sprintf('#([\n]?\/\*(?:[^*]|\n|(?:\*(?:[^\/]|\n)))*\*\/)?[\n]?%s#ms', preg_quote($classDeclaration)), |
||||
| 148 | "\n".$classDeclaration, |
||||
| 149 | $contents |
||||
| 150 | ); |
||||
| 151 | |||||
| 152 | $classDeclarationOffset = (int) strpos($contents, $classDeclaration); |
||||
| 153 | // Make sure we don't replace too much |
||||
| 154 | $contents = substr_replace( |
||||
| 155 | $contents, |
||||
| 156 | sprintf('%s%s', $docBlock->generate(), $classDeclaration), |
||||
| 157 | $classDeclarationOffset, |
||||
| 158 | strlen($classDeclaration) |
||||
| 159 | ); |
||||
| 160 | |||||
| 161 | $this->filesystem->put($fileName, $contents); |
||||
|
0 ignored issues
–
show
It seems like
$contents can also be of type array; however, parameter $contents of Illuminate\Filesystem\Filesystem::put() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 162 | $this->info("Wrote new phpDocBlock to {$fileName}."); |
||||
| 163 | } |
||||
| 164 | |||||
| 165 | protected function getClassFinder(): Finder |
||||
| 166 | { |
||||
| 167 | $scanPaths = $this->option('folder') ?: app_path('Enums'); |
||||
| 168 | |||||
| 169 | return Finder::create()->files()->in((array) $scanPaths)->name('*.php'); |
||||
| 170 | } |
||||
| 171 | } |
||||
| 172 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths