Compare commits

...
12 Commits
Author SHA1 Message Date
Brent Roose 39c148ad42 Support for custom builder classes (#782) 2019-03-26 11:38:22 +01:00
Francis Lavoie 2b3c9a2449 Fix BC introduced in #765 (#778)
See my comment https://github.com/barryvdh/laravel-ide-helper/pull/765#issuecomment-471014271:

The change in #765 made anonymous functions get reflected with `ReflectionMethod` instead of `ReflectionFunction`, which makes it lose the doc comment. This means that the generated helpers are missing their return types. This is because Closure is also an object and callable.

To fix it, Closure should be excluded from that new condition.
2019-03-12 11:38:49 +01:00
Matthew Brown 725711022b Make autoload exception more specific (#777)
This is a nice-to-have ([as I'm currently overriding it](https://github.com/psalm/laravel-psalm-plugin/commit/a700c89061d151d1c08851abd93d834f9183534d)), but might help other packages.
2019-03-05 10:24:51 +01:00
neoteknic 881f77156c Fix php 7.3 bug (#772) 2019-03-02 15:15:16 +01:00
neoteknic 0fad511954 Fix Bug PHP 7.3 & L5.8 (#774)
add cast (string) to disable bug ($type can be null)
2019-03-02 15:14:46 +01:00
Stan Daniëls 754bb4d075 Add support for invokable classes as macro function (#765)
Macros can be used with invokable classes, like so.

```
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Response;

class ResponseMacroServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Response::macro('foo', new Foo());
    }
}

class Foo
{
    public function __invoke()
    {
        return 'foobar';
    }
}
```

When running `ide-helper:generate` the following fatal error was thrown.

```  Symfony\Component\Debug\Exception\FatalThrowableError  : ReflectionFunction::__construct() expects parameter 1 to be string, object given```

This commit fixes this error.
2019-02-18 20:54:27 +01:00
edcoreweb bcb881b20d Nested relations detection. (#763) 2019-02-03 16:59:09 +01:00
Tim Philips d00600d769 Include DocBloc’s from classes to allow deeper code inspection (#745)
* Add support to include DocBloc’s from classes to allow further code inspection

* Adjust for PSR2

* Additional fix for PSR2
2019-01-28 21:38:57 +01:00
Ahmed Fathy 858dd40844 Install doctrine/dbal on development (#753) 2019-01-28 21:25:55 +01:00
Kyle 4cd11a4d33 Allow Laravel 5.8 (#754) 2019-01-28 21:24:50 +01:00
Barry vd. Heuvel 5439781e7c Update composer.json 2018-12-19 13:13:32 +01:00
+pikari 190bf07c05 fix: warning when call the instance method (#735) 2018-12-19 13:12:44 +01:00
9 changed files with 106 additions and 37 deletions
+6 -6
View File
@@ -11,15 +11,15 @@
], ],
"require": { "require": {
"php": ">=7", "php": ">=7",
"illuminate/support": "^5.5,<5.8", "illuminate/support": "^5.5,<5.9",
"illuminate/console": "^5.5,<5.8", "illuminate/console": "^5.5,<5.9",
"illuminate/filesystem": "^5.5,<5.8", "illuminate/filesystem": "^5.5,<5.9",
"barryvdh/reflection-docblock": "^2.0.6", "barryvdh/reflection-docblock": "^2.0.6",
"composer/composer": "^1.6" "composer/composer": "^1.6"
}, },
"require-dev": { "require-dev": {
"illuminate/config": "^5.1,<5.8", "illuminate/config": "^5.1,<5.9",
"illuminate/view": "^5.1,<5.8", "illuminate/view": "^5.1,<5.9",
"phpro/grumphp": "^0.14", "phpro/grumphp": "^0.14",
"phpunit/phpunit" : "4.*", "phpunit/phpunit" : "4.*",
"scrutinizer/ocular": "~1.1", "scrutinizer/ocular": "~1.1",
@@ -46,7 +46,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.5-dev" "dev-master": "2.6-dev"
}, },
"laravel": { "laravel": {
"providers": [ "providers": [
+12
View File
@@ -193,4 +193,16 @@ return array(
'integer' => 'int', 'integer' => 'int',
'boolean' => 'bool', 'boolean' => 'bool',
), ),
/*
|--------------------------------------------------------------------------
| Include DocBlocks from classes
|--------------------------------------------------------------------------
|
| Include DocBlocks from classes to allow additional code inspection for
| magic methods and properties.
|
*/
'include_class_docblocks' => false,
); );
+2 -2
View File
@@ -97,11 +97,11 @@ The `Illuminate/Support/helpers.php` is already set up, but you can add/remove y
### Automatic phpDocs for models ### Automatic phpDocs for models
> You need to require `doctrine/dbal: ~2.3` in your own composer.json to get database columns. > You need to add `doctrine/dbal: ~2.3` to require-dev in your own composer.json to get database columns.
```bash ```bash
composer require doctrine/dbal composer require --dev doctrine/dbal
``` ```
If you don't want to write your properties yourself, you can use the command `php artisan ide-helper:models` to generate If you don't want to write your properties yourself, you can use the command `php artisan ide-helper:models` to generate
+8 -2
View File
@@ -36,7 +36,10 @@ namespace <?= $namespace == '__root' ? '' : trim($namespace, '\\') ?> {
//Method inherited from <?= $method->getDeclaringClass() ?> //Method inherited from <?= $method->getDeclaringClass() ?>
<?php endif; ?> <?php endif; ?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getRealName() ?>(<?= $method->getParams() ?>); <?php if($method->isInstanceCall()):?>
/** @var <?=$method->getRoot()?> $instance */
<?php endif?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRootMethodCall() ?>;
} }
<?php endforeach; ?> <?php endforeach; ?>
} }
@@ -58,7 +61,10 @@ namespace <?= $namespace == '__root' ? '' : trim($namespace, '\\') ?> {
//Method inherited from <?= $method->getDeclaringClass() ?> //Method inherited from <?= $method->getDeclaringClass() ?>
<?php endif; ?> <?php endif; ?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getRealName() ?>(<?= $method->getParams() ?>); <?php if($method->isInstanceCall()):?>
/** @var <?=$method->getRoot()?> $instance */
<?php endif?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRootMethodCall() ?>;
} }
<?php endforeach; ?> <?php endforeach; ?>
<?php endif; ?>} <?php endif; ?>}
+24 -3
View File
@@ -10,11 +10,13 @@
namespace Barryvdh\LaravelIdeHelper; namespace Barryvdh\LaravelIdeHelper;
use Closure;
use ReflectionClass;
use Barryvdh\Reflection\DocBlock; use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Context; use Barryvdh\Reflection\DocBlock\Context;
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
use Barryvdh\Reflection\DocBlock\Tag\MethodTag; use Barryvdh\Reflection\DocBlock\Tag\MethodTag;
use ReflectionClass; use Illuminate\Config\Repository as ConfigRepository;
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
class Alias class Alias
{ {
@@ -35,17 +37,22 @@ class Alias
protected $interfaces = array(); protected $interfaces = array();
protected $phpdoc = null; protected $phpdoc = null;
/** @var ConfigRepository */
protected $config;
/** /**
* @param ConfigRepository $config
* @param string $alias * @param string $alias
* @param string $facade * @param string $facade
* @param array $magicMethods * @param array $magicMethods
* @param array $interfaces * @param array $interfaces
*/ */
public function __construct($alias, $facade, $magicMethods = array(), $interfaces = array()) public function __construct($config, $alias, $facade, $magicMethods = array(), $interfaces = array())
{ {
$this->alias = $alias; $this->alias = $alias;
$this->magicMethods = $magicMethods; $this->magicMethods = $magicMethods;
$this->interfaces = $interfaces; $this->interfaces = $interfaces;
$this->config = $config;
// Make the class absolute // Make the class absolute
$facade = '\\' . ltrim($facade, '\\'); $facade = '\\' . ltrim($facade, '\\');
@@ -389,6 +396,10 @@ class Alias
return new \ReflectionMethod($macro_func[0], $macro_func[1]); return new \ReflectionMethod($macro_func[0], $macro_func[1]);
} }
if (is_object($macro_func) && is_callable($macro_func) && !$macro_func instanceof Closure) {
return new \ReflectionMethod($macro_func, '__invoke');
}
return new \ReflectionFunction($macro_func); return new \ReflectionFunction($macro_func);
} }
@@ -403,6 +414,16 @@ class Alias
$serializer = new DocBlockSerializer(1, $prefix); $serializer = new DocBlockSerializer(1, $prefix);
if ($this->phpdoc) { if ($this->phpdoc) {
if ($this->config->get('ide-helper.include_class_docblocks')) {
// if a class doesn't expose any DocBlock tags
// we can perform reflection on the class and
// add in the original class DocBlock
if (count($this->phpdoc->getTags()) === 0) {
$class = new ReflectionClass($this->root);
$this->phpdoc = new DocBlock($class->getDocComment());
}
}
$this->removeDuplicateMethodsFromPhpDoc(); $this->removeDuplicateMethodsFromPhpDoc();
return $serializer->getDocComment($this->phpdoc); return $serializer->getDocComment($this->phpdoc);
} }
+1 -1
View File
@@ -135,7 +135,7 @@ class MetaCommand extends Command
protected function registerClassAutoloadExceptions() protected function registerClassAutoloadExceptions()
{ {
spl_autoload_register(function ($class) { spl_autoload_register(function ($class) {
throw new \Exception("Class '$class' not found."); throw new \ReflectionException("Class '$class' not found.");
}); });
} }
+18 -13
View File
@@ -446,12 +446,17 @@ class ModelsCommand extends Command
} }
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) { } elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) {
$reflection = new \ReflectionClass($model); $reflection = new \ReflectionClass($model);
$this->setMethod($method, '\Illuminate\Database\Eloquent\Builder|\\' . $reflection->getName());
$builder = get_class($model->newModelQuery());
$this->setMethod($method, "\\{$builder}|\\" . $reflection->getName());
} elseif (!method_exists('Illuminate\Database\Eloquent\Model', $method) } elseif (!method_exists('Illuminate\Database\Eloquent\Model', $method)
&& !Str::startsWith($method, 'get') && !Str::startsWith($method, 'get')
) { ) {
//Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
$reflection = new \ReflectionMethod($model, $method); $reflection = new \ReflectionMethod($model, $method);
// php 7.x type or fallback to docblock
$type = (string) $reflection->getReturnType() ?: (string)$this->getReturnTypeFromDocBlock($reflection);
$file = new \SplFileObject($reflection->getFileName()); $file = new \SplFileObject($reflection->getFileName());
$file->seek($reflection->getStartLine() - 1); $file->seek($reflection->getStartLine() - 1);
@@ -466,19 +471,19 @@ class ModelsCommand extends Command
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1); $code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
foreach (array( foreach (array(
'hasMany', 'hasMany' => '\Illuminate\Database\Eloquent\Relations\HasMany',
'hasManyThrough', 'hasManyThrough' => '\Illuminate\Database\Eloquent\Relations\HasManyThrough',
'belongsToMany', 'belongsToMany' => '\Illuminate\Database\Eloquent\Relations\BelongsToMany',
'hasOne', 'hasOne' => '\Illuminate\Database\Eloquent\Relations\HasOne',
'belongsTo', 'belongsTo' => '\Illuminate\Database\Eloquent\Relations\BelongsTo',
'morphOne', 'morphOne' => '\Illuminate\Database\Eloquent\Relations\MorphOne',
'morphTo', 'morphTo' => '\Illuminate\Database\Eloquent\Relations\MorphTo',
'morphMany', 'morphMany' => '\Illuminate\Database\Eloquent\Relations\MorphMany',
'morphToMany', 'morphToMany' => '\Illuminate\Database\Eloquent\Relations\MorphToMany',
'morphedByMany' 'morphedByMany' => '\Illuminate\Database\Eloquent\Relations\MorphToMany'
) as $relation) { ) as $relation => $impl) {
$search = '$this->' . $relation . '('; $search = '$this->' . $relation . '(';
if ($pos = stripos($code, $search)) { if (stripos($code, $search) || stripos($impl, (string)$type) !== false) {
//Resolve the relation's model to a Relation object. //Resolve the relation's model to a Relation object.
$methodReflection = new \ReflectionMethod($model, $method); $methodReflection = new \ReflectionMethod($model, $method);
if ($methodReflection->getNumberOfParameters()) { if ($methodReflection->getNumberOfParameters()) {
+1 -1
View File
@@ -203,7 +203,7 @@ class Generator
} }
$magicMethods = array_key_exists($name, $this->magic) ? $this->magic[$name] : array(); $magicMethods = array_key_exists($name, $this->magic) ? $this->magic[$name] : array();
$alias = new Alias($name, $facade, $magicMethods, $this->interfaces); $alias = new Alias($this->config, $name, $facade, $magicMethods, $this->interfaces);
if ($alias->isValid()) { if ($alias->isValid()) {
//Add extra methods, from other classes (magic static calls) //Add extra methods, from other classes (magic static calls)
if (array_key_exists($name, $this->extra)) { if (array_key_exists($name, $this->extra)) {
+28 -3
View File
@@ -34,6 +34,7 @@ class Method
protected $interfaces = array(); protected $interfaces = array();
protected $real_name; protected $real_name;
protected $return = null; protected $return = null;
protected $root;
/** /**
* @param \ReflectionMethod|\ReflectionFunctionAbstract $method * @param \ReflectionMethod|\ReflectionFunctionAbstract $method
@@ -50,6 +51,9 @@ class Method
$this->real_name = $method->isClosure() ? $this->name : $method->name; $this->real_name = $method->isClosure() ? $this->name : $method->name;
$this->initClassDefinedProperties($method, $class); $this->initClassDefinedProperties($method, $class);
//Reference the 'real' function in the declaring class
$this->root = '\\' . ltrim($class->getName(), '\\');
//Create a DocBlock and serializer instance //Create a DocBlock and serializer instance
$this->initPhpDoc($method); $this->initPhpDoc($method);
@@ -66,9 +70,6 @@ class Method
//Make the method static //Make the method static
$this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc)); $this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc));
//Reference the 'real' function in the declaring class
$this->root = '\\' . ltrim($class->getName(), '\\');
} }
/** /**
@@ -110,6 +111,26 @@ class Method
return $this->root; return $this->root;
} }
/**
* @return bool
*/
public function isInstanceCall()
{
return ! ($this->method->isClosure() || $this->method->isStatic());
}
/**
* @return string
*/
public function getRootMethodCall()
{
if ($this->isInstanceCall()) {
return "\$instance->{$this->getRealName()}({$this->getParams()})";
} else {
return "{$this->getRoot()}::{$this->getRealName()}({$this->getParams()})";
}
}
/** /**
* Get the docblock for this method * Get the docblock for this method
* *
@@ -243,6 +264,10 @@ class Method
// Set the changed content // Set the changed content
$tag->setContent($returnValue . ' ' . $tag->getDescription()); $tag->setContent($returnValue . ' ' . $tag->getDescription());
$this->return = $returnValue; $this->return = $returnValue;
if ($tag->getType() === '$this') {
$tag->setType($this->root);
}
} else { } else {
$this->return = null; $this->return = null;
} }