Skip to content

Add comments like table columns. #1168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 15, 2021
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -216,6 +216,33 @@ You may use the [`::withCount`](https://laravel.com/docs/master/eloquent-relatio

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`.

#### Support `@comment` based on DocBlock

In order to better support ide, relations and getters/setters can also add comments like table columns. Only based on DocBlock, use `@comment`. example:
```php
class Users extends Model
{
/**
* @comment Get User's full name
*
* @return string
*/
public function getFullNameAttribute(): string
{
return $this->first_name . ' ' .$this->last_name ;
}
}

// => after generate models

/**
* App\Models\Users
*
* @property-read string $full_name Get User's full name
* …
*/
```

#### Dedicated Eloquent Builder methods

A new method to the eloquent models was added called `newEloquentBuilder` [Reference](https://timacdonald.me/dedicated-eloquent-model-query-builders/) where we can
53 changes: 45 additions & 8 deletions src/Console/ModelsCommand.php
Original file line number Diff line number Diff line change
@@ -527,7 +527,8 @@ protected function getPropertiesFromMethods($model)
$reflection = new \ReflectionMethod($model, $method);
$type = $this->getReturnType($reflection);
$type = $this->getTypeInModel($model, $type);
$this->setProperty($name, $type, true, null);
$comment = $this->getCommentFromDocBlock($reflection);
$this->setProperty($name, $type, true, null, $comment);
}
} elseif (
Str::startsWith($method, 'set') && Str::endsWith(
@@ -538,13 +539,16 @@ protected function getPropertiesFromMethods($model)
//Magic set<name>Attribute
$name = Str::snake(substr($method, 3, -9));
if (!empty($name)) {
$this->setProperty($name, null, null, true);
$reflection = new \ReflectionMethod($model, $method);
$comment = $this->getCommentFromDocBlock($reflection);
$this->setProperty($name, null, null, true, $comment);
}
} elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') {
//Magic set<name>Attribute
$name = Str::camel(substr($method, 5));
if (!empty($name)) {
$reflection = new \ReflectionMethod($model, $method);
$comment = $this->getCommentFromDocBlock($reflection);
$args = $this->getParameters($reflection);
//Remove the first ($query) argument
array_shift($args);
@@ -556,7 +560,7 @@ protected function getPropertiesFromMethods($model)
$reflection->getDeclaringClass(),
$reflection->getDeclaringClass()->getName()
);
$this->setMethod($name, $builder . '|' . $modelName, $args);
$this->setMethod($name, $builder . '|' . $modelName, $args, $comment);
}
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) {
$builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery()));
@@ -608,6 +612,7 @@ protected function getPropertiesFromMethods($model)
continue;
}

$comment = $this->getCommentFromDocBlock($reflection);
// Adding constraints requires reading model properties which
// can cause errors. Since we don't need constraints we can
// disable them when we fetch the relation to avoid errors.
@@ -639,14 +644,16 @@ protected function getPropertiesFromMethods($model)
$method,
$collectionClassNameInModel . '|' . $relatedModel . '[]',
true,
null
null,
$comment
);
if ($this->write_model_relation_count_properties) {
$this->setProperty(
Str::snake($method) . '_count',
'int|null',
true,
false
// What kind of comments should be added to the relation count here?
);
}
} elseif ($relation === 'morphTo') {
@@ -655,7 +662,8 @@ protected function getPropertiesFromMethods($model)
$method,
$this->getClassNameInDestinationFile($model, Model::class) . '|\Eloquent',
true,
null
null,
$comment
);
} else {
//Single model is returned
@@ -664,7 +672,7 @@ protected function getPropertiesFromMethods($model)
$relatedModel,
true,
null,
'',
$comment,
$this->isRelationNullable($relation, $relationObj)
);
}
@@ -737,14 +745,15 @@ protected function setProperty($name, $type = null, $read = null, $write = null,
}
}

protected function setMethod($name, $type = '', $arguments = [])
protected function setMethod($name, $type = '', $arguments = [], $comment = '')
{
$methods = array_change_key_case($this->methods, CASE_LOWER);

if (!isset($methods[strtolower($name)])) {
$this->methods[$name] = [];
$this->methods[$name]['type'] = $type;
$this->methods[$name]['arguments'] = $arguments;
$this->methods[$name]['comment'] = $comment;
}
}

@@ -820,7 +829,11 @@ protected function createPhpDocs($class)
continue;
}
$arguments = implode(', ', $method['arguments']);
$tag = Tag::createInstance("@method static {$method['type']} {$name}({$arguments})", $phpdoc);
$tagLine = "@method static {$method['type']} {$name}({$arguments})";
if ($method['comment'] !== '') {
$tagLine .= " {$method['comment']}";
}
$tag = Tag::createInstance($tagLine, $phpdoc);
$phpdoc->appendTag($tag);
}

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

/**
* Get method comment based on it DocBlock comment
*
* @param \ReflectionMethod $reflection
*
* @return null|string
*/
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
{
$phpDocContext = (new ContextFactory())->createFromReflector($reflection);
$context = new Context(
$phpDocContext->getNamespace(),
$phpDocContext->getNamespaceAliases()
);
$comment = '';
$phpdoc = new DocBlock($reflection, $context);

if ($phpdoc->hasTag('comment')) {
$comment = $phpdoc->getTagsByName('comment')[0]->getContent();
}

return $comment;
}

/**
* Get method return type based on it DocBlock comment
*
136 changes: 136 additions & 0 deletions tests/Console/ModelsCommand/Comment/Models/Simple.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

declare(strict_types=1);

namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;

class Simple extends Model
{
/**
* There is not comment.
*
* @return string
*/
public function getNotCommentAttribute(): string
{
}

/**
* comment There is not format comment, invalid.
*
* @return string
*/
public function getFakerCommentAttribute(): string
{
}

/**
* @comment There is format comment, success.
*
* @return string
*/
public function getFormatCommentAttribute(): string
{
}

/**
* @comment There is format comment, success.
* This is second line, success too.
*
* @return string
*/
public function getFormatCommentLineTwoAttribute(): string
{
}

/**
* @comment There is format comment, success.
* @comment This is others format comment, invalid.
*
* @return string
*/
public function getManyFormatCommentAttribute(): string
{
}

/**
* @comment Set the user's first name.
* @param $value
*/
public function setFirstNameAttribute($value)
{
}

/**
* @comment Scope a query to only include active users.
*
* @param $query
* @return mixed
*/
public function scopeActive($query)
{
return $query;
}

/**
* @comment HasMany relations.
*
* @return HasMany
*/
public function relationHasMany(): HasMany
{
return $this->hasMany(Simple::class);
}

/**
* @comment MorphTo relations.
* @return MorphTo
*/
public function relationMorphTo(): MorphTo
{
return $this->morphTo();
}

/**
* @comment Others relations.
* @return HasOne
*/
public function relationHasOne(): HasOne
{
return $this->hasOne(Simple::class);
}

/**
* @comment I'm a setter
*/
public function setBothSameNameAttribute(): void
{
}

/**
* @comment I'm a getter
* @return string
*/
public function getBothSameNameAttribute(): string
{
}

/**
* @comment I'm a setter
*/
public function setBothWithoutGetterCommentAttribute(): void
{
}

/**
* @return string
*/
public function getBothWithoutGetterCommentAttribute(): string
{
}
}
24 changes: 24 additions & 0 deletions tests/Console/ModelsCommand/Comment/Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment;

use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;

class Test extends AbstractModelsCommand
{
public function test(): void
{
$command = $this->app->make(ModelsCommand::class);

$tester = $this->runCommand($command, [
'--write' => true,
]);

$this->assertSame(0, $tester->getStatusCode());
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
$this->assertMatchesMockedSnapshot();
}
}
160 changes: 160 additions & 0 deletions tests/Console/ModelsCommand/Comment/__snapshots__/Test__test__1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?php

declare(strict_types=1);

namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;

/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Comment\Models\Simple
*
* @property integer $id
* @property string $both_same_name I'm a getter
* @property string $both_without_getter_comment
* @property-read string $faker_comment
* @property-read string $format_comment There is format comment, success.
* @property-read string $format_comment_line_two There is format comment, success.
* This is second line, success too.
* @property-read string $many_format_comment There is format comment, success.
* @property-read string $not_comment
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationHasMany HasMany relations.
* @property-read int|null $relation_has_many_count
* @property-read Simple|null $relationHasOne Others relations.
* @property-read Model|\Eloquent $relationMorphTo MorphTo relations.
* @property-write mixed $first_name Set the user's first name.
* @method static \Illuminate\Database\Eloquent\Builder|Simple active() Scope a query to only include active users.
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple query()
* @method static \Illuminate\Database\Eloquent\Builder|Simple whereId($value)
* @mixin \Eloquent
*/
class Simple extends Model
{
/**
* There is not comment.
*
* @return string
*/
public function getNotCommentAttribute(): string
{
}

/**
* comment There is not format comment, invalid.
*
* @return string
*/
public function getFakerCommentAttribute(): string
{
}

/**
* @comment There is format comment, success.
*
* @return string
*/
public function getFormatCommentAttribute(): string
{
}

/**
* @comment There is format comment, success.
* This is second line, success too.
*
* @return string
*/
public function getFormatCommentLineTwoAttribute(): string
{
}

/**
* @comment There is format comment, success.
* @comment This is others format comment, invalid.
*
* @return string
*/
public function getManyFormatCommentAttribute(): string
{
}

/**
* @comment Set the user's first name.
* @param $value
*/
public function setFirstNameAttribute($value)
{
}

/**
* @comment Scope a query to only include active users.
*
* @param $query
* @return mixed
*/
public function scopeActive($query)
{
return $query;
}

/**
* @comment HasMany relations.
*
* @return HasMany
*/
public function relationHasMany(): HasMany
{
return $this->hasMany(Simple::class);
}

/**
* @comment MorphTo relations.
* @return MorphTo
*/
public function relationMorphTo(): MorphTo
{
return $this->morphTo();
}

/**
* @comment Others relations.
* @return HasOne
*/
public function relationHasOne(): HasOne
{
return $this->hasOne(Simple::class);
}

/**
* @comment I'm a setter
*/
public function setBothSameNameAttribute(): void
{
}

/**
* @comment I'm a getter
* @return string
*/
public function getBothSameNameAttribute(): string
{
}

/**
* @comment I'm a setter
*/
public function setBothWithoutGetterCommentAttribute(): void
{
}

/**
* @return string
*/
public function getBothWithoutGetterCommentAttribute(): string
{
}
}