Skip to content

Commit 406cd93

Browse files
Merge pull request #57 from laravel-shift/model-properties
Add PHPDoc for properties of Model class
2 parents 790a021 + 6b7cb5d commit 406cd93

File tree

8 files changed

+264
-4
lines changed

8 files changed

+264
-4
lines changed

config/blueprint.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,16 @@
4444
*/
4545
'app_path' => app_path(),
4646

47-
];
47+
/*
48+
|--------------------------------------------------------------------------
49+
| Generate PHPDocs
50+
|--------------------------------------------------------------------------
51+
|
52+
| Here you may enable generate PHPDocs for classes like Models. This
53+
| not only serves as documentation, but also allows your IDE to
54+
| map to the dynamic properties used by Laravel Models.
55+
|
56+
*/
57+
'generate_phpdocs' => false,
58+
59+
];

src/Generators/ModelGenerator.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ protected function populateStub(string $stub, Model $model)
4242
{
4343
$stub = str_replace('DummyNamespace', $model->fullyQualifiedNamespace(), $stub);
4444
$stub = str_replace('DummyClass', $model->name(), $stub);
45+
$stub = str_replace('/** DummyPHPDocClass **/', $this->buildClassPhpDoc($model), $stub);
4546

4647
$body = $this->buildProperties($model);
4748
$body .= PHP_EOL . PHP_EOL;
@@ -53,6 +54,38 @@ protected function populateStub(string $stub, Model $model)
5354
return $stub;
5455
}
5556

57+
private function buildClassPhpDoc(Model $model)
58+
{
59+
if (!config('blueprint.generate_phpdocs')) {
60+
return '';
61+
}
62+
63+
$phpDoc = PHP_EOL;
64+
$phpDoc .= '/**';
65+
$phpDoc .= PHP_EOL;
66+
/** @var Column $column */
67+
foreach ($model->columns() as $column) {
68+
$phpDoc .= sprintf(' * @property %s $%s', $this->phpDataType($column->dataType()), $column->name());
69+
$phpDoc .= PHP_EOL;
70+
}
71+
72+
if ($model->usesSoftDeletes()) {
73+
$phpDoc .= ' * @property \Carbon\Carbon $deleted_at';
74+
$phpDoc .= PHP_EOL;
75+
}
76+
77+
if ($model->usesTimestamps()) {
78+
$phpDoc .= ' * @property \Carbon\Carbon $created_at';
79+
$phpDoc .= PHP_EOL;
80+
$phpDoc .= ' * @property \Carbon\Carbon $updated_at';
81+
$phpDoc .= PHP_EOL;
82+
}
83+
84+
$phpDoc .= ' */';
85+
86+
return $phpDoc;
87+
}
88+
5689
private function buildProperties(Model $model)
5790
{
5891
$properties = '';
@@ -188,4 +221,46 @@ private function addTraits(Model $model, $stub)
188221

189222
return $stub;
190223
}
224+
225+
private function phpDataType(string $dataType)
226+
{
227+
static $php_data_types = [
228+
'id' => 'int',
229+
'bigincrements' => 'int',
230+
'biginteger' => 'int',
231+
'boolean' => 'bool',
232+
'date' => '\Carbon\Carbon',
233+
'datetime' => '\Carbon\Carbon',
234+
'datetimetz' => '\Carbon\Carbon',
235+
'decimal' => 'float',
236+
'double' => 'double',
237+
'float' => 'float',
238+
'increments' => 'int',
239+
'integer' => 'int',
240+
'mediumincrements' => 'int',
241+
'mediuminteger' => 'int',
242+
'nullabletimestamps' => '\Carbon\Carbon',
243+
'smallincrements' => 'int',
244+
'smallinteger' => 'int',
245+
'softdeletes' => '\Carbon\Carbon',
246+
'softdeletestz' => '\Carbon\Carbon',
247+
'time' => '\Carbon\Carbon',
248+
'timetz' => '\Carbon\Carbon',
249+
'timestamp' => '\Carbon\Carbon',
250+
'timestamptz' => '\Carbon\Carbon',
251+
'timestamps' => '\Carbon\Carbon',
252+
'timestampstz' => '\Carbon\Carbon',
253+
'tinyincrements' => 'integer',
254+
'tinyinteger' => 'int',
255+
'unsignedbiginteger' => 'int',
256+
'unsigneddecimal' => 'float',
257+
'unsignedinteger' => 'int',
258+
'unsignedmediuminteger' => 'int',
259+
'unsignedsmallinteger' => 'int',
260+
'unsignedtinyinteger' => 'int',
261+
'year' => 'int',
262+
];
263+
264+
return $php_data_types[strtolower($dataType)] ?? 'string';
265+
}
191266
}

stubs/model/class.stub

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace DummyNamespace;
44

55
use Illuminate\Database\Eloquent\Model;
6-
6+
/** DummyPHPDocClass **/
77
class DummyClass extends Model
88
{
99
// ...

tests/Feature/Generator/ModelGeneratorTest.php

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected function setUp(): void
3030
/**
3131
* @test
3232
*/
33-
public function output_writes_nothing_for_empty_tree()
33+
public function output_generates_nothing_for_empty_tree()
3434
{
3535
$this->files->expects('stub')
3636
->with('model/class.stub')
@@ -45,7 +45,7 @@ public function output_writes_nothing_for_empty_tree()
4545
* @test
4646
* @dataProvider modelTreeDataProvider
4747
*/
48-
public function output_writes_migration_for_model_tree($definition, $path, $model)
48+
public function output_generates_models($definition, $path, $model)
4949
{
5050
$this->files->expects('stub')
5151
->with('model/class.stub')
@@ -112,6 +112,45 @@ public function output_respects_configuration()
112112
$this->assertEquals(['created' => ['src/path/Models/Comment.php']], $this->subject->output($tree));
113113
}
114114

115+
/**
116+
* @test
117+
* @dataProvider docBlockModelsDataProvider
118+
*/
119+
public function output_generates_phpdoc_for_model($definition, $path, $model)
120+
{
121+
$this->app['config']->set('blueprint.generate_phpdocs', true);
122+
123+
$this->files->expects('stub')
124+
->with('model/class.stub')
125+
->andReturn(file_get_contents('stubs/model/class.stub'));
126+
127+
$this->files->expects('stub')
128+
->with('model/fillable.stub')
129+
->andReturn(file_get_contents('stubs/model/fillable.stub'));
130+
131+
$this->files->expects('stub')
132+
->with('model/casts.stub')
133+
->andReturn(file_get_contents('stubs/model/casts.stub'));
134+
135+
if ($definition === 'definitions/readme-example.bp') {
136+
$this->files->expects('stub')
137+
->with('model/dates.stub')
138+
->andReturn(file_get_contents('stubs/model/dates.stub'));
139+
}
140+
141+
$this->files->shouldReceive('stub')
142+
->with('model/method.stub')
143+
->andReturn(file_get_contents('stubs/model/method.stub'));
144+
145+
$this->files->expects('put')
146+
->with($path, $this->fixture($model));
147+
148+
$tokens = $this->blueprint->parse($this->fixture($definition));
149+
$tree = $this->blueprint->analyze($tokens);
150+
151+
$this->assertEquals(['created' => [$path]], $this->subject->output($tree));
152+
}
153+
115154
public function modelTreeDataProvider()
116155
{
117156
return [
@@ -123,4 +162,13 @@ public function modelTreeDataProvider()
123162
['definitions/nested-components.bp', 'app/Admin/User.php', 'models/nested-components.php'],
124163
];
125164
}
165+
166+
public function docBlockModelsDataProvider()
167+
{
168+
return [
169+
['definitions/readme-example.bp', 'app/Post.php', 'models/readme-example-phpdoc.php'],
170+
['definitions/soft-deletes.bp', 'app/Comment.php', 'models/soft-deletes-phpdoc.php'],
171+
['definitions/disable-auto-columns.bp', 'app/State.php', 'models/disable-auto-columns-phpdoc.php'],
172+
];
173+
}
126174
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
models:
2+
State:
3+
name: string
4+
code: string
5+
timestamps: false
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
/**
8+
* @property int $id
9+
* @property string $name
10+
* @property string $code
11+
*/
12+
class State extends Model
13+
{
14+
/**
15+
* The attributes that are mass assignable.
16+
*
17+
* @var array
18+
*/
19+
protected $fillable = [
20+
'name',
21+
'code',
22+
];
23+
24+
/**
25+
* The attributes that should be cast to native types.
26+
*
27+
* @var array
28+
*/
29+
protected $casts = [
30+
'id' => 'integer',
31+
];
32+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
/**
8+
* @property int $id
9+
* @property string $title
10+
* @property string $content
11+
* @property \Carbon\Carbon $published_at
12+
* @property \Carbon\Carbon $created_at
13+
* @property \Carbon\Carbon $updated_at
14+
*/
15+
class Post extends Model
16+
{
17+
/**
18+
* The attributes that are mass assignable.
19+
*
20+
* @var array
21+
*/
22+
protected $fillable = [
23+
'title',
24+
'content',
25+
'published_at',
26+
];
27+
28+
/**
29+
* The attributes that should be cast to native types.
30+
*
31+
* @var array
32+
*/
33+
protected $casts = [
34+
'id' => 'integer',
35+
];
36+
37+
/**
38+
* The attributes that should be mutated to dates.
39+
*
40+
* @var array
41+
*/
42+
protected $dates = [
43+
'published_at',
44+
];
45+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Illuminate\Database\Eloquent\SoftDeletes;
7+
8+
/**
9+
* @property int $id
10+
* @property int $post_id
11+
* @property \Carbon\Carbon $deleted_at
12+
* @property \Carbon\Carbon $created_at
13+
* @property \Carbon\Carbon $updated_at
14+
*/
15+
class Comment extends Model
16+
{
17+
use SoftDeletes;
18+
19+
/**
20+
* The attributes that are mass assignable.
21+
*
22+
* @var array
23+
*/
24+
protected $fillable = [
25+
'post_id',
26+
];
27+
28+
/**
29+
* The attributes that should be cast to native types.
30+
*
31+
* @var array
32+
*/
33+
protected $casts = [
34+
'id' => 'integer',
35+
'post_id' => 'integer',
36+
];
37+
38+
39+
public function post()
40+
{
41+
return $this->belongsTo(\App\Post::class);
42+
}
43+
}

0 commit comments

Comments
 (0)