Skip to content

Commit c5c9b2b

Browse files
biiiiiigmonstermfn
andauthored
Add comments like table columns. (#1168)
* add comment with @method & @property-read & property-write in models * add readme comment * add readme comment * add comment tag unit-test * add comment tag unit-test * both a getter and a setter has a @comment test * Update README.md improve README Co-authored-by: Markus Podar <[email protected]> * Update CHANGELOG.md Co-authored-by: Markus Podar <[email protected]>
1 parent c5e18be commit c5c9b2b

File tree

6 files changed

+393
-8
lines changed

6 files changed

+393
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66
--------------
77
### Added
88
- Generate PHPDoc for Laravel 8.x factories [\#1074 / ahmed-aliraqi](https://github.com/barryvdh/laravel-ide-helper/pull/1074)
9+
- Add a comment to a property like table columns [\#1168 / biiiiiigmonster](https://github.com/barryvdh/laravel-ide-helper/pull/1168)
910

1011
### Fixed
1112
- Error when generating helper for invokable classes [\#1124 / standaniels](https://github.com/barryvdh/laravel-ide-helper/pull/1124)

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,33 @@ You may use the [`::withCount`](https://laravel.com/docs/master/eloquent-relatio
216216

217217
By default, these attributes are generated in the phpdoc. You can turn them off by setting the config `write_model_relation_count_properties` to `false`.
218218

219+
#### Support `@comment` based on DocBlock
220+
221+
In order to better support IDEs, relations and getters/setters can also add a comment to a property like table columns. Therefore a custom docblock `@comment` is used:
222+
```php
223+
class Users extends Model
224+
{
225+
/**
226+
* @comment Get User's full name
227+
*
228+
* @return string
229+
*/
230+
public function getFullNameAttribute(): string
231+
{
232+
return $this->first_name . ' ' .$this->last_name ;
233+
}
234+
}
235+
236+
// => after generate models
237+
238+
/**
239+
* App\Models\Users
240+
*
241+
* @property-read string $full_name Get User's full name
242+
* …
243+
*/
244+
```
245+
219246
#### Dedicated Eloquent Builder methods
220247

221248
A new method to the eloquent models was added called `newEloquentBuilder` [Reference](https://timacdonald.me/dedicated-eloquent-model-query-builders/) where we can

src/Console/ModelsCommand.php

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ protected function getPropertiesFromMethods($model)
527527
$reflection = new \ReflectionMethod($model, $method);
528528
$type = $this->getReturnType($reflection);
529529
$type = $this->getTypeInModel($model, $type);
530-
$this->setProperty($name, $type, true, null);
530+
$comment = $this->getCommentFromDocBlock($reflection);
531+
$this->setProperty($name, $type, true, null, $comment);
531532
}
532533
} elseif (
533534
Str::startsWith($method, 'set') && Str::endsWith(
@@ -538,13 +539,16 @@ protected function getPropertiesFromMethods($model)
538539
//Magic set<name>Attribute
539540
$name = Str::snake(substr($method, 3, -9));
540541
if (!empty($name)) {
541-
$this->setProperty($name, null, null, true);
542+
$reflection = new \ReflectionMethod($model, $method);
543+
$comment = $this->getCommentFromDocBlock($reflection);
544+
$this->setProperty($name, null, null, true, $comment);
542545
}
543546
} elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') {
544547
//Magic set<name>Attribute
545548
$name = Str::camel(substr($method, 5));
546549
if (!empty($name)) {
547550
$reflection = new \ReflectionMethod($model, $method);
551+
$comment = $this->getCommentFromDocBlock($reflection);
548552
$args = $this->getParameters($reflection);
549553
//Remove the first ($query) argument
550554
array_shift($args);
@@ -556,7 +560,7 @@ protected function getPropertiesFromMethods($model)
556560
$reflection->getDeclaringClass(),
557561
$reflection->getDeclaringClass()->getName()
558562
);
559-
$this->setMethod($name, $builder . '|' . $modelName, $args);
563+
$this->setMethod($name, $builder . '|' . $modelName, $args, $comment);
560564
}
561565
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) {
562566
$builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery()));
@@ -608,6 +612,7 @@ protected function getPropertiesFromMethods($model)
608612
continue;
609613
}
610614

615+
$comment = $this->getCommentFromDocBlock($reflection);
611616
// Adding constraints requires reading model properties which
612617
// can cause errors. Since we don't need constraints we can
613618
// disable them when we fetch the relation to avoid errors.
@@ -639,14 +644,16 @@ protected function getPropertiesFromMethods($model)
639644
$method,
640645
$collectionClassNameInModel . '|' . $relatedModel . '[]',
641646
true,
642-
null
647+
null,
648+
$comment
643649
);
644650
if ($this->write_model_relation_count_properties) {
645651
$this->setProperty(
646652
Str::snake($method) . '_count',
647653
'int|null',
648654
true,
649655
false
656+
// What kind of comments should be added to the relation count here?
650657
);
651658
}
652659
} elseif ($relation === 'morphTo') {
@@ -655,7 +662,8 @@ protected function getPropertiesFromMethods($model)
655662
$method,
656663
$this->getClassNameInDestinationFile($model, Model::class) . '|\Eloquent',
657664
true,
658-
null
665+
null,
666+
$comment
659667
);
660668
} else {
661669
//Single model is returned
@@ -664,7 +672,7 @@ protected function getPropertiesFromMethods($model)
664672
$relatedModel,
665673
true,
666674
null,
667-
'',
675+
$comment,
668676
$this->isRelationNullable($relation, $relationObj)
669677
);
670678
}
@@ -737,14 +745,15 @@ protected function setProperty($name, $type = null, $read = null, $write = null,
737745
}
738746
}
739747

740-
protected function setMethod($name, $type = '', $arguments = [])
748+
protected function setMethod($name, $type = '', $arguments = [], $comment = '')
741749
{
742750
$methods = array_change_key_case($this->methods, CASE_LOWER);
743751

744752
if (!isset($methods[strtolower($name)])) {
745753
$this->methods[$name] = [];
746754
$this->methods[$name]['type'] = $type;
747755
$this->methods[$name]['arguments'] = $arguments;
756+
$this->methods[$name]['comment'] = $comment;
748757
}
749758
}
750759

@@ -820,7 +829,11 @@ protected function createPhpDocs($class)
820829
continue;
821830
}
822831
$arguments = implode(', ', $method['arguments']);
823-
$tag = Tag::createInstance("@method static {$method['type']} {$name}({$arguments})", $phpdoc);
832+
$tagLine = "@method static {$method['type']} {$name}({$arguments})";
833+
if ($method['comment'] !== '') {
834+
$tagLine .= " {$method['comment']}";
835+
}
836+
$tag = Tag::createInstance($tagLine, $phpdoc);
824837
$phpdoc->appendTag($tag);
825838
}
826839

@@ -980,6 +993,30 @@ protected function getReturnType(\ReflectionMethod $reflection): ?string
980993
return $this->getReturnTypeFromReflection($reflection);
981994
}
982995

996+
/**
997+
* Get method comment based on it DocBlock comment
998+
*
999+
* @param \ReflectionMethod $reflection
1000+
*
1001+
* @return null|string
1002+
*/
1003+
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
1004+
{
1005+
$phpDocContext = (new ContextFactory())->createFromReflector($reflection);
1006+
$context = new Context(
1007+
$phpDocContext->getNamespace(),
1008+
$phpDocContext->getNamespaceAliases()
1009+
);
1010+
$comment = '';
1011+
$phpdoc = new DocBlock($reflection, $context);
1012+
1013+
if ($phpdoc->hasTag('comment')) {
1014+
$comment = $phpdoc->getTagsByName('comment')[0]->getContent();
1015+
}
1016+
1017+
return $comment;
1018+
}
1019+
9831020
/**
9841021
* Get method return type based on it DocBlock comment
9851022
*
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment\Models;
6+
7+
use Illuminate\Database\Eloquent\Model;
8+
use Illuminate\Database\Eloquent\Relations\HasMany;
9+
use Illuminate\Database\Eloquent\Relations\HasOne;
10+
use Illuminate\Database\Eloquent\Relations\MorphTo;
11+
12+
class Simple extends Model
13+
{
14+
/**
15+
* There is not comment.
16+
*
17+
* @return string
18+
*/
19+
public function getNotCommentAttribute(): string
20+
{
21+
}
22+
23+
/**
24+
* comment There is not format comment, invalid.
25+
*
26+
* @return string
27+
*/
28+
public function getFakerCommentAttribute(): string
29+
{
30+
}
31+
32+
/**
33+
* @comment There is format comment, success.
34+
*
35+
* @return string
36+
*/
37+
public function getFormatCommentAttribute(): string
38+
{
39+
}
40+
41+
/**
42+
* @comment There is format comment, success.
43+
* This is second line, success too.
44+
*
45+
* @return string
46+
*/
47+
public function getFormatCommentLineTwoAttribute(): string
48+
{
49+
}
50+
51+
/**
52+
* @comment There is format comment, success.
53+
* @comment This is others format comment, invalid.
54+
*
55+
* @return string
56+
*/
57+
public function getManyFormatCommentAttribute(): string
58+
{
59+
}
60+
61+
/**
62+
* @comment Set the user's first name.
63+
* @param $value
64+
*/
65+
public function setFirstNameAttribute($value)
66+
{
67+
}
68+
69+
/**
70+
* @comment Scope a query to only include active users.
71+
*
72+
* @param $query
73+
* @return mixed
74+
*/
75+
public function scopeActive($query)
76+
{
77+
return $query;
78+
}
79+
80+
/**
81+
* @comment HasMany relations.
82+
*
83+
* @return HasMany
84+
*/
85+
public function relationHasMany(): HasMany
86+
{
87+
return $this->hasMany(Simple::class);
88+
}
89+
90+
/**
91+
* @comment MorphTo relations.
92+
* @return MorphTo
93+
*/
94+
public function relationMorphTo(): MorphTo
95+
{
96+
return $this->morphTo();
97+
}
98+
99+
/**
100+
* @comment Others relations.
101+
* @return HasOne
102+
*/
103+
public function relationHasOne(): HasOne
104+
{
105+
return $this->hasOne(Simple::class);
106+
}
107+
108+
/**
109+
* @comment I'm a setter
110+
*/
111+
public function setBothSameNameAttribute(): void
112+
{
113+
}
114+
115+
/**
116+
* @comment I'm a getter
117+
* @return string
118+
*/
119+
public function getBothSameNameAttribute(): string
120+
{
121+
}
122+
123+
/**
124+
* @comment I'm a setter
125+
*/
126+
public function setBothWithoutGetterCommentAttribute(): void
127+
{
128+
}
129+
130+
/**
131+
* @return string
132+
*/
133+
public function getBothWithoutGetterCommentAttribute(): string
134+
{
135+
}
136+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment;
6+
7+
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
8+
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
9+
10+
class Test extends AbstractModelsCommand
11+
{
12+
public function test(): void
13+
{
14+
$command = $this->app->make(ModelsCommand::class);
15+
16+
$tester = $this->runCommand($command, [
17+
'--write' => true,
18+
]);
19+
20+
$this->assertSame(0, $tester->getStatusCode());
21+
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
22+
$this->assertMatchesMockedSnapshot();
23+
}
24+
}

0 commit comments

Comments
 (0)