Compare commits

..
4 Commits
Author SHA1 Message Date
Markus Podar 64a6b90258 [2.9] Drop support for: Laravel 6, Laravel 7, PHP 7.2 and add doctrine/dbal ^3 (#1114)
* composer.json: drop support for PHP 7.2/Laravel 6+7 and bump dependencies

* tests: remove framework version tests

They don't apply anymore, we're Laravel 8+ only from now on

* changelog: update for ending support for L6/7 and PHP7.2
2020-12-29 11:11:05 +01:00
Aleksei Lebedev 25cc68c75f Macro::initPhpDoc() will save original docblock if present. (#1116)
* `Macro::initPhpDoc()` will save original docblock if present.

* Added `MacroTest::testInitPhpDocClosureWithoutDocBlock()`.

* Mock class rename.

* Code cleanup.
2020-12-23 12:26:18 +01:00
Aleksei Lebedev 36c4406b3a Alias will grab macros from \Illuminate\Database\Eloquent\Builder too (#1118)
* `Alias` will grab macros from `\Illuminate\Database\Eloquent\Builder` too.

* `@return` will contains `|static` for Eloquent Builder macros which return Eloquent Builder instance.

* `Macro` tests.

* `Alias::detectMethods()` tests.

* Mock classes rename.
2020-12-21 11:15:47 +01:00
Barry vd. Heuvel 9ba2f5c557 Update run-static-analysis.yml (#1131) 2020-12-21 09:34:43 +01:00
11 changed files with 373 additions and 57 deletions
+4 -14
View File
@@ -18,15 +18,8 @@ jobs:
COMPOSER_NO_INTERACTION: 1
strategy:
matrix:
php: [8.0, 7.4, 7.3, 7.2]
lumen: [8.*, 7.*, 6.*]
exclude:
- lumen: 6.*
php: 8.0
- lumen: 7.*
php: 8.0
- lumen: 8.*
php: 7.2
php: [8.0, 7.4, 7.3]
lumen: [8.*]
name: P${{ matrix.php }} - Lumen${{ matrix.lumen }}
steps:
- name: Checkout code
@@ -82,11 +75,8 @@ jobs:
COMPOSER_NO_INTERACTION: 1
strategy:
matrix:
php: [7.4, 7.3, 7.2]
laravel: [8.*, 7.*, 6.*]
exclude:
- laravel: 8.*
php: 7.2
php: [8.0, 7.4, 7.3]
laravel: [8.*]
name: P${{ matrix.php }} - Laravel${{ matrix.laravel }}
steps:
- name: Checkout code
@@ -13,6 +13,13 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
coverage: none
extensions: pdo_sqlite
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
+2 -4
View File
@@ -19,12 +19,10 @@ jobs:
strategy:
matrix:
php: [8.0, 7.4, 7.3, 7.2]
laravel: [8.*, 7.*, 6.*]
php: [8.0, 7.4, 7.3]
laravel: [8.*]
dependency-version: [prefer-lowest, prefer-stable]
exclude:
- laravel: 8.*
php: 7.2
- php: 8.0
dependency-version: prefer-lowest
+2
View File
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
[Next release](https://github.com/barryvdh/laravel-ide-helper/compare/v2.8.1...master)
--------------
### Changed
- Dropped support for Laravel 6 and Laravel 7, as well as support for PHP 7.2 [\# / mfn]()
### Added
- Fix phpdoc generate for custom cast with parameter [\#986 / artelkr](https://github.com/barryvdh/laravel-ide-helper/pull/986)
+11 -11
View File
@@ -20,25 +20,25 @@
}
],
"require": {
"php": ">=7.2",
"php": "^7.3 || ^8.0",
"ext-json": "*",
"barryvdh/reflection-docblock": "^2.0.6",
"composer/composer": "^1.6 || ^2",
"doctrine/dbal": "~2.3",
"illuminate/console": "^6 || ^7 || ^8",
"illuminate/filesystem": "^6 || ^7 || ^8",
"illuminate/support": "^6 || ^7 || ^8",
"doctrine/dbal": "^2.6 || ^3",
"illuminate/console": "^8",
"illuminate/filesystem": "^8",
"illuminate/support": "^8",
"phpdocumentor/type-resolver": "^1.1.0"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"friendsofphp/php-cs-fixer": "^2",
"illuminate/config": "^6 || ^7 || ^8",
"illuminate/view": "^6 || ^7 || ^8",
"mockery/mockery": "^1.3.3",
"orchestra/testbench": "^4 || ^5 || ^6",
"illuminate/config": "^8",
"illuminate/view": "^8",
"mockery/mockery": "^1.4",
"orchestra/testbench": "^6",
"phpunit/phpunit": "^8.5 || ^9",
"spatie/phpunit-snapshot-assertions": "^1.4 || ^2.2 || ^3 || ^4",
"spatie/phpunit-snapshot-assertions": "^3 || ^4",
"vimeo/psalm": "^3.12"
},
"config": {
@@ -46,7 +46,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
"dev-master": "2.9-dev"
},
"laravel": {
"providers": [
+3 -1
View File
@@ -17,6 +17,7 @@ use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
use Barryvdh\Reflection\DocBlock\Tag\MethodTag;
use Closure;
use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Facades\Facade;
use ReflectionClass;
@@ -368,8 +369,9 @@ class Alias
}
// Check if the class is macroable
// (Eloquent\Builder is also macroable but doesn't use Macroable trait)
$traits = collect($reflection->getTraitNames());
if ($traits->contains('Illuminate\Support\Traits\Macroable')) {
if ($traits->contains('Illuminate\Support\Traits\Macroable') || $class === EloquentBuilder::class) {
$properties = $reflection->getStaticProperties();
$macros = isset($properties['macros']) ? $properties['macros'] : [];
foreach ($macros as $macro_name => $macro_func) {
+19 -12
View File
@@ -4,6 +4,7 @@ namespace Barryvdh\LaravelIdeHelper;
use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Tag;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
class Macro extends Method
@@ -32,25 +33,31 @@ class Macro extends Method
*/
protected function initPhpDoc($method)
{
$this->phpdoc = new DocBlock('/** */');
$this->phpdoc = new DocBlock($method);
$this->addLocationToPhpDoc();
// Add macro parameters
foreach ($method->getParameters() as $parameter) {
$type = $parameter->hasType() ? $parameter->getType()->getName() : 'mixed';
$type .= $parameter->hasType() && $parameter->getType()->allowsNull() ? '|null' : '';
// Add macro parameters if they are missed in original docblock
if (!$this->phpdoc->hasTag('param')) {
foreach ($method->getParameters() as $parameter) {
$type = $parameter->hasType() ? $parameter->getType()->getName() : 'mixed';
$type .= $parameter->hasType() && $parameter->getType()->allowsNull() ? '|null' : '';
$name = $parameter->isVariadic() ? '...' : '';
$name .= '$' . $parameter->getName();
$name = $parameter->isVariadic() ? '...' : '';
$name .= '$' . $parameter->getName();
$this->phpdoc->appendTag(Tag::createInstance("@param {$type} {$name}"));
$this->phpdoc->appendTag(Tag::createInstance("@param {$type} {$name}"));
}
}
// Add macro return type
if ($method->hasReturnType()) {
$type = $method->getReturnType()->getName();
$type .= $method->getReturnType()->allowsNull() ? '|null' : '';
// Add macro return type if it missed in original docblock
if ($method->hasReturnType() && !$this->phpdoc->hasTag('return')) {
$builder = EloquentBuilder::class;
$return = $method->getReturnType();
$type = $return->getName();
$type .= $this->root === "\\{$builder}" && $return->getName() === $builder ? '|static' : '';
$type .= $return->allowsNull() ? '|null' : '';
$this->phpdoc->appendTag(Tag::createInstance("@return {$type}"));
}
+105
View File
@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests;
use Barryvdh\LaravelIdeHelper\Alias;
use Barryvdh\LaravelIdeHelper\Macro;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Arr;
/**
* @internal
* @coversDefaultClass \Barryvdh\LaravelIdeHelper\Alias
*/
class AliasTest extends TestCase
{
/**
* @covers ::detectMethods
*/
public function testDetectMethodsMacroableMacros(): void
{
// Mock
$macro = __FUNCTION__;
$alias = new AliasMock();
// Macros
Builder::macro(
$macro,
function () {
// empty
}
);
// Prepare
$alias->setClasses([Builder::class]);
$alias->detectMethods();
// Test
$this->assertNotNull($this->getAliasMacro($alias, Builder::class, $macro));
}
/**
* @covers ::detectMethods
*/
public function testDetectMethodsEloquentBuilderMacros(): void
{
// Mock
$macro = __FUNCTION__;
$alias = new AliasMock();
// Macros
EloquentBuilder::macro(
$macro,
function () {
// empty
}
);
// Prepare
$alias->setClasses([EloquentBuilder::class]);
$alias->detectMethods();
// Test
$this->assertNotNull($this->getAliasMacro($alias, EloquentBuilder::class, $macro));
}
protected function getAliasMacro(Alias $alias, string $class, string $method): ?Macro
{
return Arr::first(
$alias->getMethods(),
function ($macro) use ($class, $method) {
return $macro instanceof Macro
&& $macro->getDeclaringClass() === "\\{$class}"
&& $macro->getName() === $method;
}
);
}
}
/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
*/
class AliasMock extends Alias
{
public function __construct()
{
// no need to call parent
}
/**
* @param string[] $classes
*/
public function setClasses(array $classes)
{
$this->classes = $classes;
}
public function detectMethods()
{
parent::detectMethods();
}
}
@@ -6,19 +6,9 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCas
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
use Illuminate\Foundation\Application;
class Test extends AbstractModelsCommand
{
protected function setUp(): void
{
parent::setUp();
if (version_compare(Application::VERSION, '7.0', '<')) {
$this->markTestSkipped('This test requires Laravel 7.0 or higher');
}
}
public function test(): void
{
$command = $this->app->make(ModelsCommand::class);
+220
View File
@@ -0,0 +1,220 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests;
use Barryvdh\LaravelIdeHelper\Macro;
use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Tag;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use ReflectionClass;
use ReflectionFunction;
use ReflectionFunctionAbstract;
use function array_map;
use function implode;
use const PHP_EOL;
/**
* @internal
* @coversDefaultClass \Barryvdh\LaravelIdeHelper\Macro
*/
class MacroTest extends TestCase
{
/**
* @covers ::initPhpDoc
* @throws \ReflectionException
*/
public function testInitPhpDocEloquentBuilderHasStaticInReturnType(): void
{
$class = new ReflectionClass(EloquentBuilder::class);
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
function (): EloquentBuilder {
return $this;
}
),
$class
);
$this->assertNotNull($phpdoc);
$this->assertEquals(
'@return \Illuminate\Database\Eloquent\Builder|static',
$this->tagsToString($phpdoc, 'return')
);
}
/**
* @covers ::initPhpDoc
* @throws \ReflectionException
*/
public function testInitPhpDocClosureWithoutDocBlock(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
function (int $a = null): int {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertEmpty($phpdoc->getText());
$this->assertEquals('@param int|null $a', $this->tagsToString($phpdoc, 'param'));
$this->assertEquals('@return int', $this->tagsToString($phpdoc, 'return'));
$this->assertTrue($phpdoc->hasTag('see'));
}
/**
* @covers ::initPhpDoc
* @throws \ReflectionException
*/
public function testInitPhpDocClosureWithArgsAndReturnType(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
/**
* Test docblock.
*/
function (int $a = null): int {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
$this->assertEquals('@param int|null $a', $this->tagsToString($phpdoc, 'param'));
$this->assertEquals('@return int', $this->tagsToString($phpdoc, 'return'));
$this->assertTrue($phpdoc->hasTag('see'));
}
/**
* @covers ::initPhpDoc
* @throws \ReflectionException
*/
public function testInitPhpDocClosureWithArgs(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
/**
* Test docblock.
*/
function (int $a = null) {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
$this->assertEquals('@param int|null $a', $this->tagsToString($phpdoc, 'param'));
$this->assertFalse($phpdoc->hasTag('return'));
$this->assertTrue($phpdoc->hasTag('see'));
}
/**
* @covers ::initPhpDoc
* @throws \ReflectionException
*/
public function testInitPhpDocClosureWithReturnType(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
/**
* Test docblock.
*/
function (): int {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
$this->assertFalse($phpdoc->hasTag('param'));
$this->assertEquals('@return int', $this->tagsToString($phpdoc, 'return'));
$this->assertTrue($phpdoc->hasTag('see'));
}
/**
* @covers ::initPhpDoc
*/
public function testInitPhpDocParamsAddedOnlyNotPresent(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
/**
* Test docblock.
*
* @param \stdClass|null $a aaaaa
*/
function ($a = null): int {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
$this->assertEquals('@param \stdClass|null $a aaaaa', $this->tagsToString($phpdoc, 'param'));
$this->assertEquals('@return int', $this->tagsToString($phpdoc, 'return'));
}
/**
* @covers ::initPhpDoc
*/
public function testInitPhpDocReturnAddedOnlyNotPresent(): void
{
$phpdoc = (new MacroMock())->getPhpDoc(
new ReflectionFunction(
/**
* Test docblock.
*
* @return \stdClass|null rrrrrrr
*/
function ($a = null): int {
return 0;
}
)
);
$this->assertNotNull($phpdoc);
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
$this->assertEquals('@param mixed $a', $this->tagsToString($phpdoc, 'param'));
$this->assertEquals('@return \stdClass|null rrrrrrr', $this->tagsToString($phpdoc, 'return'));
}
protected function tagsToString(DocBlock $docBlock, string $name)
{
$tags = $docBlock->getTagsByName($name);
$tags = array_map(
function (Tag $tag) {
return trim((string)$tag);
},
$tags
);
$tags = implode(PHP_EOL, $tags);
return $tags;
}
}
/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
*/
class MacroMock extends Macro
{
public function __construct()
{
// no need to call parent
}
public function getPhpDoc(ReflectionFunctionAbstract $method, ReflectionClass $class = null): DocBlock
{
return (new Macro($method, '', $class ?? $method->getClosureScopeClass()))->phpdoc;
}
}
-5
View File
@@ -6,7 +6,6 @@ namespace Barryvdh\LaravelIdeHelper\Tests;
use Barryvdh\LaravelIdeHelper\Method;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Application;
use PHPUnit\Framework\TestCase;
class MethodTest extends TestCase
@@ -59,10 +58,6 @@ DOC;
*/
public function testEloquentBuilderOutput()
{
if ((int) Application::VERSION < 8) {
$this->markTestSkipped('This test requires Laravel 8.0 or higher');
}
$reflectionClass = new \ReflectionClass(Builder::class);
$reflectionMethod = $reflectionClass->getMethod('with');