Skip to content

Commit 771d331

Browse files
committed
#103127 Refactoring, add tests & fix bugs
1 parent 03b5619 commit 771d331

File tree

6 files changed

+103
-33
lines changed

6 files changed

+103
-33
lines changed

src/Generators/PoliciesGenerator.php

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace Ensi\LaravelOpenApiServerGenerator\Generators;
44

55
use cebe\openapi\SpecObjectInterface;
6+
use Ensi\LaravelOpenApiServerGenerator\DTO\ParsedRouteHandler;
67
use RuntimeException;
8+
use stdClass;
79

810
class PoliciesGenerator extends BaseGenerator implements GeneratorInterface
911
{
@@ -13,7 +15,6 @@ public function generate(SpecObjectInterface $specObject): void
1315
$this->createPoliciesFiles($policies, $this->templatesManager->getTemplate('Policy.template'));
1416
}
1517

16-
// TODO: предварительная версия, необходим рефакторинг и доп. проверки
1718
protected function extractPolicies(SpecObjectInterface $specObject): array
1819
{
1920
$openApiData = $specObject->getSerializableData();
@@ -22,36 +23,31 @@ protected function extractPolicies(SpecObjectInterface $specObject): array
2223
$paths = $openApiData->paths ?: [];
2324
foreach ($paths as $routes) {
2425
foreach ($routes as $route) {
25-
if (!empty($route->{'x-lg-skip-policy-generation'})) {
26+
if (!$this->routeValidation($route)) {
2627
continue;
2728
}
2829

29-
if (empty($route->{'x-lg-handler'})) {
30-
continue;
31-
}
32-
33-
$response = $route->responses->{403} ?? null;
34-
if (!$response) {
30+
$handler = $this->routeHandlerParser->parse($route->{'x-lg-handler'});
31+
if (!$this->handlerValidation($handler)) {
3532
continue;
3633
}
3734

38-
$handler = $this->routeHandlerParser->parse($route->{'x-lg-handler'});
39-
4035
try {
41-
$namespace = $this->getReplacedNamespace($handler->namespace, 'Controllers', 'Policies');
42-
$className = $handler->class . 'Policy';
36+
$namespace = $this->getReplacedNamespace(
37+
$handler->namespace,
38+
'Controllers',
39+
'Policies'
40+
);
4341
} catch (RuntimeException) {
4442
continue;
4543
}
4644

47-
if (empty($handler->method)) {
48-
continue;
49-
}
45+
$className = $handler->class . 'Policy';
46+
$methods = [$handler->method];
5047

5148
if (isset($policies["$namespace\\$className"])) {
52-
$policies["$namespace\\$className"]['methods'][] = $handler->method;
49+
$policies["$namespace\\$className"]['methods'][] = $methods[0];
5350
} else {
54-
$methods = [$handler->method];
5551
$policies["$namespace\\$className"] = compact('className', 'namespace', 'methods');
5652
}
5753
}
@@ -60,7 +56,6 @@ protected function extractPolicies(SpecObjectInterface $specObject): array
6056
return $policies;
6157
}
6258

63-
// TODO: протестировать
6459
protected function createPoliciesFiles(array $policies, string $template): void
6560
{
6661
foreach ($policies as ['className' => $className, 'namespace' => $namespace, 'methods' => $methods]) {
@@ -74,24 +69,40 @@ protected function createPoliciesFiles(array $policies, string $template): void
7469
$this->replacePlaceholders($template, [
7570
'{{ namespace }}' => $namespace,
7671
'{{ className }}' => $className,
77-
'{{ methods }}' => $this->convertToString($methods),
72+
'{{ methods }}' => $this->convertMethodsToString($methods),
7873
])
7974
);
80-
81-
die();
8275
}
8376
}
8477

85-
private function convertToString(array $methods): string
78+
private function routeValidation(stdClass $route): bool
79+
{
80+
return match (true) {
81+
!empty($route->{'x-lg-skip-policy-generation'}),
82+
empty($route->{'x-lg-handler'}),
83+
empty($route->responses->{403}) => false,
84+
default => true
85+
};
86+
}
87+
88+
private function handlerValidation(ParsedRouteHandler $handler): bool
89+
{
90+
return match (true) {
91+
empty($handler->namespace),
92+
empty($handler->class),
93+
empty($handler->method) => false,
94+
default => true
95+
};
96+
}
97+
98+
private function convertMethodsToString(array $methods): string
8699
{
87100
$methodsStrings = [];
88101

89102
foreach ($methods as $method) {
90103
$methodsStrings[] = $this->replacePlaceholders(
91104
$this->templatesManager->getTemplate('PolicyGate.template'),
92-
[
93-
'{{ method }}' => $method,
94-
]
105+
['{{ method }}' => $method]
95106
);
96107
}
97108

templates/Policy.template

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
namespace {{ namespace }};
44

5-
use App\Domain\Auth\Models\User;
6-
use Ensi\AdminAuthClient\Dto\RightsAccessEnum;
5+
use App\Models\User;
76
use Illuminate\Auth\Access\HandlesAuthorization;
87
use Illuminate\Auth\Access\Response;
98

templates/PolicyGate.template

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
public function {{ method }}(User $user): Response
22
{
3-
return $user->allowOneOf([
4-
// add rights access from RightsAccessEnum
5-
]);
3+
return Response::allow();
64
}

tests/GenerateServerTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
$this->makeFilePath('/app/Http/Resources/ResourcesResource.php'),
5959
$this->makeFilePath('/app/Http/Resources/ResourcesDataDataResource.php'),
6060
$this->makeFilePath('/app/Http/Resources/ResourceRootResource.php'),
61+
62+
$this->makeFilePath('/app/Http/Controllers/PoliciesController.php'),
63+
$this->makeFilePath('/app/Http/Tests/PoliciesComponentTest.php'),
64+
$this->makeFilePath('/app/Http/Policies/PoliciesControllerPolicy.php'),
6165
], $putFiles);
6266
});
6367

tests/PolicyGenerationTest.php

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,41 @@
77

88
use function Pest\Laravel\artisan;
99
use function PHPUnit\Framework\assertEqualsCanonicalizing;
10+
use function PHPUnit\Framework\assertNotEqualsCanonicalizing;
1011

11-
test('can generate policy', function () {
12-
\PHPUnit\Framework\assertIsBool(true);
12+
test('Correct methods in generated policy', function () {
13+
/** @var TestCase $this */
14+
$mapping = Config::get('openapi-server-generator.api_docs_mappings');
15+
$mappingValue = current($mapping);
16+
$mapping = [$this->makeFilePath(__DIR__ . '/resources/index.yaml') => $mappingValue];
17+
Config::set('openapi-server-generator.api_docs_mappings', $mapping);
18+
19+
$filesystem = $this->mock(Filesystem::class);
20+
$filesystem->shouldReceive('exists')->andReturn(false);
21+
$filesystem->shouldReceive('get')->withArgs(function ($path) {
22+
return (bool)strstr($path, '.template');
23+
})->andReturnUsing(function ($path) {
24+
return file_get_contents($path);
25+
});
26+
$filesystem->shouldReceive('cleanDirectory', 'ensureDirectoryExists');
27+
28+
$policies = [];
29+
$filesystem->shouldReceive('put')->withArgs(function ($path, $content) use (&$policies) {
30+
if (str_contains($path, 'Policy.php')) {
31+
$policies[pathinfo($path, PATHINFO_BASENAME)] = $content;
32+
}
33+
34+
return true;
35+
});
36+
37+
artisan(GenerateServer::class);
38+
39+
foreach ($policies as $key => $content) {
40+
$methods = [];
41+
preg_match_all('~public function (.*)\(~', $content, $methods);
42+
$policies[$key] = $methods[1];
43+
}
44+
45+
assertEqualsCanonicalizing(['methodFoo', 'methodBar'], $policies['PoliciesControllerPolicy.php']);
46+
assertNotEqualsCanonicalizing(['methodWithoutForbiddenResponse'], $policies['PoliciesControllerPolicy.php']);
1347
});

tests/resources/index.yaml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ paths:
6060
x-lg-skip-controller-generation: true
6161
x-lg-skip-request-generation: true
6262
x-lg-skip-tests-generation: true
63+
x-lg-skip-policy-generation: true
6364
responses:
6465
"200":
6566
description: Успешный ответ
@@ -146,7 +147,30 @@ paths:
146147
application/json:
147148
schema:
148149
$ref: './schemas/test_resource_generation.yaml#/GenerateResourceWithoutPropertiesResponse'
149-
150+
/policies:test-generate-policy-method-foo:
151+
post:
152+
operationId: generatePolicyMethodFoo
153+
x-lg-handler: '\App\Http\Controllers\PoliciesController@methodFoo'
154+
x-lg-skip-request-generation: true
155+
responses:
156+
"403":
157+
description: Ошибка прав доступа
158+
/policies:test-generate-policy-method-bar:
159+
post:
160+
operationId: generatePolicyMethodBar
161+
x-lg-handler: '\App\Http\Controllers\PoliciesController@methodBar'
162+
x-lg-skip-request-generation: true
163+
responses:
164+
"403":
165+
description: Ошибка прав доступа
166+
/policies:test-generate-policy-method-without-forbidden-response:
167+
post:
168+
operationId: generatePolicyMethodWithoutForbiddenResponse
169+
x-lg-handler: '\App\Http\Controllers\PoliciesController@methodWithoutForbiddenResponse'
170+
x-lg-skip-request-generation: true
171+
responses:
172+
"200":
173+
description: Успешный ответ c контекстом
150174
components:
151175
responses:
152176
ServerError:

0 commit comments

Comments
 (0)