使用扩展包
github:https://github.com/barryvdh/laravel-ide-helper
composer require --dev barryvdh/laravel-ide-helper
原理
# @property string $id
通过注释中的 @property 提示这个类有哪些属性
# @method \Illuminate\Database\Eloquent\Builder|User whereId($value)
通过注释中的 @method 提示这个类有哪些方法
常用方法
命令 | 作用 |
---|---|
php artisan ide-helper:models | 给所有模型添加注释 |
php artisan ide-helper:models “App\Models\Auth\User” | 给指定模型添加注释 |
php artisan ide-helper:models -R “App\Models\Auth\User” | 给指定模型重新添加注释,会覆盖原有注释 |
缺陷
* @method static \Illuminate\Database\Eloquent\Builder|User whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereMobile($value)
* @method static \Illuminate\Database\Eloquent\Builder|User wherePassword($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereCreator($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUpdater($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereDeleted($value)
* @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User query()
# 链式写法没有提示whereId,因为whereId 是 static
# 改成 @method \Illuminate\Database\Eloquent\Builder|User whereId($value) 就有提示了
User::query()->whereId(1)
改造
创建了自己的artisan命令 ide-helper-pro
并继承了laravel-ide-helper的创建模型注释命令
并对其稍作修改
namespace App\Console\Commands;
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Context;
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
use Barryvdh\Reflection\DocBlock\Tag;
use Illuminate\Support\Str;
class create extends ModelsCommand
{
protected $name = 'ide-helper-pro:models';
protected $description = 'Generate autocompletion for models';
protected function createPhpDocs($class)
{
$reflection = new \ReflectionClass($class);
$namespace = $reflection->getNamespaceName();
$classname = $reflection->getShortName();
$originalDoc = $reflection->getDocComment();
$keyword = $this->getClassKeyword($reflection);
$interfaceNames = array_diff_key(
$reflection->getInterfaceNames(),
$reflection->getParentClass()->getInterfaceNames()
);
if ($this->reset) {
$phpdoc = new DocBlock('', new Context($namespace));
if ($this->keep_text) {
$phpdoc->setText(
(new DocBlock($reflection, new Context($namespace)))->getText()
);
}
} else {
$phpdoc = new DocBlock($reflection, new Context($namespace));
}
if (!$phpdoc->getText()) {
$phpdoc->setText($class);
}
$properties = [];
$methods = [];
foreach ($phpdoc->getTags() as $tag) {
$name = $tag->getName();
if ($name == 'property' || $name == 'property-read' || $name == 'property-write') {
$properties[] = $tag->getVariableName();
} elseif ($name == 'method') {
$methods[] = $tag->getMethodName();
}
}
foreach ($this->properties as $name => $property) {
$name = "\$$name";
if ($this->hasCamelCaseModelProperties()) {
$name = Str::camel($name);
}
if (in_array($name, $properties)) {
continue;
}
if ($property['read'] && $property['write']) {
$attr = 'property';
} elseif ($property['write']) {
$attr = 'property-write';
} else {
$attr = 'property-read';
}
$tagLine = trim("@{$attr} {$property['type']} {$name} {$property['comment']}");
$tag = Tag::createInstance($tagLine, $phpdoc);
$phpdoc->appendTag($tag);
}
foreach ($this->methods as $name => $method) {
if (in_array($name, $methods)) {
continue;
}
$arguments = implode(', ', $method['arguments']);
# 主要是这部分
# 稍作修改
# 是以where开头的方法不设置成 static
if (!Str::startsWith($name, 'where')) {
$tagLine = "@method static {$method['type']} {$name}({$arguments})";
} else {
$tagLine = "@method {$method['type']} {$name}({$arguments})";
}
if ($method['comment'] !== '') {
$tagLine .= " {$method['comment']}";
}
$tag = Tag::createInstance($tagLine, $phpdoc);
$phpdoc->appendTag($tag);
}
if ($this->write && !$phpdoc->getTagsByName('mixin')) {
$eloquentClassNameInModel = $this->getClassNameInDestinationFile($reflection, 'Eloquent');
$phpdoc->appendTag(Tag::createInstance('@mixin ' . $eloquentClassNameInModel, $phpdoc));
}
if ($this->phpstorm_noinspections) {
/**
* Facades, Eloquent API
* @see https://www.jetbrains.com/help/phpstorm/php-fully-qualified-name-usage.html
*/
$phpdoc->appendTag(Tag::createInstance('@noinspection PhpFullyQualifiedNameUsageInspection', $phpdoc));
/**
* Relations, other models in the same namespace
* @see https://www.jetbrains.com/help/phpstorm/php-unnecessary-fully-qualified-name.html
*/
$phpdoc->appendTag(
Tag::createInstance('@noinspection PhpUnnecessaryFullyQualifiedNameInspection', $phpdoc)
);
}
$serializer = new DocBlockSerializer();
$docComment = $serializer->getDocComment($phpdoc);
if ($this->write_mixin) {
$phpdocMixin = new DocBlock($reflection, new Context($namespace));
// remove all mixin tags prefixed with IdeHelper
foreach ($phpdocMixin->getTagsByName('mixin') as $tag) {
if (Str::startsWith($tag->getContent(), 'IdeHelper')) {
$phpdocMixin->deleteTag($tag);
}
}
$mixinClassName = "IdeHelper{$classname}";
$phpdocMixin->appendTag(Tag::createInstance("@mixin {$mixinClassName}", $phpdocMixin));
$mixinDocComment = $serializer->getDocComment($phpdocMixin);
// remove blank lines if there's no text
if (!$phpdocMixin->getText()) {
$mixinDocComment = preg_replace("/\s\*\s*\n/", '', $mixinDocComment);
}
foreach ($phpdoc->getTagsByName('mixin') as $tag) {
if (Str::startsWith($tag->getContent(), 'IdeHelper')) {
$phpdoc->deleteTag($tag);
}
}
$docComment = $serializer->getDocComment($phpdoc);
}
if ($this->write) {
$modelDocComment = $this->write_mixin ? $mixinDocComment : $docComment;
$filename = $reflection->getFileName();
$contents = $this->files->get($filename);
if ($originalDoc) {
$contents = str_replace($originalDoc, $modelDocComment, $contents);
} else {
$replace = "{$modelDocComment}\n";
$pos = strpos($contents, "final class {$classname}") ?: strpos($contents, "class {$classname}");
if ($pos !== false) {
$contents = substr_replace($contents, $replace, $pos, 0);
}
}
if ($this->files->put($filename, $contents)) {
$this->info('Written new phpDocBlock to ' . $filename);
}
}
$classname = $this->write_mixin ? $mixinClassName : $classname;
$output = "namespace {$namespace}{\n{$docComment}\n\t{$keyword}class {$classname} ";
if (!$this->write_mixin) {
$output .= "extends \Eloquent ";
if ($interfaceNames) {
$interfaces = implode(', \\', $interfaceNames);
$output .= "implements \\{$interfaces} ";
}
}
return $output . "{}\n}\n\n";
}
}
改造后的结果
/**
* App\Models\Auth\User
*
* @property string $id
* @property string $name
* @property string $mobile
* @property string $password
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property bool $creator
* @property int $updater
* @property int|null $deleted 删除标记
* @method \Illuminate\Database\Eloquent\Builder|User whereId($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereName($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereMobile($value)
* @method \Illuminate\Database\Eloquent\Builder|User wherePassword($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereCreator($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereUpdater($value)
* @method \Illuminate\Database\Eloquent\Builder|User whereDeleted($value)
* @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User query()
* @mixin \Eloquent
*/