Skip to content

Commit bd949ff

Browse files
committed
Support resource controller shorthand
1 parent 74f8c75 commit bd949ff

File tree

6 files changed

+270
-1
lines changed

6 files changed

+270
-1
lines changed

src/Blueprint.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public function parse($content)
2626
return $matches[1] . strtolower($matches[2]) . ': ' . $matches[2];
2727
}, $content);
2828

29+
$content = preg_replace_callback('/^(\s+)resource(: true)?$/mi', function ($matches) {
30+
return $matches[1] . 'resource: all';
31+
}, $content);
32+
2933
return Yaml::parse($content);
3034
}
3135

src/Lexers/ControllerLexer.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Blueprint\Contracts\Lexer;
66
use Blueprint\Models\Controller;
7+
use Illuminate\Support\Str;
78

89
class ControllerLexer implements Lexer
910
{
@@ -28,6 +29,10 @@ public function analyze(array $tokens): array
2829
foreach ($tokens['controllers'] as $name => $definition) {
2930
$controller = new Controller($name);
3031

32+
if ($this->isResource($definition)) {
33+
$definition = $this->generateResourceTokens($controller, $this->methodsForResource($definition['resource']));
34+
}
35+
3136
foreach ($definition as $method => $body) {
3237
$controller->addMethod($method, $this->statementLexer->analyze($body));
3338
}
@@ -37,4 +42,78 @@ public function analyze(array $tokens): array
3742

3843
return $registry;
3944
}
45+
46+
private function isResource(array $definition)
47+
{
48+
return isset($definition['resource']) && is_string($definition['resource']);
49+
}
50+
51+
private function generateResourceTokens(Controller $controller, array $methods)
52+
{
53+
return collect($this->resourceTokens())
54+
->filter(function ($statements, $method) use ($methods) {
55+
return in_array($method, $methods);
56+
})
57+
->map(function ($statements) use ($controller) {
58+
return collect($statements)
59+
->map(function ($statement) use ($controller) {
60+
$model = Str::singular($controller->prefix());
61+
62+
return str_replace(
63+
['[singular]', '[plural]'],
64+
[Str::lower($model), Str::lower(Str::plural($model))],
65+
$statement
66+
);
67+
});
68+
})
69+
->toArray();
70+
}
71+
72+
private function resourceTokens()
73+
{
74+
return [
75+
'index' => [
76+
'query' => 'all:[plural]',
77+
'render' => '[singular].index with [plural]'
78+
],
79+
'create' => [
80+
'render' => '[singular].create'
81+
],
82+
'store' => [
83+
'validate' => '[singular]',
84+
'save' => '[singular]',
85+
'flash' => '[singular].id',
86+
'redirect' => '[singular].index'
87+
],
88+
'show' => [
89+
'render' => '[singular].show with:[singular]'
90+
],
91+
'edit' => [
92+
'render' => '[singular].edit with:[singular]'
93+
],
94+
'update' => [
95+
'validate' => '[singular]',
96+
'update' => '[singular]',
97+
'flash' => '[singular].id',
98+
'redirect' => '[singular].index'
99+
],
100+
'destroy' => [
101+
'delete' => '[singular]',
102+
'redirect' => '[singular].index'
103+
]
104+
];
105+
}
106+
107+
private function methodsForResource(string $type)
108+
{
109+
if ($type === 'api') {
110+
return ['index', 'store', 'show', 'update', 'destroy'];
111+
}
112+
113+
if ($type === 'all') {
114+
return ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy'];
115+
}
116+
117+
return array_map('trim', explode(',', $type));
118+
}
40119
}

tests/Feature/BlueprintTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ public function it_parses_shorthands()
8787
'timestamps' => 'timestamps',
8888
],
8989
],
90+
'controllers' => [
91+
'Context' => [
92+
'resource' => 'all'
93+
]
94+
]
9095
], $this->subject->parse($blueprint));
9196
}
9297

@@ -131,6 +136,28 @@ public function it_parses_longhands()
131136
'timestampstz' => 'timestampsTz',
132137
],
133138
],
139+
'controllers' => [
140+
'Context' => [
141+
'resource' => 'all'
142+
]
143+
]
144+
], $this->subject->parse($blueprint));
145+
}
146+
147+
/**
148+
* @test
149+
*/
150+
public function it_parses_resource_shorthands()
151+
{
152+
$blueprint = $this->fixture('definitions/with-timezones.bp');
153+
154+
$this->assertEquals([
155+
'models' => [
156+
'Comment' => [
157+
'softdeletestz' => 'softDeletesTz',
158+
'timestampstz' => 'timestampstz',
159+
],
160+
],
134161
], $this->subject->parse($blueprint));
135162
}
136163

tests/Feature/Lexers/ControllerLexerTest.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,155 @@ public function it_returns_controllers()
104104
$this->assertCount(1, $methods['index']);
105105
$this->assertEquals('index-statement-1', $methods['index'][0]);
106106
}
107+
108+
/**
109+
* @test
110+
*/
111+
public function it_returns_a_resource_controller()
112+
{
113+
$tokens = [
114+
'controllers' => [
115+
'Comment' => [
116+
'resource' => 'all'
117+
]
118+
]
119+
];
120+
121+
$this->statementLexer->shouldReceive('analyze')
122+
->with([
123+
'query' => 'all:comments',
124+
'render' => 'comment.index with comments'
125+
])
126+
->andReturn(['index-statements']);
127+
128+
$this->statementLexer->shouldReceive('analyze')
129+
->with([
130+
'render' => 'comment.create'
131+
])
132+
->andReturn(['create-statements']);
133+
134+
$this->statementLexer->shouldReceive('analyze')
135+
->with([
136+
'validate' => 'comment',
137+
'save' => 'comment',
138+
'flash' => 'comment.id',
139+
'redirect' => 'comment.index'
140+
])
141+
->andReturn(['store-statements']);
142+
143+
$this->statementLexer->shouldReceive('analyze')
144+
->with([
145+
'render' => 'comment.show with:comment'
146+
])
147+
->andReturn(['show-statements']);
148+
149+
$this->statementLexer->shouldReceive('analyze')
150+
->with([
151+
'render' => 'comment.edit with:comment'
152+
])
153+
->andReturn(['edit-statements']);
154+
155+
$this->statementLexer->shouldReceive('analyze')
156+
->with([
157+
'validate' => 'comment',
158+
'update' => 'comment',
159+
'flash' => 'comment.id',
160+
'redirect' => 'comment.index'
161+
])
162+
->andReturn(['update-statements']);
163+
164+
$this->statementLexer->shouldReceive('analyze')
165+
->with([
166+
'delete' => 'comment',
167+
'redirect' => 'comment.index'
168+
])
169+
->andReturn(['destroy-statements']);
170+
171+
$actual = $this->subject->analyze($tokens);
172+
173+
$this->assertCount(1, $actual['controllers']);
174+
175+
$controller = $actual['controllers']['Comment'];
176+
$this->assertEquals('CommentController', $controller->className());
177+
178+
$methods = $controller->methods();
179+
$this->assertCount(7, $methods);
180+
181+
$this->assertCount(1, $methods['index']);
182+
$this->assertEquals('index-statements', $methods['index'][0]);
183+
$this->assertCount(1, $methods['create']);
184+
$this->assertEquals('create-statements', $methods['create'][0]);
185+
$this->assertCount(1, $methods['store']);
186+
$this->assertEquals('store-statements', $methods['store'][0]);
187+
$this->assertCount(1, $methods['show']);
188+
$this->assertEquals('show-statements', $methods['show'][0]);
189+
$this->assertCount(1, $methods['edit']);
190+
$this->assertEquals('edit-statements', $methods['edit'][0]);
191+
$this->assertCount(1, $methods['update']);
192+
$this->assertEquals('update-statements', $methods['update'][0]);
193+
$this->assertCount(1, $methods['destroy']);
194+
$this->assertEquals('destroy-statements', $methods['destroy'][0]);
195+
}
196+
197+
/**
198+
* @test
199+
*/
200+
public function it_returns_a_limited_resource_controller()
201+
{
202+
$tokens = [
203+
'controllers' => [
204+
'User' => [
205+
'resource' => 'index, edit, update, destroy'
206+
]
207+
]
208+
];
209+
210+
$this->statementLexer->shouldReceive('analyze')
211+
->with([
212+
'query' => 'all:users',
213+
'render' => 'user.index with users'
214+
])
215+
->andReturn(['index-statements']);
216+
217+
$this->statementLexer->shouldReceive('analyze')
218+
->with([
219+
'render' => 'user.edit with:user'
220+
])
221+
->andReturn(['edit-statements']);
222+
223+
$this->statementLexer->shouldReceive('analyze')
224+
->with([
225+
'validate' => 'user',
226+
'update' => 'user',
227+
'flash' => 'user.id',
228+
'redirect' => 'user.index'
229+
])
230+
->andReturn(['update-statements']);
231+
232+
$this->statementLexer->shouldReceive('analyze')
233+
->with([
234+
'delete' => 'user',
235+
'redirect' => 'user.index'
236+
])
237+
->andReturn(['destroy-statements']);
238+
239+
$actual = $this->subject->analyze($tokens);
240+
241+
$this->assertCount(1, $actual['controllers']);
242+
243+
$controller = $actual['controllers']['User'];
244+
$this->assertEquals('UserController', $controller->className());
245+
246+
$methods = $controller->methods();
247+
$this->assertCount(4, $methods);
248+
249+
$this->assertCount(1, $methods['index']);
250+
$this->assertEquals('index-statements', $methods['index'][0]);
251+
$this->assertCount(1, $methods['edit']);
252+
$this->assertEquals('edit-statements', $methods['edit'][0]);
253+
$this->assertCount(1, $methods['update']);
254+
$this->assertEquals('update-statements', $methods['update'][0]);
255+
$this->assertCount(1, $methods['destroy']);
256+
$this->assertEquals('destroy-statements', $methods['destroy'][0]);
257+
}
107258
}

tests/fixtures/definitions/longhands.bp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ models:
1212
Timezone:
1313
softdeletestz: true
1414
timestampsTz: true
15+
16+
controllers:
17+
Context:
18+
resource: true

tests/fixtures/definitions/shorthands.bp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ models:
22
Name:
33
softDeletes
44
id
5-
timestamps
5+
timestamps
6+
7+
controllers:
8+
Context:
9+
resource

0 commit comments

Comments
 (0)