Skip to content

Commit 4ae5492

Browse files
author
Brian Faust
authored
Add support for constructor property promotion (#624)
1 parent 1eeeb64 commit 4ae5492

10 files changed

+319
-4
lines changed

config/blueprint.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,19 @@
114114
*/
115115
'plural_routes' => null,
116116

117+
/*
118+
|--------------------------------------------------------------------------
119+
| Constructor Property Promotion
120+
|--------------------------------------------------------------------------
121+
|
122+
| PHP 8.0 offers a new feature called "constructor property promotion."
123+
| If you are running PHP >= 8.0, you may enable this feature to tell
124+
| Blueprint to generate constructor signatures and properties for
125+
| your classes automatically if you don't explicitly do so.
126+
|
127+
*/
128+
'constructor_property_promotion' => false,
129+
117130
/*
118131
|--------------------------------------------------------------------------
119132
| Generators

src/Generators/StatementGenerator.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ protected function populateConstructor(string $type, $statement): string
2323

2424
protected function buildProperties(array $data)
2525
{
26+
if (config('blueprint.constructor_property_promotion')) {
27+
return '';
28+
}
29+
2630
return trim(
2731
array_reduce(
2832
$data,
@@ -38,6 +42,10 @@ function ($output, $property) {
3842

3943
protected function buildAssignments(array $data)
4044
{
45+
if (config('blueprint.constructor_property_promotion')) {
46+
return '//';
47+
}
48+
4149
return trim(
4250
array_reduce(
4351
$data,
@@ -53,10 +61,17 @@ function ($output, $property) {
5361

5462
protected function buildParameters(array $data)
5563
{
56-
$parameters = array_map(
57-
fn ($parameter) => '$' . $parameter,
58-
$data
59-
);
64+
if (config('blueprint.constructor_property_promotion')) {
65+
$parameters = array_map(
66+
fn ($parameter) => 'public $' . $parameter,
67+
$data
68+
);
69+
} else {
70+
$parameters = array_map(
71+
fn ($parameter) => '$' . $parameter,
72+
$data
73+
);
74+
}
6075

6176
return implode(', ', $parameters);
6277
}

tests/Feature/Generators/Statements/EventGeneratorTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,34 @@ public function it_respects_configuration(): void
140140

141141
$this->assertEquals(['created' => ['src/path/Events/NewPost.php']], $this->subject->output($tree));
142142
}
143+
144+
#[Test]
145+
public function it_respects_configuration_for_constructor_property_promotion(): void
146+
{
147+
$this->app['config']->set('blueprint.namespace', 'Some\\App');
148+
$this->app['config']->set('blueprint.app_path', 'src/path');
149+
$this->app['config']->set('blueprint.constructor_property_promotion', true);
150+
151+
$this->filesystem->expects('stub')
152+
->with('event.stub')
153+
->andReturn($this->stub('event.stub'));
154+
$this->filesystem->expects('stub')
155+
->with('constructor.stub')
156+
->andReturn($this->stub('constructor.stub'));
157+
$this->filesystem->expects('exists')
158+
->with('src/path/Events')
159+
->andReturnFalse();
160+
$this->filesystem->expects('makeDirectory')
161+
->with('src/path/Events', 0755, true);
162+
$this->filesystem->expects('exists')
163+
->with('src/path/Events/NewPost.php')
164+
->andReturnFalse();
165+
$this->filesystem->expects('put')
166+
->with('src/path/Events/NewPost.php', $this->fixture('events/event-configured-with-constructor-property-promotion.php'));
167+
168+
$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example.yaml'));
169+
$tree = $this->blueprint->analyze($tokens);
170+
171+
$this->assertEquals(['created' => ['src/path/Events/NewPost.php']], $this->subject->output($tree));
172+
}
143173
}

tests/Feature/Generators/Statements/JobGeneratorTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,34 @@ public function it_respects_configuration(): void
138138

139139
$this->assertEquals(['created' => ['src/path/Jobs/SyncMedia.php']], $this->subject->output($tree));
140140
}
141+
142+
#[Test]
143+
public function it_respects_configuration_for_constructor_property_promotion(): void
144+
{
145+
$this->app['config']->set('blueprint.namespace', 'Some\\App');
146+
$this->app['config']->set('blueprint.app_path', 'src/path');
147+
$this->app['config']->set('blueprint.constructor_property_promotion', true);
148+
149+
$this->filesystem->expects('stub')
150+
->with('job.stub')
151+
->andReturn($this->stub('job.stub'));
152+
$this->filesystem->expects('stub')
153+
->with('constructor.stub')
154+
->andReturn($this->stub('constructor.stub'));
155+
$this->filesystem->expects('exists')
156+
->with('src/path/Jobs')
157+
->andReturnFalse();
158+
$this->filesystem->expects('exists')
159+
->with('src/path/Jobs/SyncMedia.php')
160+
->andReturnFalse();
161+
$this->filesystem->expects('makeDirectory')
162+
->with('src/path/Jobs', 0755, true);
163+
$this->filesystem->expects('put')
164+
->with('src/path/Jobs/SyncMedia.php', $this->fixture('jobs/job-configured-with-constructor-property-promotion.php'));
165+
166+
$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example.yaml'));
167+
$tree = $this->blueprint->analyze($tokens);
168+
169+
$this->assertEquals(['created' => ['src/path/Jobs/SyncMedia.php']], $this->subject->output($tree));
170+
}
141171
}

tests/Feature/Generators/Statements/MailGeneratorTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,51 @@ public function it_respects_configuration(): void
190190
], $this->subject->output($tree));
191191
}
192192

193+
#[Test]
194+
public function it_respects_configuration_for_constructor_property_promotion(): void
195+
{
196+
$this->app['config']->set('blueprint.namespace', 'Some\\App');
197+
$this->app['config']->set('blueprint.app_path', 'src/path');
198+
$this->app['config']->set('blueprint.constructor_property_promotion', true);
199+
200+
$this->filesystem->expects('stub')
201+
->with('mail.stub')
202+
->andReturn($this->stub('mail.stub'));
203+
$this->filesystem->expects('stub')
204+
->with('mail.view.stub')
205+
->andReturn($this->stub('mail.view.stub'));
206+
$this->filesystem->expects('stub')
207+
->with('constructor.stub')
208+
->andReturn($this->stub('constructor.stub'));
209+
$this->filesystem->expects('exists')
210+
->with('src/path/Mail')
211+
->andReturnFalse();
212+
$this->filesystem->expects('exists')
213+
->with('src/path/Mail/ReviewPost.php')
214+
->andReturnFalse();
215+
$this->filesystem->expects('makeDirectory')
216+
->with('src/path/Mail', 0755, true);
217+
$this->filesystem->expects('put')
218+
->with('src/path/Mail/ReviewPost.php', $this->fixture('mailables/mail-configured-with-constructor-property-promotion.php'));
219+
$this->filesystem->expects('exists')
220+
->with('resources/views/emails/review-post.blade.php')
221+
->andReturnFalse();
222+
$this->filesystem->expects('makeDirectory')
223+
->with('resources/views/emails', 0755, true);
224+
$this->filesystem->expects('put')
225+
->with('resources/views/emails/review-post.blade.php', $this->fixture('mailables/review-post-view.blade.php'));
226+
227+
$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example.yaml'));
228+
$tree = $this->blueprint->analyze($tokens);
229+
230+
$this->assertEquals([
231+
'created' => [
232+
'src/path/Mail/ReviewPost.php',
233+
'resources/views/emails/review-post.blade.php',
234+
],
235+
], $this->subject->output($tree));
236+
}
237+
193238
#[Test]
194239
public function output_writes_mails_but_not_existing_templates(): void
195240
{

tests/Feature/Generators/Statements/NotificationGeneratorTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,36 @@ public function it_respects_configuration(): void
148148
$this->assertEquals(['created' => ['src/path/Notification/ReviewNotification.php']], $this->subject->output($tree));
149149
}
150150

151+
#[Test]
152+
public function it_respects_configuration_for_constructor_property_promotion(): void
153+
{
154+
$this->app['config']->set('blueprint.namespace', 'Some\\App');
155+
$this->app['config']->set('blueprint.app_path', 'src/path');
156+
$this->app['config']->set('blueprint.constructor_property_promotion', true);
157+
158+
$this->filesystem->expects('stub')
159+
->with('notification.stub')
160+
->andReturn($this->stub('notification.stub'));
161+
$this->filesystem->expects('stub')
162+
->with('constructor.stub')
163+
->andReturn($this->stub('constructor.stub'));
164+
$this->filesystem->expects('exists')
165+
->with('src/path/Notification')
166+
->andReturnFalse();
167+
$this->filesystem->expects('exists')
168+
->with('src/path/Notification/ReviewNotification.php')
169+
->andReturnFalse();
170+
$this->filesystem->expects('makeDirectory')
171+
->with('src/path/Notification', 0755, true);
172+
$this->filesystem->expects('put')
173+
->with('src/path/Notification/ReviewNotification.php', $this->fixture('notifications/notification-configured-with-constructor-property-promotion.php'));
174+
175+
$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example-notification-facade.yaml'));
176+
$tree = $this->blueprint->analyze($tokens);
177+
178+
$this->assertEquals(['created' => ['src/path/Notification/ReviewNotification.php']], $this->subject->output($tree));
179+
}
180+
151181
public static function notificationDraftProvider(): array
152182
{
153183
return [
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Some\App\Events;
4+
5+
use Illuminate\Queue\SerializesModels;
6+
7+
class NewPost
8+
{
9+
use SerializesModels;
10+
11+
/**
12+
* Create a new event instance.
13+
*/
14+
public function __construct(public $post)
15+
{
16+
//
17+
}
18+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Some\App\Jobs;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Foundation\Bus\Dispatchable;
8+
use Illuminate\Queue\InteractsWithQueue;
9+
use Illuminate\Queue\SerializesModels;
10+
11+
class SyncMedia implements ShouldQueue
12+
{
13+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
14+
15+
/**
16+
* Create a new job instance.
17+
*/
18+
public function __construct(public $post)
19+
{
20+
//
21+
}
22+
23+
/**
24+
* Execute the job.
25+
*/
26+
public function handle(): void
27+
{
28+
//
29+
}
30+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Some\App\Mail;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Mail\Mailable;
8+
use Illuminate\Mail\Mailables\Content;
9+
use Illuminate\Mail\Mailables\Envelope;
10+
use Illuminate\Queue\SerializesModels;
11+
12+
class ReviewPost extends Mailable
13+
{
14+
use Queueable, SerializesModels;
15+
16+
/**
17+
* Create a new message instance.
18+
*/
19+
public function __construct(public $post)
20+
{
21+
//
22+
}
23+
24+
/**
25+
* Get the message envelope.
26+
*/
27+
public function envelope(): Envelope
28+
{
29+
return new Envelope(
30+
subject: 'Review Post',
31+
);
32+
}
33+
34+
/**
35+
* Get the message content definition.
36+
*/
37+
public function content(): Content
38+
{
39+
return new Content(
40+
view: 'emails.review-post',
41+
);
42+
}
43+
44+
/**
45+
* Get the attachments for the message.
46+
*
47+
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
48+
*/
49+
public function attachments(): array
50+
{
51+
return [];
52+
}
53+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Some\App\Notification;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Notifications\Notification;
7+
use Illuminate\Contracts\Queue\ShouldQueue;
8+
use Illuminate\Notifications\Messages\MailMessage;
9+
use Illuminate\Queue\SerializesModels;
10+
11+
class ReviewNotification extends Notification
12+
{
13+
use Queueable, SerializesModels;
14+
15+
/**
16+
* Create a new message instance.
17+
*/
18+
public function __construct(public $post)
19+
{
20+
//
21+
}
22+
23+
/**
24+
* Get the notification's delivery channels.
25+
*/
26+
public function via(mixed $notifiable): array
27+
{
28+
return ['mail'];
29+
}
30+
31+
/**
32+
* Get the mail representation of the notification.
33+
*/
34+
public function toMail(mixed $notifiable): MailMessage
35+
{
36+
return (new MailMessage)
37+
->line('The introduction to the notification.')
38+
->action('Notification Action', 'https://laravel.com')
39+
->line('Thank you for using our application!');
40+
}
41+
42+
/**
43+
* Get the array representation of the notification.
44+
*/
45+
public function toArray(mixed $notifiable): array
46+
{
47+
return [
48+
//
49+
];
50+
}
51+
}

0 commit comments

Comments
 (0)