Skip to content

Commit 03b5619

Browse files
committed
#103127
1 parent 2dd4b4e commit 03b5619

File tree

6 files changed

+141
-1
lines changed

6 files changed

+141
-1
lines changed

config/openapi-server-generator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use Ensi\LaravelOpenApiServerGenerator\Generators\ControllersGenerator;
44
use Ensi\LaravelOpenApiServerGenerator\Generators\EnumsGenerator;
55
use Ensi\LaravelOpenApiServerGenerator\Generators\PestTestsGenerator;
6+
use Ensi\LaravelOpenApiServerGenerator\Generators\PoliciesGenerator;
67
use Ensi\LaravelOpenApiServerGenerator\Generators\RequestsGenerator;
78
use Ensi\LaravelOpenApiServerGenerator\Generators\ResourcesGenerator;
89
use Ensi\LaravelOpenApiServerGenerator\Generators\RoutesGenerator;
@@ -37,6 +38,9 @@
3738
'resources' => [
3839
'response_key' => 'data',
3940
],
41+
'policies' => [
42+
'namespace' => ["Controllers" => "Policies"],
43+
],
4044
],
4145
],
4246

@@ -57,6 +61,7 @@
5761
'routes' => RoutesGenerator::class,
5862
'pest_tests' => PestTestsGenerator::class,
5963
'resources' => ResourcesGenerator::class,
64+
'policies' => PoliciesGenerator::class,
6065
],
6166

6267
/**
@@ -69,6 +74,7 @@
6974
'routes',
7075
'pest_tests',
7176
'resources',
77+
'policies',
7278
],
7379

7480
'extra_templates_path' => resource_path('openapi-server-generator/templates'),

src/Commands/GenerateServer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class GenerateServer extends Command
1414
protected $signature = 'openapi:generate-server {--e|entities=}';
1515

1616
/** var @string */
17-
protected $description = 'Generate application files from openapi specification files';
17+
protected $description = 'Generate application files from openapi specification files [with policies]';
1818

1919
private array $config = [];
2020

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
namespace Ensi\LaravelOpenApiServerGenerator\Generators;
4+
5+
use cebe\openapi\SpecObjectInterface;
6+
use RuntimeException;
7+
8+
class PoliciesGenerator extends BaseGenerator implements GeneratorInterface
9+
{
10+
public function generate(SpecObjectInterface $specObject): void
11+
{
12+
$policies = $this->extractPolicies($specObject);
13+
$this->createPoliciesFiles($policies, $this->templatesManager->getTemplate('Policy.template'));
14+
}
15+
16+
// TODO: предварительная версия, необходим рефакторинг и доп. проверки
17+
protected function extractPolicies(SpecObjectInterface $specObject): array
18+
{
19+
$openApiData = $specObject->getSerializableData();
20+
21+
$policies = [];
22+
$paths = $openApiData->paths ?: [];
23+
foreach ($paths as $routes) {
24+
foreach ($routes as $route) {
25+
if (!empty($route->{'x-lg-skip-policy-generation'})) {
26+
continue;
27+
}
28+
29+
if (empty($route->{'x-lg-handler'})) {
30+
continue;
31+
}
32+
33+
$response = $route->responses->{403} ?? null;
34+
if (!$response) {
35+
continue;
36+
}
37+
38+
$handler = $this->routeHandlerParser->parse($route->{'x-lg-handler'});
39+
40+
try {
41+
$namespace = $this->getReplacedNamespace($handler->namespace, 'Controllers', 'Policies');
42+
$className = $handler->class . 'Policy';
43+
} catch (RuntimeException) {
44+
continue;
45+
}
46+
47+
if (empty($handler->method)) {
48+
continue;
49+
}
50+
51+
if (isset($policies["$namespace\\$className"])) {
52+
$policies["$namespace\\$className"]['methods'][] = $handler->method;
53+
} else {
54+
$methods = [$handler->method];
55+
$policies["$namespace\\$className"] = compact('className', 'namespace', 'methods');
56+
}
57+
}
58+
}
59+
60+
return $policies;
61+
}
62+
63+
// TODO: протестировать
64+
protected function createPoliciesFiles(array $policies, string $template): void
65+
{
66+
foreach ($policies as ['className' => $className, 'namespace' => $namespace, 'methods' => $methods]) {
67+
$filePath = $this->getNamespacedFilePath($className, $namespace);
68+
if ($this->filesystem->exists($filePath)) {
69+
continue;
70+
}
71+
72+
$this->filesystem->put(
73+
$filePath,
74+
$this->replacePlaceholders($template, [
75+
'{{ namespace }}' => $namespace,
76+
'{{ className }}' => $className,
77+
'{{ methods }}' => $this->convertToString($methods),
78+
])
79+
);
80+
81+
die();
82+
}
83+
}
84+
85+
private function convertToString(array $methods): string
86+
{
87+
$methodsStrings = [];
88+
89+
foreach ($methods as $method) {
90+
$methodsStrings[] = $this->replacePlaceholders(
91+
$this->templatesManager->getTemplate('PolicyGate.template'),
92+
[
93+
'{{ method }}' => $method,
94+
]
95+
);
96+
}
97+
98+
return implode("\n\n ", $methodsStrings);
99+
}
100+
}

templates/Policy.template

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace {{ namespace }};
4+
5+
use App\Domain\Auth\Models\User;
6+
use Ensi\AdminAuthClient\Dto\RightsAccessEnum;
7+
use Illuminate\Auth\Access\HandlesAuthorization;
8+
use Illuminate\Auth\Access\Response;
9+
10+
class {{ className }}
11+
{
12+
use HandlesAuthorization;
13+
14+
{{ methods }}
15+
}

templates/PolicyGate.template

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

tests/PolicyGenerationTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Ensi\LaravelOpenApiServerGenerator\Commands\GenerateServer;
4+
use Ensi\LaravelOpenApiServerGenerator\Tests\TestCase;
5+
use Illuminate\Filesystem\Filesystem;
6+
use Illuminate\Support\Facades\Config;
7+
8+
use function Pest\Laravel\artisan;
9+
use function PHPUnit\Framework\assertEqualsCanonicalizing;
10+
11+
test('can generate policy', function () {
12+
\PHPUnit\Framework\assertIsBool(true);
13+
});

0 commit comments

Comments
 (0)