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 ![]() |
|||||
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 ![]() |
|||||
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 ![]() |
|||||
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 ![]() |
|||||
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
![]() |
|||||
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
![]() |
|||||
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
![]() |
|||||
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
![]() |
|||||
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