Skip to content

Commit 588eaa3

Browse files
authored
Ability to differentiate between mail and notification when using send (#235)
1 parent 4ae634e commit 588eaa3

24 files changed

+777
-50
lines changed

src/BlueprintServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ function ($app) {
7979
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\ResourceGenerator($app['files']));
8080
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\JobGenerator($app['files']));
8181
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\MailGenerator($app['files']));
82+
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\NotificationGenerator($app['files']));
8283
$blueprint->registerGenerator(new \Blueprint\Generators\Statements\ViewGenerator($app['files']));
8384
$blueprint->registerGenerator(new \Blueprint\Generators\RouteGenerator($app['files']));
8485

src/Generators/ControllerGenerator.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,13 @@ private function buildMethods(Controller $controller)
102102
foreach ($statements as $statement) {
103103
if ($statement instanceof SendStatement) {
104104
$body .= self::INDENT . $statement->output() . PHP_EOL;
105-
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Mail');
106-
$this->addImport($controller, config('blueprint.namespace') . '\\Mail\\' . $statement->mail());
105+
if ($statement->type() === 'notification') {
106+
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Notification');
107+
$this->addImport($controller, config('blueprint.namespace') . '\\Notification\\' . $statement->mail());
108+
} else {
109+
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Mail');
110+
$this->addImport($controller, config('blueprint.namespace') . '\\Mail\\' . $statement->mail());
111+
}
107112
} elseif ($statement instanceof ValidateStatement) {
108113
$class_name = $controller->name() . Str::studly($name) . 'Request';
109114

src/Generators/Statements/MailGenerator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ public function output(array $tree): array
3232
continue;
3333
}
3434

35+
if ($statement->type() !== 'mail') {
36+
continue;
37+
}
38+
3539
$path = $this->getPath($statement->mail());
3640

3741
if ($this->files->exists($path)) {
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
namespace Blueprint\Generators\Statements;
4+
5+
use Blueprint\Blueprint;
6+
use Blueprint\Contracts\Generator;
7+
use Blueprint\Models\Statements\SendStatement;
8+
9+
class NotificationGenerator implements Generator
10+
{
11+
/**
12+
* @
13+
\Illuminate\Contracts\Filesystem\Filesystem
14+
*/
15+
private $files;
16+
17+
public function __construct($files)
18+
{
19+
$this->files = $files;
20+
}
21+
22+
public function output(array $tree): array
23+
{
24+
$output = [];
25+
26+
$stub = $this->files->stub('notification.stub');
27+
28+
/** @var \Blueprint\Models\Controller $controller */
29+
foreach ($tree['controllers'] as $controller) {
30+
foreach ($controller->methods() as $method => $statements) {
31+
foreach ($statements as $statement) {
32+
if (!$statement instanceof SendStatement) {
33+
continue;
34+
}
35+
36+
if ($statement->type() !== 'notification') {
37+
continue;
38+
}
39+
40+
$path = $this->getPath($statement->mail());
41+
42+
if ($this->files->exists($path)) {
43+
continue;
44+
}
45+
46+
if (!$this->files->exists(dirname($path))) {
47+
$this->files->makeDirectory(dirname($path), 0755, true);
48+
}
49+
50+
$this->files->put($path, $this->populateStub($stub, $statement));
51+
52+
$output['created'][] = $path;
53+
}
54+
}
55+
}
56+
57+
return $output;
58+
}
59+
60+
protected function getPath(string $name)
61+
{
62+
return Blueprint::appPath() . '/Notification/' . $name . '.php';
63+
}
64+
65+
protected function populateStub(string $stub, SendStatement $sendStatement)
66+
{
67+
$stub = str_replace('DummyNamespace', config('blueprint.namespace') . '\\Notification', $stub);
68+
$stub = str_replace('DummyClass', $sendStatement->mail(), $stub);
69+
$stub = str_replace('// properties...', $this->buildConstructor($sendStatement), $stub);
70+
71+
return $stub;
72+
}
73+
74+
private function buildConstructor(SendStatement $sendStatement)
75+
{
76+
static $constructor = null;
77+
78+
if (is_null($constructor)) {
79+
$constructor = str_replace('new instance', 'new message instance', $this->files->stub('partials/constructor.stub'));
80+
}
81+
82+
if (empty($sendStatement->data())) {
83+
return trim($constructor);
84+
}
85+
86+
$stub = $this->buildProperties($sendStatement->data()) . PHP_EOL . PHP_EOL;
87+
$stub .= str_replace('__construct()', '__construct(' . $this->buildParameters($sendStatement->data()) . ')', $constructor);
88+
$stub = str_replace('//', $this->buildAssignments($sendStatement->data()), $stub);
89+
90+
return $stub;
91+
}
92+
93+
private function buildProperties(array $data)
94+
{
95+
return trim(array_reduce($data, function ($output, $property) {
96+
$output .= ' public $' . $property . ';' . PHP_EOL . PHP_EOL;
97+
return $output;
98+
}, ''));
99+
}
100+
101+
private function buildParameters(array $data)
102+
{
103+
$parameters = array_map(function ($parameter) {
104+
return '$' . $parameter;
105+
}, $data);
106+
107+
return implode(', ', $parameters);
108+
}
109+
110+
private function buildAssignments(array $data)
111+
{
112+
return trim(array_reduce($data, function ($output, $property) {
113+
$output .= ' $this->' . $property . ' = $' . $property . ';' . PHP_EOL;
114+
return $output;
115+
}, ''));
116+
}
117+
}

src/Generators/TestGenerator.php

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,46 +112,89 @@ protected function buildTestCases(Controller $controller)
112112

113113
foreach ($statements as $statement) {
114114
if ($statement instanceof SendStatement) {
115-
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Mail');
116-
$this->addImport($controller, config('blueprint.namespace') . '\\Mail\\' . $statement->mail());
115+
if ($statement->type() === 'notification') {
116+
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Notification');
117+
$this->addImport($controller, config('blueprint.namespace') . '\\Notification\\' . $statement->mail());
117118

118-
$setup['mock'][] = 'Mail::fake();';
119+
$setup['mock'][] = 'Notification::fake();';
119120

120-
$assertion = sprintf('Mail::assertSent(%s::class', $statement->mail());
121+
$assertion = sprintf('Notification::assertSent(%s::class', $statement->mail());
121122

122-
if ($statement->data() || $statement->to()) {
123-
$conditions = [];
124-
$variables = [];
125-
$assertion .= ', function ($mail)';
123+
if ($statement->data() || $statement->to()) {
124+
$conditions = [];
125+
$variables = [];
126+
$assertion .= ', function ($notification)';
126127

127-
if ($statement->to()) {
128-
$conditions[] = '$mail->hasTo($' . str_replace('.', '->', $statement->to()) . ')';
129-
}
128+
if ($statement->to()) {
129+
$conditions[] = '$notification->hasTo($' . str_replace('.', '->', $statement->to()) . ')';
130+
}
130131

131-
foreach ($statement->data() as $data) {
132-
if (Str::studly(Str::singular($data)) === $context) {
133-
$variables[] .= '$' . $data;
134-
$conditions[] .= sprintf('$mail->%s->is($%s)', $data, $data);
135-
} else {
136-
[$model, $property] = explode('.', $data);
137-
$variables[] .= '$' . $model;
138-
$conditions[] .= sprintf('$mail->%s == $%s', $property ?? $model, str_replace('.', '->', $data()));
132+
foreach ($statement->data() as $data) {
133+
if (Str::studly(Str::singular($data)) === $context) {
134+
$variables[] .= '$' . $data;
135+
$conditions[] .= sprintf('$notification->%s->is($%s)', $data, $data);
136+
} else {
137+
[$model, $property] = explode('.', $data);
138+
$variables[] .= '$' . $model;
139+
$conditions[] .= sprintf('$notification->%s == $%s', $property ?? $model, str_replace('.', '->', $data()));
140+
}
139141
}
140-
}
141142

142-
if ($variables) {
143-
$assertion .= ' use (' . implode(', ', array_unique($variables)) . ')';
143+
if ($variables) {
144+
$assertion .= ' use (' . implode(', ', array_unique($variables)) . ')';
145+
}
146+
147+
$assertion .= ' {' . PHP_EOL;
148+
$assertion .= str_pad(' ', 12);
149+
$assertion .= 'return ' . implode(' && ', $conditions) . ';';
150+
$assertion .= PHP_EOL . str_pad(' ', 8) . '}';
144151
}
145152

146-
$assertion .= ' {' . PHP_EOL;
147-
$assertion .= str_pad(' ', 12);
148-
$assertion .= 'return ' . implode(' && ', $conditions) . ';';
149-
$assertion .= PHP_EOL . str_pad(' ', 8) . '}';
150-
}
153+
$assertion .= ');';
151154

152-
$assertion .= ');';
155+
$assertions['mock'][] = $assertion;
156+
} else {
157+
$this->addImport($controller, 'Illuminate\\Support\\Facades\\Mail');
158+
$this->addImport($controller, config('blueprint.namespace') . '\\Mail\\' . $statement->mail());
153159

154-
$assertions['mock'][] = $assertion;
160+
$setup['mock'][] = 'Mail::fake();';
161+
162+
$assertion = sprintf('Mail::assertSent(%s::class', $statement->mail());
163+
164+
if ($statement->data() || $statement->to()) {
165+
$conditions = [];
166+
$variables = [];
167+
$assertion .= ', function ($mail)';
168+
169+
if ($statement->to()) {
170+
$conditions[] = '$mail->hasTo($' . str_replace('.', '->', $statement->to()) . ')';
171+
}
172+
173+
foreach ($statement->data() as $data) {
174+
if (Str::studly(Str::singular($data)) === $context) {
175+
$variables[] .= '$' . $data;
176+
$conditions[] .= sprintf('$mail->%s->is($%s)', $data, $data);
177+
} else {
178+
[$model, $property] = explode('.', $data);
179+
$variables[] .= '$' . $model;
180+
$conditions[] .= sprintf('$mail->%s == $%s', $property ?? $model, str_replace('.', '->', $data()));
181+
}
182+
}
183+
184+
if ($variables) {
185+
$assertion .= ' use (' . implode(', ', array_unique($variables)) . ')';
186+
}
187+
188+
$assertion .= ' {' . PHP_EOL;
189+
$assertion .= str_pad(' ', 12);
190+
$assertion .= 'return ' . implode(' && ', $conditions) . ';';
191+
$assertion .= PHP_EOL . str_pad(' ', 8) . '}';
192+
}
193+
194+
$assertion .= ');';
195+
196+
$assertions['mock'][] = $assertion;
197+
}
155198
} elseif ($statement instanceof ValidateStatement) {
156199
$this->addTestAssertionsTrait($controller);
157200

src/Lexers/StatementLexer.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function analyze(array $tokens): array
3838
$statements[] = $this->analyzeDispatch($statement);
3939
break;
4040
case 'send':
41-
$statements[] = $this->analyzeMail($statement);
41+
$statements[] = $this->analyzeSend($statement);
4242
break;
4343
case 'validate':
4444
$statements[] = $this->analyzeValidate($statement);
@@ -103,7 +103,7 @@ private function analyzeRespond(string $statement)
103103
return new RespondStatement($statement);
104104
}
105105

106-
private function analyzeMail($statement)
106+
private function analyzeSend($statement)
107107
{
108108
$to = null;
109109

@@ -120,7 +120,12 @@ private function analyzeMail($statement)
120120
$data = preg_split('/,([ \t]+)?/', substr($with, 5));
121121
}
122122

123-
return new SendStatement($object, $to, $data);
123+
$type = 'mail';
124+
if (Str::endsWith($object, 'Notification')) {
125+
$type = 'notification';
126+
}
127+
128+
return new SendStatement($object, $to, $data, $type);
124129
}
125130

126131
private function analyzeValidate($statement)

src/Models/Statements/SendStatement.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ class SendStatement
2020
*/
2121
private $data;
2222

23-
public function __construct(string $mail, string $to = null, array $data = [])
23+
/**
24+
* @var string
25+
*/
26+
private $type;
27+
28+
public function __construct(string $mail, string $to = null, array $data = [], string $type)
2429
{
2530
$this->mail = $mail;
2631
$this->data = $data;
2732
$this->to = $to;
33+
$this->type = $type;
2834
}
2935

3036
public function mail()
@@ -37,6 +43,11 @@ public function to()
3743
return $this->to;
3844
}
3945

46+
public function type()
47+
{
48+
return $this->type;
49+
}
50+
4051
/**
4152
* @return array
4253
*/
@@ -46,6 +57,11 @@ public function data(): array
4657
}
4758

4859
public function output()
60+
{
61+
return $this->type() === 'mail' ? $this->mailOutput() : $this->notificationOutput();
62+
}
63+
64+
private function mailOutput()
4965
{
5066
$code = 'Mail::';
5167

@@ -64,6 +80,23 @@ public function output()
6480
return $code;
6581
}
6682

83+
private function notificationOutput()
84+
{
85+
$code = 'Notification::';
86+
87+
if ($this->to()) {
88+
$code .= 'send($' . str_replace('.', '->', $this->to()) . ', new ' . $this->mail() . '(';
89+
}
90+
91+
if ($this->data()) {
92+
$code .= $this->buildParameters($this->data());
93+
}
94+
95+
$code .= '));';
96+
97+
return $code;
98+
}
99+
67100
private function buildParameters(array $data)
68101
{
69102
$parameters = array_map(function ($parameter) {

0 commit comments

Comments
 (0)