Skip to content

Commit ddfc44f

Browse files
Generate resources and specific API actions (#93)
1 parent 0ff38dd commit ddfc44f

File tree

15 files changed

+642
-16
lines changed

15 files changed

+642
-16
lines changed

src/BlueprintServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ function ($app) {
6868
$blueprint->registerGenerator(new \Blueprint\Generators\ControllerGenerator($app['files']));
6969
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\EventGenerator($app['files']));
7070
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\FormRequestGenerator($app['files']));
71+
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\ResourceGenerator($app['files']));
7172
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\JobGenerator($app['files']));
7273
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\MailGenerator($app['files']));
7374
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\ViewGenerator($app['files']));

src/Generators/ControllerGenerator.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Blueprint\Models\Statements\QueryStatement;
1212
use Blueprint\Models\Statements\RedirectStatement;
1313
use Blueprint\Models\Statements\RenderStatement;
14+
use Blueprint\Models\Statements\ResourceStatement;
1415
use Blueprint\Models\Statements\RespondStatement;
1516
use Blueprint\Models\Statements\SendStatement;
1617
use Blueprint\Models\Statements\SessionStatement;
@@ -116,6 +117,19 @@ private function buildMethods(Controller $controller)
116117
$this->addImport($controller, config('blueprint.namespace') . '\\Events\\' . $statement->event());
117118
}
118119
} elseif ($statement instanceof RenderStatement) {
120+
$body .= self::INDENT . $statement->output() . PHP_EOL;
121+
} elseif ($statement instanceof ResourceStatement) {
122+
$fqcn = config('blueprint.namespace') . '\\Http\\Resources\\' . ($controller->namespace() ? $controller->namespace() . '\\' : '') . $statement->name();
123+
124+
$method = str_replace('* @return \\Illuminate\\Http\\Response', '* @return \\' . $fqcn, $method);
125+
126+
$import = $fqcn;
127+
if (!$statement->collection()) {
128+
$import .= ' as ' . $statement->name() . 'Resource';
129+
}
130+
131+
$this->addImport($controller, $import);
132+
119133
$body .= self::INDENT . $statement->output() . PHP_EOL;
120134
} elseif ($statement instanceof RedirectStatement) {
121135
$body .= self::INDENT . $statement->output() . PHP_EOL;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace Blueprint\Generators\Statements;
4+
5+
use Blueprint\Contracts\Generator;
6+
use Blueprint\Models\Controller;
7+
use Blueprint\Models\Statements\ResourceStatement;
8+
9+
class ResourceGenerator implements Generator
10+
{
11+
/**
12+
* @var \Illuminate\Contracts\Filesystem\Filesystem
13+
*/
14+
private $files;
15+
16+
private $models = [];
17+
18+
public function __construct($files)
19+
{
20+
$this->files = $files;
21+
}
22+
23+
public function output(array $tree): array
24+
{
25+
$output = [];
26+
27+
$stub = $this->files->stub('resource.stub');
28+
29+
/** @var \Blueprint\Models\Controller $controller */
30+
foreach ($tree['controllers'] as $controller) {
31+
foreach ($controller->methods() as $method => $statements) {
32+
foreach ($statements as $statement) {
33+
if (!$statement instanceof ResourceStatement) {
34+
continue;
35+
}
36+
37+
$path = $this->getPath($statement->name());
38+
39+
if ($this->files->exists($path)) {
40+
continue;
41+
}
42+
43+
if (!$this->files->exists(dirname($path))) {
44+
$this->files->makeDirectory(dirname($path), 0755, true);
45+
}
46+
47+
$this->files->put($path, $this->populateStub($stub, $statement));
48+
49+
$output['created'][] = $path;
50+
}
51+
}
52+
}
53+
54+
return $output;
55+
}
56+
57+
protected function getPath(string $name)
58+
{
59+
return config('blueprint.app_path') . '/Http/Resources/' . $name . '.php';
60+
}
61+
62+
protected function populateStub(string $stub, ResourceStatement $resource)
63+
{
64+
$stub = str_replace('DummyNamespace', config('blueprint.namespace') . '\\Http\\Resources', $stub);
65+
$stub = str_replace('DummyImport', $resource->collection() ? 'Illuminate\\Http\\Resources\\Json\\ResourceCollection' : 'Illuminate\\Http\\Resources\\Json\\JsonResource', $stub);
66+
$stub = str_replace('DummyParent', $resource->collection() ? 'ResourceCollection' : 'JsonResource', $stub);
67+
$stub = str_replace('DummyClass', $resource->name(), $stub);
68+
$stub = str_replace('DummyParent', $resource->collection() ? 'ResourceCollection' : 'JsonResource', $stub);
69+
$stub = str_replace('DummyItem', $resource->collection() ? 'resource collection' : 'resource', $stub);
70+
$stub = str_replace('// data...', $this->buildData($resource), $stub);
71+
72+
return $stub;
73+
}
74+
75+
private function buildData(ResourceStatement $resource)
76+
{
77+
if ($resource->collection()) {
78+
return 'return [
79+
\'data\' => $this->collection,
80+
];';
81+
}
82+
83+
return 'return [
84+
\'id\' => $this->id,
85+
];';
86+
}
87+
}

src/Lexers/ControllerLexer.php

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ public function analyze(array $tokens): array
3030
$controller = new Controller($name);
3131

3232
if ($this->isResource($definition)) {
33+
$original = $definition;
3334
$definition = $this->generateResourceTokens($controller, $this->methodsForResource($definition['resource']));
35+
// unset shorthand
36+
unset($original['resource']);
37+
// this gives the ability to both use a shorthand and override some methods
38+
$definition = array_merge($definition, $original);
3439
}
3540

3641
foreach ($definition as $method => $body) {
@@ -54,17 +59,18 @@ private function generateResourceTokens(Controller $controller, array $methods)
5459
->filter(function ($statements, $method) use ($methods) {
5560
return in_array($method, $methods);
5661
})
57-
->map(function ($statements) use ($controller) {
58-
return collect($statements)
59-
->map(function ($statement) use ($controller) {
62+
->mapWithKeys(function ($statements, $method) use ($controller) {
63+
return [
64+
str_replace('api.', '', $method) => collect($statements)->map(function ($statement) use ($controller) {
6065
$model = Str::singular($controller->prefix());
6166

6267
return str_replace(
6368
['[singular]', '[plural]'],
6469
[Str::lower($model), Str::lower(Str::plural($model))],
6570
$statement
6671
);
67-
});
72+
}),
73+
];
6874
})
6975
->toArray();
7076
}
@@ -74,40 +80,62 @@ private function resourceTokens()
7480
return [
7581
'index' => [
7682
'query' => 'all:[plural]',
77-
'render' => '[singular].index with [plural]'
83+
'render' => '[singular].index with [plural]',
7884
],
7985
'create' => [
80-
'render' => '[singular].create'
86+
'render' => '[singular].create',
8187
],
8288
'store' => [
8389
'validate' => '[singular]',
8490
'save' => '[singular]',
8591
'flash' => '[singular].id',
86-
'redirect' => '[singular].index'
92+
'redirect' => '[singular].index',
8793
],
8894
'show' => [
89-
'render' => '[singular].show with:[singular]'
95+
'render' => '[singular].show with:[singular]',
9096
],
9197
'edit' => [
92-
'render' => '[singular].edit with:[singular]'
98+
'render' => '[singular].edit with:[singular]',
9399
],
94100
'update' => [
95101
'validate' => '[singular]',
96102
'update' => '[singular]',
97103
'flash' => '[singular].id',
98-
'redirect' => '[singular].index'
104+
'redirect' => '[singular].index',
99105
],
100106
'destroy' => [
101107
'delete' => '[singular]',
102-
'redirect' => '[singular].index'
103-
]
108+
'redirect' => '[singular].index',
109+
],
110+
111+
'api.index' => [
112+
'query' => 'all:[plural]',
113+
'resource' => 'collection:[plural]',
114+
],
115+
'api.store' => [
116+
'validate' => '[singular]',
117+
'save' => '[singular]',
118+
'resource' => '[singular]',
119+
],
120+
'api.show' => [
121+
'resource' => '[singular]',
122+
],
123+
'api.update' => [
124+
'validate' => '[singular]',
125+
'update' => '[singular]',
126+
'resource' => '[singular]',
127+
],
128+
'api.destroy' => [
129+
'delete' => '[singular]',
130+
'respond' => 200,
131+
],
104132
];
105133
}
106134

107135
private function methodsForResource(string $type)
108136
{
109137
if ($type === 'api') {
110-
return ['index', 'store', 'show', 'update', 'destroy'];
138+
return ['api.index', 'api.store', 'api.show', 'api.update', 'api.destroy'];
111139
}
112140

113141
if ($type === 'all') {

src/Lexers/StatementLexer.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Blueprint\Models\Statements\QueryStatement;
1111
use Blueprint\Models\Statements\RedirectStatement;
1212
use Blueprint\Models\Statements\RenderStatement;
13+
use Blueprint\Models\Statements\ResourceStatement;
1314
use Blueprint\Models\Statements\RespondStatement;
1415
use Blueprint\Models\Statements\SendStatement;
1516
use Blueprint\Models\Statements\SessionStatement;
@@ -48,6 +49,9 @@ public function analyze(array $tokens): array
4849
case 'respond':
4950
$statements[] = $this->analyzeRespond($statement);
5051
break;
52+
case 'resource':
53+
$statements[] = $this->analyzeResource($statement);
54+
break;
5155
case 'save':
5256
case 'update':
5357
case 'delete':
@@ -162,4 +166,17 @@ private function analyzeQuery($statement)
162166

163167
return new QueryStatement('get', $this->extractTokens($statement));
164168
}
169+
170+
private function analyzeResource($statement)
171+
{
172+
$reference = $statement;
173+
$collection = null;
174+
175+
if (Str::contains($statement, ':')) {
176+
$collection = Str::before($reference, ':');
177+
$reference = Str::after($reference, ':');
178+
}
179+
180+
return new ResourceStatement($reference, !is_null($collection), $collection === 'paginate');
181+
}
165182
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Blueprint\Models\Statements;
4+
5+
use Illuminate\Support\Str;
6+
7+
class ResourceStatement
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private $reference;
13+
14+
/**
15+
* @var bool
16+
*/
17+
private $collection = false;
18+
19+
/**
20+
* @var bool
21+
*/
22+
private $paginate = false;
23+
24+
public function __construct(string $reference, bool $collection = false, bool $paginate = false)
25+
{
26+
$this->reference = $reference;
27+
$this->collection = $collection;
28+
$this->paginate = $paginate;
29+
}
30+
31+
public function name(): string
32+
{
33+
if ($this->collection()) {
34+
return Str::studly(Str::singular($this->reference)) . 'Collection';
35+
}
36+
37+
return Str::studly(Str::singular($this->reference));
38+
}
39+
40+
public function reference(): string
41+
{
42+
return $this->reference;
43+
}
44+
45+
public function collection(): bool
46+
{
47+
return $this->collection;
48+
}
49+
50+
public function paginate(): bool
51+
{
52+
return $this->paginate;
53+
}
54+
55+
public function output(): string
56+
{
57+
$code = 'return new ' . $this->name();
58+
59+
if (!$this->collection()) {
60+
$code .= 'Resource';
61+
}
62+
63+
$code .= '($' . $this->reference();
64+
65+
if ($this->paginate()) {
66+
$code .= '->paginate()';
67+
}
68+
69+
$code .= ');';
70+
71+
return $code;
72+
}
73+
}

stubs/resource.stub

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace DummyNamespace;
4+
5+
use DummyImport;
6+
7+
class DummyClass extends DummyParent
8+
{
9+
/**
10+
* Transform the DummyItem into an array.
11+
*
12+
* @param \Illuminate\Http\Request $request
13+
* @return array
14+
*/
15+
public function toArray($request)
16+
{
17+
// data...
18+
}
19+
}

tests/Feature/Generator/ControllerGeneratorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public function controllerTreeDataProvider()
107107
['definitions/crazy-eloquent.bp', 'app/Http/Controllers/PostController.php', 'controllers/crazy-eloquent.php'],
108108
['definitions/nested-components.bp', 'app/Http/Controllers/Admin/UserController.php', 'controllers/nested-components.php'],
109109
['definitions/respond-statements.bp', 'app/Http/Controllers/Api/PostController.php', 'controllers/respond-statements.php'],
110+
['definitions/resource-statements.bp', 'app/Http/Controllers/UserController.php', 'controllers/resource-statements.php'],
110111
];
111112
}
112113
}

0 commit comments

Comments
 (0)