Skip to content

Commit eedca26

Browse files
authored
Add support for nested resource controllers (#725)
1 parent bcc2560 commit eedca26

17 files changed

+420
-1
lines changed

src/Generators/ControllerGenerator.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,21 @@ protected function buildMethods(Controller $controller): string
8282

8383
foreach ($controller->methods() as $name => $statements) {
8484
$method = str_replace('{{ method }}', $name, $template);
85+
$search = '(Request $request';
8586

8687
if (in_array($name, ['edit', 'update', 'show', 'destroy'])) {
8788
$reference = $this->fullyQualifyModelReference($controller->namespace(), $controllerModelName);
8889
$variable = '$' . Str::camel($controllerModelName);
8990

90-
$search = '(Request $request';
9191
$method = str_replace($search, $search . ', ' . $controllerModelName . ' ' . $variable, $method);
9292
$this->addImport($controller, $reference);
9393
}
9494

95+
if ($parent = $controller->parent()) {
96+
$method = str_replace($search, $search . ', ' . $parent . ' $' . Str::camel($parent), $method);
97+
$this->addImport($controller, $this->fullyQualifyModelReference($controller->namespace(), $parent));
98+
}
99+
95100
$body = '';
96101
$using_validation = false;
97102

@@ -181,6 +186,17 @@ protected function buildMethods(Controller $controller): string
181186
$this->addImport($controller, 'Inertia\Inertia');
182187
}
183188

189+
if (
190+
$controller->parent() &&
191+
($statement instanceof QueryStatement || $statement instanceof EloquentStatement || $statement instanceof ResourceStatement)
192+
) {
193+
$body = str_replace(
194+
['::all', Str::singular($controller->prefix()) . '::'],
195+
['::get', '$' . Str::lower($controller->parent()) . '->' . Str::plural(Str::lower($controller->prefix())) . '()->'],
196+
$body
197+
);
198+
}
199+
184200
$body .= PHP_EOL;
185201
}
186202

src/Generators/PestTestGenerator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ protected function buildTestCases(Controller $controller): string
115115
$setup['data'][] = sprintf('$%s = %s::factory()->create();', $variable, $model);
116116
}
117117

118+
if ($parent = $controller->parent()) {
119+
$this->addImport($controller, $modelNamespace . '\\' . $parent);
120+
$setup['data'][] = sprintf('$%s = %s::factory()->create();', Str::camel($parent), $parent);
121+
}
122+
118123
foreach ($statements as $statement) {
119124
if ($statement instanceof SendStatement) {
120125
if ($statement->isNotification()) {
@@ -496,6 +501,22 @@ protected function buildTestCases(Controller $controller): string
496501
}
497502
$call .= ')';
498503

504+
if ($controller->parent()) {
505+
$parent = Str::camel($controller->parent());
506+
$variable = Str::camel($context);
507+
$binding = sprintf(', $%s)', $variable);
508+
$params = sprintf("'%s' => $%s", $parent, $parent);
509+
510+
if (Str::contains($call, $binding)) {
511+
$params .= sprintf(", '%s' => $%s", $variable, $variable);
512+
$search = $binding;
513+
} else {
514+
$search = ')';
515+
}
516+
517+
$call = str_replace($search, sprintf(', [%s])', $params), $call);
518+
}
519+
499520
if ($request_data) {
500521
$call .= ', [';
501522
$call .= PHP_EOL;

src/Generators/PhpUnitTestGenerator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ protected function buildTestCases(Controller $controller): string
114114
$setup['data'][] = sprintf('$%s = %s::factory()->create();', $variable, $model);
115115
}
116116

117+
if ($parent = $controller->parent()) {
118+
$this->addImport($controller, $modelNamespace . '\\' . $parent);
119+
$setup['data'][] = sprintf('$%s = %s::factory()->create();', Str::camel($parent), $parent);
120+
}
121+
117122
foreach ($statements as $statement) {
118123
if ($statement instanceof SendStatement) {
119124
if ($statement->isNotification()) {
@@ -486,6 +491,22 @@ protected function buildTestCases(Controller $controller): string
486491
}
487492
$call .= ')';
488493

494+
if ($controller->parent()) {
495+
$parent = Str::camel($controller->parent());
496+
$variable = Str::camel($context);
497+
$binding = sprintf(', $%s)', $variable);
498+
$params = sprintf("'%s' => $%s", $parent, $parent);
499+
500+
if (Str::contains($call, $binding)) {
501+
$params .= sprintf(", '%s' => $%s", $variable, $variable);
502+
$search = $binding;
503+
} else {
504+
$search = ')';
505+
}
506+
507+
$call = str_replace($search, sprintf(', [%s])', $params), $call);
508+
}
509+
489510
if ($request_data) {
490511
$call .= ', [';
491512
$call .= PHP_EOL;

src/Generators/RouteGenerator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ protected function buildRoutes(Controller $controller): string
4545
$className = $this->getClassName($controller);
4646
$slug = config('blueprint.singular_routes') ? Str::kebab($controller->prefix()) : Str::plural(Str::kebab($controller->prefix()));
4747

48+
if ($controller->parent()) {
49+
$parentSlug = config('blueprint.singular_routes') ? Str::kebab($controller->parent()) : Str::plural(Str::kebab($controller->parent()));
50+
$parentBinding = '/{' . Str::kebab($controller->parent()) . '}/';
51+
$slug = $parentSlug . $parentBinding . $slug;
52+
}
53+
4854
foreach (array_diff($methods, Controller::$resourceMethods) as $method) {
4955
$routes .= $this->buildRouteLine($className, $slug, $method);
5056
$routes .= PHP_EOL;

src/Lexers/ControllerLexer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ public function analyze(array $tokens): array
7474
$registry['policies'][] = $policy;
7575
}
7676

77+
if (isset($definition['meta']['parent'])) {
78+
$controller->setParent($definition['meta']['parent']);
79+
}
80+
7781
unset($definition['meta']);
7882
}
7983

src/Models/Controller.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class Controller implements BlueprintModel
2121

2222
private bool $apiResource = false;
2323

24+
private ?string $parent = null;
25+
2426
public function __construct(string $name)
2527
{
2628
$this->name = class_basename($name);
@@ -103,4 +105,14 @@ public function isApiResource(): bool
103105
{
104106
return $this->apiResource;
105107
}
108+
109+
public function setParent(string $parent): void
110+
{
111+
$this->parent = Str::studly(Str::singular($parent));
112+
}
113+
114+
public function parent(): ?string
115+
{
116+
return $this->parent;
117+
}
106118
}

tests/Feature/Generators/ControllerGeneratorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ public static function controllerTreeDataProvider(): array
273273
['drafts/inertia-render.yaml', 'app/Http/Controllers/CustomerController.php', 'controllers/inertia-render.php'],
274274
['drafts/save-without-validation.yaml', 'app/Http/Controllers/PostController.php', 'controllers/save-without-validation.php'],
275275
['drafts/api-resource-pagination.yaml', 'app/Http/Controllers/PostController.php', 'controllers/api-resource-pagination.php'],
276+
['drafts/api-resource-nested.yaml', 'app/Http/Controllers/CommentController.php', 'controllers/api-resource-nested.php'],
276277
['drafts/api-routes-example.yaml', 'app/Http/Controllers/Api/CertificateController.php', 'controllers/api-routes-example.php'],
277278
['drafts/invokable-controller.yaml', 'app/Http/Controllers/ReportController.php', 'controllers/invokable-controller.php'],
278279
['drafts/invokable-controller-shorthand.yaml', 'app/Http/Controllers/ReportController.php', 'controllers/invokable-controller-shorthand.php'],

tests/Feature/Generators/PestTestGeneratorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ public static function controllerTreeDataProvider(): array
225225
['drafts/model-reference-validate.yaml', 'tests/Feature/Http/Controllers/CertificateControllerTest.php', 'tests/pest/api-shorthand-validation.php'],
226226
['drafts/controllers-only-no-context.yaml', 'tests/Feature/Http/Controllers/ReportControllerTest.php', 'tests/pest/controllers-only-no-context.php'],
227227
['drafts/date-formats.yaml', 'tests/Feature/Http/Controllers/DateControllerTest.php', 'tests/pest/date-formats.php'],
228+
['drafts/api-resource-nested.yaml', 'tests/Feature/Http/Controllers/CommentControllerTest.php', 'tests/pest/api-resource-nested.php'],
228229
['drafts/call-to-a-member-function-columns-on-null.yaml', [
229230
'tests/Feature/Http/Controllers/SubscriptionControllerTest.php',
230231
'tests/Feature/Http/Controllers/TelegramControllerTest.php',

tests/Feature/Generators/PhpUnitTestGeneratorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ public static function controllerTreeDataProvider(): array
226226
['drafts/controllers-only-no-context.yaml', 'tests/Feature/Http/Controllers/ReportControllerTest.php', 'tests/phpunit/controllers-only-no-context.php'],
227227
['drafts/date-formats.yaml', 'tests/Feature/Http/Controllers/DateControllerTest.php', 'tests/phpunit/date-formats.php'],
228228
['drafts/test-relationships.yaml', 'tests/Feature/Http/Controllers/ConferenceControllerTest.php', 'tests/phpunit/test-relationships.php'],
229+
['drafts/api-resource-nested.yaml', 'tests/Feature/Http/Controllers/CommentControllerTest.php', 'tests/phpunit/api-resource-nested.php'],
229230
['drafts/call-to-a-member-function-columns-on-null.yaml', [
230231
'tests/Feature/Http/Controllers/SubscriptionControllerTest.php',
231232
'tests/Feature/Http/Controllers/TelegramControllerTest.php',

tests/Feature/Generators/RouteGeneratorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public static function controllerTreeDataProvider(): array
119119
['drafts/respond-statements.yaml', 'routes/respond-statements.php'],
120120
['drafts/invokable-controller.yaml', 'routes/invokable-controller.php'],
121121
['drafts/invokable-controller-shorthand.yaml', 'routes/invokable-controller.php'],
122+
['drafts/controller-nested.yaml', 'routes/nested-controller.php'],
122123
];
123124
}
124125
}

0 commit comments

Comments
 (0)