Skip to content

Commit a882b4a

Browse files
committed
refactor: enhance type safety and improve code clarity across various classes and methods
1 parent 1f468bd commit a882b4a

13 files changed

+429
-51
lines changed

phpstan-baseline.neon

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,253 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#^Parameter \#1 \$iterator of function iterator_to_array expects iterable, Illuminate\\Routing\\RouteCollectionInterface given\.$#'
5+
identifier: argument.type
6+
count: 1
7+
path: src/Console/Commands/ApiVersionHealthCommand.php
18

9+
-
10+
message: '#^Parameter \#1 \$iterator of function iterator_to_array expects iterable, Illuminate\\Routing\\RouteCollectionInterface given\.$#'
11+
identifier: argument.type
12+
count: 1
13+
path: src/Console/Commands/ApiVersionsCommand.php
14+
15+
-
16+
message: '#^Cannot call method toArray\(\) on mixed\.$#'
17+
identifier: method.nonObject
18+
count: 1
19+
path: src/Http/Resources/VersionedJsonResource.php
20+
21+
-
22+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedJsonResource\:\:callMethodIfExists\(\) should return array\<string, mixed\> but returns array\<mixed\>\.$#'
23+
identifier: return.type
24+
count: 2
25+
path: src/Http/Resources/VersionedJsonResource.php
26+
27+
-
28+
message: '#^Parameter \#1 \$callback of function call_user_func expects callable\(\)\: mixed, array\{\$this\(ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedJsonResource\), string\} given\.$#'
29+
identifier: argument.type
30+
count: 1
31+
path: src/Http/Resources/VersionedJsonResource.php
32+
33+
-
34+
message: '#^Cannot access offset ''version_inheritance'' on mixed\.$#'
35+
identifier: offsetAccess.nonOffsetAccessible
36+
count: 1
37+
path: src/Http/Resources/VersionedResourceCollection.php
38+
39+
-
40+
message: '#^Cannot access offset ''version_method_mapping'' on mixed\.$#'
41+
identifier: offsetAccess.nonOffsetAccessible
42+
count: 1
43+
path: src/Http/Resources/VersionedResourceCollection.php
44+
45+
-
46+
message: '#^Cannot access offset mixed on mixed\.$#'
47+
identifier: offsetAccess.nonOffsetAccessible
48+
count: 2
49+
path: src/Http/Resources/VersionedResourceCollection.php
50+
51+
-
52+
message: '#^Cannot access offset string on mixed\.$#'
53+
identifier: offsetAccess.nonOffsetAccessible
54+
count: 1
55+
path: src/Http/Resources/VersionedResourceCollection.php
56+
57+
-
58+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedResourceCollection\:\:callMethodIfExists\(\) should return array\<string, mixed\> but returns array\<mixed\>\.$#'
59+
identifier: return.type
60+
count: 1
61+
path: src/Http/Resources/VersionedResourceCollection.php
62+
63+
-
64+
message: '#^Parameter \#1 \$callback of function call_user_func expects callable\(\)\: mixed, array\{\$this\(ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedResourceCollection\), string\} given\.$#'
65+
identifier: argument.type
66+
count: 1
67+
path: src/Http/Resources/VersionedResourceCollection.php
68+
69+
-
70+
message: '#^Parameter \#1 \$method of method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedResourceCollection\:\:callMethodIfExists\(\) expects string, mixed given\.$#'
71+
identifier: argument.type
72+
count: 2
73+
path: src/Http/Resources/VersionedResourceCollection.php
74+
75+
-
76+
message: '#^Parameter \#1 \$method of method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Resources\\VersionedResourceCollection\:\:methodExists\(\) expects string, mixed given\.$#'
77+
identifier: argument.type
78+
count: 2
79+
path: src/Http/Resources/VersionedResourceCollection.php
80+
81+
-
82+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Responses\\ProblemDetailsResponse\:\:__construct\(\) has parameter \$extensions with no value type specified in iterable type array\.$#'
83+
identifier: missingType.iterableValue
84+
count: 1
85+
path: src/Http/Responses/ProblemDetailsResponse.php
86+
87+
-
88+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Responses\\ProblemDetailsResponse\:\:unsupportedVersion\(\) has parameter \$endpointVersions with no value type specified in iterable type array\.$#'
89+
identifier: missingType.iterableValue
90+
count: 1
91+
path: src/Http/Responses/ProblemDetailsResponse.php
92+
93+
-
94+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Http\\Responses\\ProblemDetailsResponse\:\:unsupportedVersion\(\) has parameter \$supportedVersions with no value type specified in iterable type array\.$#'
95+
identifier: missingType.iterableValue
96+
count: 1
97+
path: src/Http/Responses/ProblemDetailsResponse.php
98+
99+
-
100+
message: '#^Parameter \#3 \$callback of static method Illuminate\\Support\\Facades\\Cache\:\:remember\(\) expects Closure, callable\(\)\: mixed given\.$#'
101+
identifier: argument.type
102+
count: 1
103+
path: src/Services/AttributeCacheService.php
104+
105+
-
106+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:createVersionInfo\(\) has parameter \$class with generic class ReflectionClass but does not specify its types\: T$#'
107+
identifier: missingType.generics
108+
count: 1
109+
path: src/Services/AttributeVersionResolver.php
110+
111+
-
112+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:getAllVersionsForRoute\(\) should return array\<string\> but returns mixed\.$#'
113+
identifier: return.type
114+
count: 1
115+
path: src/Services/AttributeVersionResolver.php
116+
117+
-
118+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:getDeprecationInfo\(\) has parameter \$reflection with generic class ReflectionClass but does not specify its types\: T$#'
119+
identifier: missingType.generics
120+
count: 1
121+
path: src/Services/AttributeVersionResolver.php
122+
123+
-
124+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:getVersionsFromAttributes\(\) has parameter \$reflection with generic class ReflectionClass but does not specify its types\: T$#'
125+
identifier: missingType.generics
126+
count: 1
127+
path: src/Services/AttributeVersionResolver.php
128+
129+
-
130+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:getVersionsFromAttributes\(\) should return array\<string\> but returns array\.$#'
131+
identifier: return.type
132+
count: 1
133+
path: src/Services/AttributeVersionResolver.php
134+
135+
-
136+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:hasAttribute\(\) has parameter \$reflection with generic class ReflectionClass but does not specify its types\: T$#'
137+
identifier: missingType.generics
138+
count: 1
139+
path: src/Services/AttributeVersionResolver.php
140+
141+
-
142+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeVersionResolver\:\:resolveVersionForRoute\(\) should return ShahGhasiAdil\\LaravelApiVersioning\\ValueObjects\\VersionInfo\|null but returns mixed\.$#'
143+
identifier: return.type
144+
count: 1
145+
path: src/Services/AttributeVersionResolver.php
146+
147+
-
148+
message: '#^Parameter \#1 \$controller of method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeCacheService\:\:generateRouteKey\(\) expects string, class\-string\|false given\.$#'
149+
identifier: argument.type
150+
count: 1
151+
path: src/Services/AttributeVersionResolver.php
152+
153+
-
154+
message: '#^Parameter \#1 \$controller of method ShahGhasiAdil\\LaravelApiVersioning\\Services\\AttributeCacheService\:\:generateRouteVersionsKey\(\) expects string, class\-string\|false given\.$#'
155+
identifier: argument.type
156+
count: 1
157+
path: src/Services/AttributeVersionResolver.php
158+
159+
-
160+
message: '#^Parameter \#1 \$object of function get_class expects object, mixed given\.$#'
161+
identifier: argument.type
162+
count: 2
163+
path: src/Services/AttributeVersionResolver.php
164+
165+
-
166+
message: '#^Parameter \#1 \$objectOrClass of class ReflectionClass constructor expects class\-string\<T of object\>\|T of object, mixed given\.$#'
167+
identifier: argument.type
168+
count: 2
169+
path: src/Services/AttributeVersionResolver.php
170+
171+
-
172+
message: '#^Parameter \#2 \.\.\.\$arrays of function array_merge expects array, mixed given\.$#'
173+
identifier: argument.type
174+
count: 1
175+
path: src/Services/AttributeVersionResolver.php
176+
177+
-
178+
message: '#^Match arm comparison between ''\='' and ''\='' is always true\.$#'
179+
identifier: match.alwaysTrue
180+
count: 1
181+
path: src/Services/VersionComparator.php
182+
183+
-
184+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:getHighest\(\) has parameter \$versions with no value type specified in iterable type array\.$#'
185+
identifier: missingType.iterableValue
186+
count: 1
187+
path: src/Services/VersionComparator.php
188+
189+
-
190+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:getHighest\(\) should return string\|null but returns mixed\.$#'
191+
identifier: return.type
192+
count: 1
193+
path: src/Services/VersionComparator.php
194+
195+
-
196+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:getLowest\(\) has parameter \$versions with no value type specified in iterable type array\.$#'
197+
identifier: missingType.iterableValue
198+
count: 1
199+
path: src/Services/VersionComparator.php
200+
201+
-
202+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:getLowest\(\) should return string\|null but returns mixed\.$#'
203+
identifier: return.type
204+
count: 1
205+
path: src/Services/VersionComparator.php
206+
207+
-
208+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:sort\(\) has parameter \$versions with no value type specified in iterable type array\.$#'
209+
identifier: missingType.iterableValue
210+
count: 1
211+
path: src/Services/VersionComparator.php
212+
213+
-
214+
message: '#^Method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:sort\(\) should return array\<string\> but returns list\.$#'
215+
identifier: return.type
216+
count: 1
217+
path: src/Services/VersionComparator.php
218+
219+
-
220+
message: '#^Offset 0 on non\-empty\-list\<string\> on left side of \?\? always exists and is not nullable\.$#'
221+
identifier: nullCoalesce.offset
222+
count: 2
223+
path: src/Services/VersionComparator.php
224+
225+
-
226+
message: '#^Only booleans are allowed in an if condition, int\|false given\.$#'
227+
identifier: if.condNotBoolean
228+
count: 1
229+
path: src/Services/VersionComparator.php
230+
231+
-
232+
message: '#^Parameter \#1 \$version1 of method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:compare\(\) expects string, mixed given\.$#'
233+
identifier: argument.type
234+
count: 4
235+
path: src/Services/VersionComparator.php
236+
237+
-
238+
message: '#^Parameter \#2 \$version2 of method ShahGhasiAdil\\LaravelApiVersioning\\Services\\VersionComparator\:\:compare\(\) expects string, mixed given\.$#'
239+
identifier: argument.type
240+
count: 4
241+
path: src/Services/VersionComparator.php
242+
243+
-
244+
message: '#^Call to function is_array\(\) with array\<string, mixed\> will always evaluate to true\.$#'
245+
identifier: function.alreadyNarrowedType
246+
count: 1
247+
path: src/Services/VersionConfigService.php
248+
249+
-
250+
message: '#^Cannot cast mixed to string\.$#'
251+
identifier: cast.string
252+
count: 2
253+
path: src/Services/VersionManager.php

phpstan.neon.dist

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ includes:
22
- phpstan-baseline.neon
33

44
parameters:
5-
level: 5
5+
level: max
66
paths:
77
- src
8+
excludePaths:
9+
- src/Examples
810
tmpDir: build/phpstan
911
checkOctaneCompatibility: true
1012
checkModelProperties: true

src/ApiVersioningServiceProvider.php

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,39 @@ public function register(): void
2626
'api-versioning'
2727
);
2828

29-
$this->app->singleton(VersionManager::class, function ($app): VersionManager {
30-
return new VersionManager($app['config']->get('api-versioning', []));
29+
$this->app->singleton(VersionManager::class, function (\Illuminate\Contracts\Foundation\Application $app): VersionManager {
30+
/** @var \Illuminate\Config\Repository $configRepo */
31+
$configRepo = $app->make('config');
32+
/** @var array<string, mixed> $config */
33+
$config = $configRepo->get('api-versioning', []);
34+
35+
return new VersionManager($config);
3136
});
3237

33-
$this->app->singleton(AttributeCacheService::class, function ($app): AttributeCacheService {
34-
$config = $app['config']->get('api-versioning.cache', []);
38+
$this->app->singleton(AttributeCacheService::class, function (\Illuminate\Contracts\Foundation\Application $app): AttributeCacheService {
39+
/** @var \Illuminate\Config\Repository $configRepo */
40+
$configRepo = $app->make('config');
41+
/** @var array{enabled?: bool|string, ttl?: int|string} $config */
42+
$config = $configRepo->get('api-versioning.cache', []);
3543

3644
return new AttributeCacheService(
37-
enabled: $config['enabled'] ?? true,
45+
enabled: (bool) ($config['enabled'] ?? true),
3846
ttl: (int) ($config['ttl'] ?? 3600)
3947
);
4048
});
4149

42-
$this->app->singleton(AttributeVersionResolver::class, function ($app): AttributeVersionResolver {
50+
$this->app->singleton(AttributeVersionResolver::class, function (\Illuminate\Contracts\Foundation\Application $app): AttributeVersionResolver {
4351
return new AttributeVersionResolver(
4452
$app->make(VersionManager::class),
4553
$app->make(AttributeCacheService::class)
4654
);
4755
});
4856

49-
$this->app->singleton(VersionConfigService::class, function ($app): VersionConfigService {
57+
$this->app->singleton(VersionConfigService::class, function (\Illuminate\Contracts\Foundation\Application $app): VersionConfigService {
5058
return new VersionConfigService;
5159
});
5260

53-
$this->app->singleton(VersionComparator::class, function ($app): VersionComparator {
61+
$this->app->singleton(VersionComparator::class, function (\Illuminate\Contracts\Foundation\Application $app): VersionComparator {
5462
return new VersionComparator;
5563
});
5664
}
@@ -61,7 +69,9 @@ public function boot(): void
6169
__DIR__.'/../config/api-versioning.php' => config_path('api-versioning.php'),
6270
], 'config');
6371

64-
$this->app['router']->aliasMiddleware('api.version', AttributeApiVersionMiddleware::class);
72+
/** @var \Illuminate\Routing\Router $router */
73+
$router = $this->app->make('router');
74+
$router->aliasMiddleware('api.version', AttributeApiVersionMiddleware::class);
6575

6676
if ($this->app->runningInConsole()) {
6777
$this->commands([

src/Console/Commands/ApiVersionConfigCommand.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ public function __construct(
2424

2525
public function handle(): int
2626
{
27-
if ($this->option('show')) {
27+
if ((bool) $this->option('show')) {
2828
$this->showConfiguration();
2929

3030
return self::SUCCESS;
3131
}
3232

33+
/** @var string|null $addVersion */
3334
$addVersion = $this->option('add-version');
34-
if (is_string($addVersion)) {
35+
if (is_string($addVersion) && $addVersion !== '') {
3536
$this->addVersionMapping($addVersion);
3637

3738
return self::SUCCESS;
@@ -72,9 +73,13 @@ private function showConfiguration(): void
7273

7374
private function addVersionMapping(string $version): void
7475
{
75-
$method = $this->option('method');
76-
if (! is_string($method)) {
76+
/** @var string|null $methodOption */
77+
$methodOption = $this->option('method');
78+
if (! is_string($methodOption)) {
79+
/** @var string|null $method */
7780
$method = $this->ask('Method name for version '.$version);
81+
} else {
82+
$method = $methodOption;
7883
}
7984

8085
if (! is_string($method) || $method === '') {

src/Console/Commands/ApiVersionHealthCommand.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,21 @@ public function handle(): int
5050

5151
// Check 3: Detection methods
5252
$detectionMethods = $this->versionManager->getDetectionMethods();
53-
$enabledMethods = array_filter($detectionMethods, fn ($config) => $config['enabled'] ?? false);
53+
$enabledMethods = array_filter($detectionMethods, function (array $config): bool {
54+
return (bool) ($config['enabled'] ?? false);
55+
});
5456
if ($enabledMethods === []) {
5557
$this->components->warn('⚠ No detection methods enabled');
5658
} else {
5759
$this->components->info('✓ Enabled detection methods: '.implode(', ', array_keys($enabledMethods)));
5860
}
5961

6062
// Check 4: Routes with version attributes
61-
$routes = collect($this->router->getRoutes());
62-
$versionedRoutes = $routes->filter(function ($route) {
63+
$allRoutes = $this->router->getRoutes();
64+
/** @var \Illuminate\Routing\Route[] $routeArray */
65+
$routeArray = iterator_to_array($allRoutes, false);
66+
$routes = collect($routeArray);
67+
$versionedRoutes = $routes->filter(function (\Illuminate\Routing\Route $route): bool {
6368
$versions = $this->resolver->getAllVersionsForRoute($route);
6469

6570
return $versions !== [];
@@ -91,6 +96,7 @@ public function handle(): int
9196
}
9297

9398
// Check 6: Cache configuration
99+
/** @var bool $cacheEnabled */
94100
$cacheEnabled = config('api-versioning.cache.enabled', true);
95101
if ($cacheEnabled) {
96102
$this->components->info('✓ Attribute caching enabled');

0 commit comments

Comments
 (0)