Skip to content

Commit 8d51c72

Browse files
committed
Generate routes
1 parent 99aa4fa commit 8d51c72

File tree

11 files changed

+219
-20
lines changed

11 files changed

+219
-20
lines changed

src/BlueprintCommand.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public function handle()
6666
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\JobGenerator($this->files));
6767
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\MailGenerator($this->files));
6868
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\ViewGenerator($this->files));
69+
$blueprint->registerGenerator(new \Blueprint\Generators\RouteGenerator($this->files));
6970

7071
$tokens = $blueprint->parse($contents);
7172
$registry = $blueprint->analyze($tokens);

src/Generators/ControllerGenerator.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function output(array $tree): array
5353
protected function populateStub(string $stub, Controller $controller)
5454
{
5555
$stub = str_replace('DummyNamespace', 'App\\Http\\Controllers', $stub);
56-
$stub = str_replace('DummyClass', $this->className($controller), $stub);
56+
$stub = str_replace('DummyClass', $controller->className(), $stub);
5757
$stub = str_replace('// methods...', $this->buildMethods($controller), $stub);
5858
$stub = str_replace('// imports...', $this->buildImports($controller), $stub);
5959

@@ -121,7 +121,7 @@ private function buildMethods(Controller $controller)
121121

122122
protected function getPath(Controller $controller)
123123
{
124-
return 'app/Http/Controllers/' . $this->className($controller) . '.php';
124+
return 'app/Http/Controllers/' . $controller->className() . '.php';
125125
}
126126

127127
private function methodStub()
@@ -135,11 +135,6 @@ private function methodStub()
135135
return $stub;
136136
}
137137

138-
protected function className(Controller $controller): string
139-
{
140-
return $controller->name() . (Str::endsWith($controller->name(), 'Controller') ? '' : 'Controller');
141-
}
142-
143138
private function addImport(Controller $controller, $class)
144139
{
145140
$this->imports[$controller->name()][] = $class;

src/Generators/RouteGenerator.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Blueprint\Generators;
4+
5+
use Blueprint\Contracts\Generator;
6+
use Blueprint\Models\Controller;
7+
use Illuminate\Support\Str;
8+
9+
class RouteGenerator implements Generator
10+
{
11+
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
12+
private $files;
13+
14+
private $resourceMethods = ['index', 'create', 'store', 'edit', 'update', 'show', 'destroy'];
15+
16+
public function __construct($files)
17+
{
18+
$this->files = $files;
19+
}
20+
21+
public function output(array $tree): array
22+
{
23+
if (empty($tree['controllers'])) {
24+
return [];
25+
}
26+
27+
$routes = '';
28+
/** @var \Blueprint\Models\Controller $controller */
29+
foreach ($tree['controllers'] as $controller) {
30+
$routes .= PHP_EOL . PHP_EOL . $this->buildRoutes($controller);
31+
}
32+
$routes .= PHP_EOL;
33+
34+
$path = 'routes/web.php';
35+
$this->files->append($path, $routes);
36+
37+
return ['updated' => [$path]];
38+
}
39+
40+
protected function buildRoutes(Controller $controller)
41+
{
42+
$routes = '';
43+
$methods = array_keys($controller->methods());
44+
45+
$className = $controller->className();
46+
$slug = Str::kebab($controller->prefix());
47+
48+
$resource_methods = array_intersect($methods, $this->resourceMethods);
49+
if (count($resource_methods)) {
50+
$routes .= sprintf("Route::resource('%s', '%s')", $slug, $className);
51+
52+
$missing_methods = array_diff($this->resourceMethods, $resource_methods);
53+
if (count($missing_methods)) {
54+
if (count($missing_methods) < 4) {
55+
$routes .= sprintf("->except('%s')", implode("', '", $missing_methods));
56+
} else {
57+
$routes .= sprintf("->only('%s')", implode("', '", $resource_methods));
58+
}
59+
}
60+
61+
62+
$routes .= ';' . PHP_EOL;
63+
}
64+
65+
$methods = array_diff($methods, $this->resourceMethods);
66+
foreach ($methods as $method) {
67+
$routes .= sprintf("Route::get('%s/%s', '%s@%s');", $slug, Str::kebab($method), $className, $method);
68+
$routes .= PHP_EOL;
69+
}
70+
71+
return trim($routes);
72+
}
73+
}

src/Generators/Statements/FormRequestGenerator.php

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Blueprint\Generators\Statements;
44

55
use Blueprint\Contracts\Generator;
6-
use Blueprint\Models\Model;
76
use Blueprint\Models\Statements\ValidateStatement;
87
use Blueprint\Translators\Rules;
98
use Illuminate\Support\Str;
@@ -40,7 +39,7 @@ public function output(array $tree): array
4039
continue;
4140
}
4241

43-
$context = $this->getContextFromController($controller->name());
42+
$context = Str::singular($controller->prefix());
4443
$name = $this->getName($context, $method);
4544
$path = $this->getPath($name);
4645

@@ -91,17 +90,6 @@ private function buildRules(string $context, ValidateStatement $validateStatemen
9190
}, ''));
9291
}
9392

94-
private function getContextFromController(string $name)
95-
{
96-
$context = $name;
97-
98-
if (Str::endsWith($name, 'Controller')) {
99-
$context = Str::substr($name, 0, -10);
100-
}
101-
102-
return Str::singular($context);
103-
}
104-
10593
private function modelForContext(string $context)
10694
{
10795
return $this->models[Str::studly($context)] ?? $this->models[Str::lower($context)] ?? null;

src/Models/Controller.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
namespace Blueprint\Models;
55

66

7+
use Illuminate\Support\Str;
8+
79
class Controller
810
{
911
/**
@@ -30,6 +32,11 @@ public function name(): string
3032
return $this->name;
3133
}
3234

35+
public function className(): string
36+
{
37+
return $this->name() . (Str::endsWith($this->name(), 'Controller') ? '' : 'Controller');
38+
}
39+
3340
public function methods(): array
3441
{
3542
return $this->methods;
@@ -39,4 +46,13 @@ public function addMethod(string $name, array $statements)
3946
{
4047
$this->methods[$name] = $statements;
4148
}
49+
50+
public function prefix()
51+
{
52+
if (Str::endsWith($this->name(), 'Controller')) {
53+
return Str::substr($this->name(), 0, -10);
54+
}
55+
56+
return $this->name();
57+
}
4258
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace Tests\Feature\Generators;
4+
5+
use Blueprint\Blueprint;
6+
use Blueprint\Generators\RouteGenerator;
7+
use Blueprint\Lexers\StatementLexer;
8+
use Tests\TestCase;
9+
10+
/**
11+
* @see RouteGenerator
12+
*/
13+
class RouteGeneratorTest extends TestCase
14+
{
15+
private $blueprint;
16+
17+
private $files;
18+
19+
/** @var RouteGenerator */
20+
private $subject;
21+
22+
protected function setUp(): void
23+
{
24+
parent::setUp();
25+
26+
$this->files = \Mockery::mock();
27+
$this->subject = new RouteGenerator($this->files);
28+
29+
$this->blueprint = new Blueprint();
30+
$this->blueprint->registerLexer(new \Blueprint\Lexers\ControllerLexer(new StatementLexer()));
31+
$this->blueprint->registerGenerator($this->subject);
32+
}
33+
34+
/**
35+
* @test
36+
*/
37+
public function output_writes_nothing_for_empty_tree()
38+
{
39+
$this->files->shouldNotHaveReceived('append');
40+
41+
$this->assertEquals([], $this->subject->output(['controllers' => []]));
42+
}
43+
44+
/**
45+
* @test
46+
* @dataProvider controllerTreeDataProvider
47+
*/
48+
public function output_writes_migration_for_route_tree($definition, $routes)
49+
{
50+
$path = 'routes/web.php';
51+
$this->files->expects('append')
52+
->with($path, $this->fixture($routes));
53+
54+
$tokens = $this->blueprint->parse($this->fixture($definition));
55+
$tree = $this->blueprint->analyze($tokens);
56+
57+
$this->assertEquals(['updated' => [$path]], $this->subject->output($tree));
58+
}
59+
60+
61+
public function controllerTreeDataProvider()
62+
{
63+
return [
64+
['definitions/readme-example.bp', 'routes/readme-example.php'],
65+
['definitions/cruddy.bp', 'routes/cruddy.php'],
66+
['definitions/non-cruddy.bp', 'routes/non-cruddy.php'],
67+
];
68+
}
69+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
controllers:
2+
Crud:
3+
index:
4+
render: crud.index
5+
create:
6+
render: crud.create
7+
store:
8+
redirect: crud.index
9+
edit:
10+
render: crud.create
11+
update:
12+
redirect: crud.index
13+
show:
14+
render: crud.show
15+
destroy:
16+
redirect: crud.index
17+
18+
UsersController:
19+
index:
20+
render: users.index
21+
edit:
22+
render: users.create
23+
update:
24+
redirect: users.index
25+
show:
26+
render: users.show
27+
destroy:
28+
redirect: users.index
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
controllers:
2+
Some:
3+
index:
4+
render: some.index
5+
show:
6+
render: some.show
7+
whatever:
8+
redirect: some.index
9+
slugName:
10+
redirect: some.index
11+
12+
Subscriptions:
13+
resume:
14+
redirect: subscriptions.index

tests/fixtures/routes/cruddy.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
Route::resource('crud', 'CrudController');
4+
5+
Route::resource('users', 'UsersController')->except('create', 'store');
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
3+
Route::resource('some', 'SomeController')->only('index', 'show');
4+
Route::get('some/whatever', 'SomeController@whatever');
5+
Route::get('some/slug-name', 'SomeController@slugName');
6+
7+
Route::get('subscriptions/resume', 'SubscriptionsController@resume');

0 commit comments

Comments
 (0)