-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from worksome/prevent_resource
Adds a new rule for disabling route resource partials
- Loading branch information
Showing
13 changed files
with
324 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
src/PHPStan/Laravel/DisallowPartialRouteResource/DisallowPartialRouteFacadeResourceRule.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
namespace Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource; | ||
|
||
use Illuminate\Support\Facades\Route; | ||
use PhpParser\Node; | ||
use PhpParser\Node\Expr\StaticCall; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Rules\Rule; | ||
use PHPStan\Rules\RuleError; | ||
|
||
/** | ||
* @implements Rule<Node\Expr\StaticCall> | ||
*/ | ||
class DisallowPartialRouteFacadeResourceRule implements Rule | ||
{ | ||
public function __construct(private PartialRouteResourceInspector $inspector) | ||
{ | ||
} | ||
|
||
public function getNodeType(): string | ||
{ | ||
return Node\Expr\StaticCall::class; | ||
} | ||
|
||
/** | ||
* @param Node\Expr\StaticCall $node | ||
* @return RuleError[] | ||
*/ | ||
public function processNode(Node $node, Scope $scope): array | ||
{ | ||
if (! $this->inspector->isApplicable($node)) { | ||
return []; | ||
} | ||
|
||
if (! $this->isCalledOnRouteFacade($node)) { | ||
return []; | ||
} | ||
|
||
return $this->inspector->inspect($node); | ||
} | ||
|
||
private function isCalledOnRouteFacade(Node $node): bool | ||
{ | ||
if (! $node instanceof StaticCall) { | ||
return false; | ||
} | ||
|
||
return $node->class->toString() === Route::class; | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...PHPStan/Laravel/DisallowPartialRouteResource/DisallowPartialRouteVariableResourceRule.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
|
||
namespace Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource; | ||
|
||
use Illuminate\Support\Facades\Route; | ||
use PhpParser\Node; | ||
use PhpParser\Node\Expr\MethodCall; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Rules\Rule; | ||
|
||
/** | ||
* @implements Rule<Node\Expr\MethodCall> | ||
*/ | ||
class DisallowPartialRouteVariableResourceRule implements Rule | ||
{ | ||
public function __construct(private PartialRouteResourceInspector $inspector) | ||
{ | ||
} | ||
|
||
public function getNodeType(): string | ||
{ | ||
return Node\Expr\MethodCall::class; | ||
} | ||
|
||
/** | ||
* @param Node\Expr\MethodCall $node | ||
* @return RuleError[] | ||
*/ | ||
public function processNode(Node $node, Scope $scope): array | ||
{ | ||
if (! $this->inspector->isApplicable($node)) { | ||
return []; | ||
} | ||
|
||
if (! $this->isCalledInRouteGroupClosure($node, $scope)) { | ||
return []; | ||
} | ||
|
||
return $this->inspector->inspect($node); | ||
} | ||
|
||
private function isCalledInRouteGroupClosure(Node\Expr\CallLike $node, Scope $scope): bool | ||
{ | ||
if (! $node instanceof MethodCall) { | ||
return false; | ||
} | ||
|
||
if (! $scope->isInAnonymousFunction()) { | ||
return false; | ||
} | ||
|
||
$parent = $node->getAttribute('parent'); | ||
|
||
while ($parent !== null) { | ||
if ($parent instanceof Node\Expr\StaticCall) { | ||
return $parent->class->toString() === Route::class; | ||
} | ||
|
||
$parent = $parent->getAttribute('parent'); | ||
} | ||
|
||
return false; | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
src/PHPStan/Laravel/DisallowPartialRouteResource/PartialRouteResourceInspector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
|
||
namespace Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Rules\RuleError; | ||
use PHPStan\Rules\RuleErrorBuilder; | ||
|
||
final class PartialRouteResourceInspector | ||
{ | ||
/** | ||
* @var string[] | ||
*/ | ||
private array $resourceMethods = [ | ||
'resource', | ||
'apiResource', | ||
]; | ||
|
||
/** | ||
* @var string[] | ||
*/ | ||
private array $partialMethods = [ | ||
'except', | ||
'only', | ||
]; | ||
|
||
public function isApplicable(Node $node): bool | ||
{ | ||
if (! $node instanceof Node\Expr\CallLike) { | ||
return false; | ||
} | ||
|
||
if (! in_array($node->name->name, $this->resourceMethods)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public function inspect(Node $node): array | ||
{ | ||
$next = $node->getAttribute('next'); | ||
|
||
while ($next !== null) { | ||
if (in_array($next->name, $this->partialMethods)) { | ||
return [$this->errorFor($next->name)]; | ||
} | ||
|
||
$next = $next->getAttribute('parent')->getAttribute('next'); | ||
} | ||
|
||
return []; | ||
} | ||
|
||
private function errorFor(string $method): RuleError | ||
{ | ||
return RuleErrorBuilder::message( | ||
"Usage of [{$method}] method on route resource is disallowed. Please split the resource into multiple routes." | ||
)->build(); | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...PHPStan/Laravel/DisallowPartialRouteResourceRule/DisallowPartialRouteResourceRuleTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
|
||
use Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource\DisallowPartialRouteFacadeResourceRule; | ||
use Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource\DisallowPartialRouteVariableResourceRule; | ||
use Worksome\CodingStyle\PHPStan\Laravel\DisallowPartialRouteResource\PartialRouteResourceInspector; | ||
|
||
it('checks for partial route facade resources', function (string $path, array ...$errors) { | ||
$this->rule = new DisallowPartialRouteFacadeResourceRule(new PartialRouteResourceInspector()); | ||
|
||
expect($path)->toHaveRuleErrors($errors); | ||
})->with([ | ||
'calls route resource with except' => [ | ||
__DIR__ . '/Fixture/route_resource_with_except.php.inc', | ||
[ | ||
'Usage of [except] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
5 | ||
] | ||
], | ||
'calls route resource with only' => [ | ||
__DIR__ . '/Fixture/route_resource_with_only.php.inc', | ||
[ | ||
'Usage of [only] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
5 | ||
] | ||
], | ||
'calls API route resource with except' => [ | ||
__DIR__ . '/Fixture/api_route_resource_with_except.php.inc', | ||
[ | ||
'Usage of [except] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
5 | ||
] | ||
], | ||
'calls except at end of method chain' => [ | ||
__DIR__ . '/Fixture/route_resource_with_except_after_after_chain.php.inc', | ||
[ | ||
'Usage of [except] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
5 | ||
] | ||
], | ||
'calls complete route resource' => [ | ||
__DIR__ . '/Fixture/route_resource.php.inc' | ||
], | ||
]); | ||
|
||
it('checks for partial route variable resources', function (string $path, array ...$errors) { | ||
$this->rule = new DisallowPartialRouteVariableResourceRule(new PartialRouteResourceInspector()); | ||
|
||
expect($path)->toHaveRuleErrors($errors); | ||
})->with([ | ||
'calls grouped resource' => [ | ||
__DIR__ . '/Fixture/grouped_route_resource_with_except.php.inc', | ||
[ | ||
'Usage of [except] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
6 | ||
], | ||
[ | ||
'Usage of [only] method on route resource is disallowed. Please split the resource into multiple routes.', | ||
7 | ||
] | ||
], | ||
'calls complete route resource' => [ | ||
__DIR__ . '/Fixture/route_resource.php.inc', | ||
], | ||
]); |
5 changes: 5 additions & 0 deletions
5
...n/Laravel/DisallowPartialRouteResourceRule/Fixture/api_route_resource_with_except.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
Route::apiResource('foo', 'FooController')->except(['show']); |
11 changes: 11 additions & 0 deletions
11
...ravel/DisallowPartialRouteResourceRule/Fixture/grouped_route_resource_with_except.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
Route::group([], function ($router) { | ||
$router->resource('foo', 'FooController')->except(['show']); | ||
$router->resource('bar', 'BarController')->only(['show']); | ||
}); | ||
|
||
// Some other method call to make sure everything still works | ||
$router->resource('baz', 'BazController'); |
33 changes: 33 additions & 0 deletions
33
tests/PHPStan/Laravel/DisallowPartialRouteResourceRule/Fixture/route_resource.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
/** | ||
* All the following examples should be allowed | ||
* as they are not partial route resources. | ||
*/ | ||
|
||
Route::resource('foo', 'FooController'); | ||
|
||
Route::resource('bar', 'BarController')->shallow(); | ||
|
||
Route::apiResource('baz', 'BazController'); | ||
|
||
Route::apiResource('bam', 'BamController')->shallow(); | ||
|
||
Route::resource('qux', 'QuxController')->names([ | ||
'index' => 'qux.list' | ||
]); | ||
|
||
Route::resource('blogs', 'BlogController')->parameters([ | ||
'blogs' => 'post' | ||
]); | ||
|
||
Route::resource('photos.comments', 'PhotoCommentController')->scoped([ | ||
'comment' => 'slug', | ||
]); | ||
|
||
Route::group([], function ($router) { | ||
$router->resource('photos', 'PhotoController')->scoped(); | ||
$router->apiResource('books', 'BookController')->scoped(); | ||
}); |
5 changes: 5 additions & 0 deletions
5
...PStan/Laravel/DisallowPartialRouteResourceRule/Fixture/route_resource_with_except.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
Route::resource('foo', 'FooController')->except(['show']); |
5 changes: 5 additions & 0 deletions
5
...llowPartialRouteResourceRule/Fixture/route_resource_with_except_after_after_chain.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
Route::resource('foo', 'FooController')->shallow()->except(['show']); |
5 changes: 5 additions & 0 deletions
5
...PHPStan/Laravel/DisallowPartialRouteResourceRule/Fixture/route_resource_with_only.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Route; | ||
|
||
Route::resource('foo', 'FooController')->only(['show', 'update']); |