diff --git a/CHANGELOG.md b/CHANGELOG.md index 70ed21894..c5af6856f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Added - Add support for `immutable_date:*` and `immutable_datetime:*` casts. [#1380 / thekonz](https://github.com/barryvdh/laravel-ide-helper/pull/1380) +- Added separation of phpdoc tags into groups [#1377 / Kerigard](https://github.com/barryvdh/laravel-ide-helper/pull/1377) 2023-02-04, 2.13.0 ------------------ diff --git a/README.md b/README.md index 92f04fa50..0e9dcebb8 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,33 @@ add support for creating a new dedicated class instead of using local scopes in If for some reason it's undesired to have them generated (one for each column), you can disable this via config `write_model_external_builder_methods` and setting it to `false`. +#### Separating docblock tags into groups + +By default, all docblock tags are written sequentially on each line. Problems can arise when using Laravel Pint or other linters because they use different formatting. + +Change the `phpdoc_separate_tags` setting in the config to `true` to fix this behavior. + +```php +// => before + +/** + * @property integer $id + * @property-write mixed $first_name Set the user's first name. + * @method static \Illuminate\Database\Eloquent\Builder|Post newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Post query() + */ + +// => after + +/** + * @property integer $id + * @property-write mixed $first_name Set the user's first name. + * + * @method static \Illuminate\Database\Eloquent\Builder|Post newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Post query() + */ +``` + #### Unsupported or custom database types Common column types (e.g. varchar, integer) are correctly mapped to PHP types (`string`, `int`). diff --git a/composer.json b/composer.json index 2eecae2de..19f3c6c93 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "require": { "php": "^7.3 || ^8.0", "ext-json": "*", - "barryvdh/reflection-docblock": "^2.0.6", + "barryvdh/reflection-docblock": "^2.1.0", "composer/class-map-generator": "^1.0", "doctrine/dbal": "^2.6 || ^3", "illuminate/console": "^8 || ^9 || ^10", diff --git a/config/ide-helper.php b/config/ide-helper.php index 80afdb2d1..e12f546c6 100644 --- a/config/ide-helper.php +++ b/config/ide-helper.php @@ -109,6 +109,17 @@ 'write_eloquent_model_mixins' => false, + /* + |-------------------------------------------------------------------------- + | PHPDOC: Separate Tag Groups + |-------------------------------------------------------------------------- + | + | Set to true to separate tags into groups with an empty string. + | + */ + + 'phpdoc_separate_tags' => false, + /* |-------------------------------------------------------------------------- | Helper files to include diff --git a/src/Alias.php b/src/Alias.php index 1907ecd0c..3c205bdb8 100644 --- a/src/Alias.php +++ b/src/Alias.php @@ -421,7 +421,8 @@ protected function getMacroFunction($macro_func) */ public function getDocComment($prefix = "\t\t") { - $serializer = new DocBlockSerializer(1, $prefix); + $separateTags = $this->config->get('ide-helper.phpdoc_separate_tags', false); + $serializer = new DocBlockSerializer(1, $prefix, true, null, $separateTags); if (!$this->phpdoc) { return ''; diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 9f9931f0c..6477dc3b2 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -106,6 +106,8 @@ class ModelsCommand extends Command protected $keep_text; protected $phpstorm_noinspections; protected $write_model_external_builder_methods; + protected $phpdoc_separate_tags = false; + /** * @var bool[string] */ @@ -158,6 +160,7 @@ public function handle() $this->write_model_external_builder_methods = $this->laravel['config']->get('ide-helper.write_model_external_builder_methods', true); $this->write_model_relation_count_properties = $this->laravel['config']->get('ide-helper.write_model_relation_count_properties', true); + $this->phpdoc_separate_tags = $this->laravel['config']->get('ide-helper.phpdoc_separate_tags', false); $this->write = $this->write_mixin ? true : $this->write; //If filename is default and Write is not specified, ask what to do @@ -1008,7 +1011,7 @@ protected function createPhpDocs($class) ); } - $serializer = new DocBlockSerializer(); + $serializer = new DocBlockSerializer(0, ' ', true, null, $this->phpdoc_separate_tags); $docComment = $serializer->getDocComment($phpdoc); if ($this->write_mixin) { diff --git a/src/Eloquent.php b/src/Eloquent.php index 23f39dd98..75bac4850 100644 --- a/src/Eloquent.php +++ b/src/Eloquent.php @@ -70,7 +70,8 @@ public static function writeEloquentModelHelper(Command $command, Filesystem $fi return; } - $serializer = new DocBlockSerializer(); + $separateTags = $command->getLaravel()['config']->get('ide-helper.phpdoc_separate_tags', false); + $serializer = new DocBlockSerializer(0, ' ', true, null, $separateTags); $serializer->getDocComment($phpdoc); $docComment = $serializer->getDocComment($phpdoc); diff --git a/src/Method.php b/src/Method.php index f7f7ffaaf..13793d90d 100644 --- a/src/Method.php +++ b/src/Method.php @@ -145,7 +145,7 @@ public function getRootMethodCall() */ public function getDocComment($prefix = "\t\t") { - $serializer = new DocBlockSerializer(1, $prefix); + $serializer = new DocBlockSerializer(1, $prefix, true, null, config('ide-helper.phpdoc_separate_tags', false)); return $serializer->getDocComment($this->phpdoc); } diff --git a/tests/Console/ModelsCommand/SeparateTags/Models/Post.php b/tests/Console/ModelsCommand/SeparateTags/Models/Post.php new file mode 100644 index 000000000..bb7cba956 --- /dev/null +++ b/tests/Console/ModelsCommand/SeparateTags/Models/Post.php @@ -0,0 +1,24 @@ +hasMany(Post::class); + } +} diff --git a/tests/Console/ModelsCommand/SeparateTags/Test.php b/tests/Console/ModelsCommand/SeparateTags/Test.php new file mode 100644 index 000000000..68354af41 --- /dev/null +++ b/tests/Console/ModelsCommand/SeparateTags/Test.php @@ -0,0 +1,31 @@ +set('ide-helper.phpdoc_separate_tags', true); + } + + 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(); + } +} diff --git a/tests/Console/ModelsCommand/SeparateTags/__snapshots__/Test__test__1.php b/tests/Console/ModelsCommand/SeparateTags/__snapshots__/Test__test__1.php new file mode 100644 index 000000000..577afb261 --- /dev/null +++ b/tests/Console/ModelsCommand/SeparateTags/__snapshots__/Test__test__1.php @@ -0,0 +1,183 @@ + $posts + * @property-read int|null $posts_count + * @property-write mixed $first_name Set the user's first name. + * + * @method static \Illuminate\Database\Eloquent\Builder|Post newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Post newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Post query() + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBigIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBigIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBinaryNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBinaryNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBooleanNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereBooleanNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereCharNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereCharNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDateNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDateNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDatetimeNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDatetimeNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDatetimetzNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDatetimetzNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDecimalNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDecimalNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDoubleNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereDoubleNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereEnumNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereEnumNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereFloatNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereFloatNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereIpaddressNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereIpaddressNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereJsonNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereJsonNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereJsonbNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereJsonbNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereLongTextNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereLongTextNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMacaddressNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMacaddressNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMediumIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMediumIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMediumTextNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereMediumTextNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereSmallIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereSmallIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereStringNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereStringNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTextNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTextNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimeNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimeNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimestampNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimestampNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimestamptzNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimestamptzNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimetzNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTimetzNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTinyIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereTinyIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedBigIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedBigIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedDecimalNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedDecimalNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedMediumIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedMediumIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedSmallIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedSmallIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedTinyIntegerNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUnsignedTinyIntegerNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUuidNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereUuidNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereYearNotNullable($value) + * @method static \Illuminate\Database\Eloquent\Builder|Post whereYearNullable($value) + * + * @mixin \Eloquent + */ +class Post extends Model +{ + /** + * @comment Set the user's first name. + * @param $value + */ + public function setFirstNameAttribute($value) + { + } + + public function posts(): HasMany + { + return $this->hasMany(Post::class); + } +} diff --git a/tests/MethodTest.php b/tests/MethodTest.php index 98010b0f3..67a078f03 100644 --- a/tests/MethodTest.php +++ b/tests/MethodTest.php @@ -6,10 +6,19 @@ use Barryvdh\LaravelIdeHelper\Method; use Illuminate\Database\Eloquent\Builder; -use PHPUnit\Framework\TestCase; +use Illuminate\Database\Eloquent\Model; class MethodTest extends TestCase { + protected function getEnvironmentSetUp($app) + { + parent::getEnvironmentSetUp($app); + + if ($this->getName() == 'testSeparateTags') { + $app['config']->set('ide-helper.phpdoc_separate_tags', true); + } + } + /** * Test that we can actually instantiate the class */ @@ -128,6 +137,39 @@ public function testClassAliases() $this->assertSame([], $method->getParamsWithDefault(false)); $this->assertTrue($method->shouldReturn()); } + + /** + * Test class output when separating tag groups + */ + public function testSeparateTags() + { + $reflectionClass = new \ReflectionClass(Model::class); + $reflectionMethod = $reflectionClass->getMethod('toJson'); + + $method = new Method($reflectionMethod, 'Model', $reflectionClass); + + $output = <<<'DOC' +/** + * Convert the model instance to JSON. + * + * @param int $options + * @return string + * + * @throws \Illuminate\Database\Eloquent\JsonEncodingException + * + * @static + */ +DOC; + + $this->assertSame($output, $method->getDocComment('')); + $this->assertSame('toJson', $method->getName()); + $this->assertSame('\\' . Model::class, $method->getDeclaringClass()); + $this->assertSame('$options', $method->getParams(true)); + $this->assertSame(['$options'], $method->getParams(false)); + $this->assertSame('$options = 0', $method->getParamsWithDefault(true)); + $this->assertSame(['$options = 0'], $method->getParamsWithDefault(false)); + $this->assertTrue($method->shouldReturn()); + } } class ExampleClass