mirror of
https://github.com/barryvdh/laravel-ide-helper.git
synced 2026-08-18 01:57:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b91b959364 | ||
|
|
9b0fbb4467 | ||
|
|
6c8e847430 | ||
|
|
25b61c56fe | ||
|
|
428d32cebd | ||
|
|
51a72d7766 | ||
|
|
d200f2284b | ||
|
|
8faae38655 | ||
|
|
8740a9a158 | ||
|
|
d344cdc842 | ||
|
|
5e411ef104 | ||
|
|
499a2113b3 | ||
|
|
f8a8cb18e0 | ||
|
|
16eb4f65ee | ||
|
|
0edf8f750e | ||
|
|
1b15d2930b | ||
|
|
3668e3821a | ||
|
|
7b4cef1ea4 | ||
|
|
cd2a71d43c | ||
|
|
c9132b28a6 | ||
|
|
8ab6e0536b | ||
|
|
87ebe458e9 | ||
|
|
9ef14f83be | ||
|
|
39c148ad42 | ||
|
|
2b3c9a2449 | ||
|
|
725711022b | ||
|
|
881f77156c | ||
|
|
0fad511954 | ||
|
|
754bb4d075 | ||
|
|
bcb881b20d | ||
|
|
d00600d769 | ||
|
|
858dd40844 | ||
|
|
4cd11a4d33 | ||
|
|
5439781e7c | ||
|
|
190bf07c05 | ||
|
|
3d7f124089 | ||
|
|
32df0a3bc6 | ||
|
|
2f8283a746 | ||
|
|
2a63b31475 | ||
|
|
494d1593c8 | ||
|
|
e513fb34dc | ||
|
|
5db82752ef | ||
|
|
1f555bc194 | ||
|
|
b0ce5325de | ||
|
|
aeae59d0af | ||
|
|
001719245c | ||
|
|
99226c92b7 | ||
|
|
dda63bf8df | ||
|
|
3d7f45479e | ||
|
|
7905dd3926 | ||
|
|
8d135a1dea | ||
|
|
858e730c00 | ||
|
|
2ab961e734 | ||
|
|
981ff45b43 | ||
|
|
8174730714 | ||
|
|
ae5b623cf2 | ||
|
|
eff51d41b3 | ||
|
|
b14d983f74 | ||
|
|
1fdc866fb0 | ||
|
|
d7359b86d4 | ||
|
|
5d8d93273f | ||
|
|
30e5300e49 | ||
|
|
593e0d4aa7 | ||
|
|
e7d4cb322f | ||
|
|
5318f485e2 | ||
|
|
7db1843473 | ||
|
|
1989d0e794 |
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: barryvdh
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
+2
-3
@@ -1,7 +1,6 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
@@ -17,11 +16,11 @@ cache:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.6
|
||||
- php: 7.0
|
||||
env: 'COMPOSER_FLAGS="--prefer-stable --prefer-lowest"'
|
||||
|
||||
before_script:
|
||||
- travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist
|
||||
- travis_wait 20 travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist
|
||||
|
||||
script:
|
||||
- vendor/bin/phpcs --standard=psr2 src/
|
||||
|
||||
+10
-13
@@ -11,23 +11,20 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7",
|
||||
"illuminate/support": "^5.5,<5.8",
|
||||
"illuminate/console": "^5.5,<5.8",
|
||||
"illuminate/filesystem": "^5.5,<5.8",
|
||||
"barryvdh/reflection-docblock": "^2.0.4",
|
||||
"composer/composer": "^1.6"
|
||||
"illuminate/support": "^5.5|^6",
|
||||
"illuminate/console": "^5.5|^6",
|
||||
"illuminate/filesystem": "^5.5|^6",
|
||||
"barryvdh/reflection-docblock": "^2.0.6",
|
||||
"composer/composer": "^1.6",
|
||||
"doctrine/dbal": "~2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/config": "^5.1,<5.8",
|
||||
"illuminate/view": "^5.1,<5.8",
|
||||
"illuminate/config": "^5.5|^6",
|
||||
"illuminate/view": "^5.5|^6",
|
||||
"phpro/grumphp": "^0.14",
|
||||
"phpunit/phpunit" : "4.*",
|
||||
"scrutinizer/ocular": "~1.1",
|
||||
"squizlabs/php_codesniffer": "^3",
|
||||
"doctrine/dbal": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)"
|
||||
"squizlabs/php_codesniffer": "^3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -46,7 +43,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.5-dev"
|
||||
"dev-master": "2.6-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
|
||||
+42
-14
@@ -27,6 +27,18 @@ return array(
|
||||
|
||||
'include_fluent' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Factory Builders
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set to true to generate factory generators for better factory()
|
||||
| method auto-completion.
|
||||
|
|
||||
*/
|
||||
|
||||
'include_factory_builders' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Write Model Magic methods
|
||||
@@ -38,6 +50,21 @@ return array(
|
||||
|
||||
'write_model_magic_where' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Write Eloquent Model Mixins
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This will add the necessary DocBlock mixins to the model class
|
||||
| contained in the Laravel Framework. This helps the IDE with
|
||||
| auto-completion.
|
||||
|
|
||||
| Please be aware that this setting changes a file within the /vendor directory.
|
||||
|
|
||||
*/
|
||||
|
||||
'write_eloquent_model_mixins' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Helper files to include
|
||||
@@ -83,18 +110,7 @@ return array(
|
||||
'Session' => array('Illuminate\Session\Store'),
|
||||
),
|
||||
|
||||
'magic' => array(
|
||||
'Log' => array(
|
||||
'debug' => 'Monolog\Logger::addDebug',
|
||||
'info' => 'Monolog\Logger::addInfo',
|
||||
'notice' => 'Monolog\Logger::addNotice',
|
||||
'warning' => 'Monolog\Logger::addWarning',
|
||||
'error' => 'Monolog\Logger::addError',
|
||||
'critical' => 'Monolog\Logger::addCritical',
|
||||
'alert' => 'Monolog\Logger::addAlert',
|
||||
'emergency' => 'Monolog\Logger::addEmergency',
|
||||
)
|
||||
),
|
||||
'magic' => array(),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -174,8 +190,20 @@ return array(
|
||||
| Cast the given "real type" to the given "type".
|
||||
|
|
||||
*/
|
||||
'type_overrides' => array(
|
||||
'type_overrides' => array(
|
||||
'integer' => 'int',
|
||||
'boolean' => 'bool',
|
||||
),
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Include DocBlocks from classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Include DocBlocks from classes to allow additional code inspection for
|
||||
| magic methods and properties.
|
||||
|
|
||||
*/
|
||||
'include_class_docblocks' => false,
|
||||
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Laravel 5 IDE Helper Generator
|
||||
## Laravel IDE Helper Generator
|
||||
|
||||
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||
[![Software License][ico-license]](LICENSE.md)
|
||||
@@ -7,6 +7,19 @@
|
||||
|
||||
__For Laravel 4.x, check [version 1.11](https://github.com/barryvdh/laravel-ide-helper/tree/1.11)__
|
||||
|
||||
* [Complete phpDocs, directly from the source](#complete-phpdocs--directly-from-the-source)
|
||||
* [Install](#install)
|
||||
* [Automatic phpDoc generation for Laravel Facades](#automatic-phpdoc-generation-for-laravel-facades)
|
||||
* [Automatic phpDocs for models](#automatic-phpdocs-for-models)
|
||||
* [Automatic phpDocs generation for Laravel Fluent methods](#automatic-phpdocs-generation-for-laravel-fluent-methods)
|
||||
* [Auto-completion for factory builders](#auto-completion-for-factory-builders)
|
||||
- [PhpStorm Meta for Container instances](#phpstorm-meta-for-container-instances)
|
||||
- [Lumen Install](#lumen-install)
|
||||
+ [Enabling Facades](#enabling-facades)
|
||||
+ [Adding the Service Provider](#adding-the-service-provider)
|
||||
+ [Adding Additional Facades](#adding-additional-facades)
|
||||
* [License](#license)
|
||||
|
||||
### Complete phpDocs, directly from the source
|
||||
|
||||
_Check out [this Laracasts video](https://laracasts.com/series/how-to-be-awesome-in-phpstorm/episodes/15) for a quick introduction/explanation!_
|
||||
@@ -29,7 +42,7 @@ Note: You do need CodeComplice for Sublime Text: https://github.com/spectacles/C
|
||||
Require this package with composer using the following command:
|
||||
|
||||
```bash
|
||||
composer require barryvdh/laravel-ide-helper
|
||||
composer require --dev barryvdh/laravel-ide-helper
|
||||
```
|
||||
|
||||
After updating composer, add the service provider to the `providers` array in `config/app.php`
|
||||
@@ -39,12 +52,6 @@ Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
|
||||
```
|
||||
**Laravel 5.5** uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider.
|
||||
|
||||
To install this package on only development systems, add the `--dev` flag to your composer command:
|
||||
|
||||
```bash
|
||||
composer require --dev barryvdh/laravel-ide-helper
|
||||
```
|
||||
|
||||
In Laravel, instead of adding the service provider in the `config/app.php` file, you can add the following code to your `app/Providers/AppServiceProvider.php` file, within the `register()` method:
|
||||
|
||||
```php
|
||||
@@ -75,8 +82,8 @@ You can configure your composer.json to do this after each commit:
|
||||
"scripts":{
|
||||
"post-update-cmd": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
|
||||
"php artisan ide-helper:generate",
|
||||
"php artisan ide-helper:meta"
|
||||
"@php artisan ide-helper:generate",
|
||||
"@php artisan ide-helper:meta"
|
||||
]
|
||||
},
|
||||
```
|
||||
@@ -97,13 +104,6 @@ The `Illuminate/Support/helpers.php` is already set up, but you can add/remove y
|
||||
|
||||
### Automatic phpDocs for models
|
||||
|
||||
> You need to require `doctrine/dbal: ~2.3` in your own composer.json to get database columns.
|
||||
|
||||
|
||||
```bash
|
||||
composer require doctrine/dbal
|
||||
```
|
||||
|
||||
If you don't want to write your properties yourself, you can use the command `php artisan ide-helper:models` to generate
|
||||
phpDocs, based on table columns, relations and getters/setters. You can write the comments directly to your Model file, using the `--write (-W)` option. By default, you are asked to overwrite or write to a separate file (`_ide_helper_models.php`). You can force No with `--nowrite (-N)`.
|
||||
Please make sure to backup your models, before writing the info.
|
||||
@@ -169,6 +169,18 @@ After publishing vendor, simply change the `include_fluent` line your `config/id
|
||||
And then run `php artisan ide-helper:generate` , you will now see all of the Fluent methods are recognized by your IDE.
|
||||
|
||||
|
||||
### Auto-completion for factory builders
|
||||
|
||||
If you would like the `factory()->create()` and `factory()->make()` methods to return the correct model class,
|
||||
you can enable custom factory builders with the `include_factory_builders` line your `config/ide-helper.php` file.
|
||||
|
||||
```php
|
||||
'include_factory_builders' => true,
|
||||
```
|
||||
|
||||
For this to work, you must also publish the PhpStorm Meta file (see below).
|
||||
|
||||
|
||||
## PhpStorm Meta for Container instances
|
||||
|
||||
It's possible to generate a PhpStorm meta file to [add support for factory design pattern](https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata). For Laravel, this means we can make PhpStorm understand what kind of object we are resolving from the IoC Container. For example, `events` will return an `Illuminate\Events\Dispatcher` object, so with the meta file you can call `app('events')` and it will autocomplete the Dispatcher methods.
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?= '<?php' ?>
|
||||
<?php
|
||||
/**
|
||||
* @var \Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_alias_ns
|
||||
* @var \Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_extends_ns
|
||||
* @var bool $include_fluent
|
||||
* @var string $helpers
|
||||
*/
|
||||
?>
|
||||
|
||||
// @formatter:off
|
||||
|
||||
@@ -28,7 +36,10 @@ namespace <?= $namespace == '__root' ? '' : trim($namespace, '\\') ?> {
|
||||
//Method inherited from <?= $method->getDeclaringClass() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getName() ?>(<?= $method->getParams() ?>);
|
||||
<?php if($method->isInstanceCall()):?>
|
||||
/** @var <?=$method->getRoot()?> $instance */
|
||||
<?php endif?>
|
||||
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRootMethodCall() ?>;
|
||||
}
|
||||
<?php endforeach; ?>
|
||||
}
|
||||
@@ -49,8 +60,11 @@ namespace <?= $namespace == '__root' ? '' : trim($namespace, '\\') ?> {
|
||||
|
||||
//Method inherited from <?= $method->getDeclaringClass() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getName() ?>(<?= $method->getParams() ?>);
|
||||
|
||||
<?php if($method->isInstanceCall()):?>
|
||||
/** @var <?=$method->getRoot()?> $instance */
|
||||
<?php endif?>
|
||||
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRootMethodCall() ?>;
|
||||
}
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>}
|
||||
@@ -91,3 +105,13 @@ namespace Illuminate\Support {
|
||||
class Fluent {}
|
||||
}
|
||||
<?php endif ?>
|
||||
|
||||
<?php foreach ($factories as $factory): ?>
|
||||
namespace <?=$factory->getNamespaceName()?> {
|
||||
/**
|
||||
* @method \Illuminate\Database\Eloquent\Collection|<?=$factory->getShortName()?>[]|<?=$factory->getShortName()?> create($attributes = [])
|
||||
* @method \Illuminate\Database\Eloquent\Collection|<?=$factory->getShortName()?>[]|<?=$factory->getShortName()?> make($attributes = [])
|
||||
*/
|
||||
class <?=$factory->getShortName()?>FactoryBuilder extends \Illuminate\Database\Eloquent\FactoryBuilder {}
|
||||
}
|
||||
<?php endforeach; ?>
|
||||
|
||||
@@ -20,6 +20,15 @@ namespace PHPSTORM_META {
|
||||
]));
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if (count($factories)): ?>
|
||||
override(\factory(0), map([
|
||||
'' => '@FactoryBuilder',
|
||||
<?php foreach($factories as $factory): ?>
|
||||
'<?= $factory->getName() ?>' => \<?= $factory->getName() ?>FactoryBuilder::class,
|
||||
<?php endforeach; ?>
|
||||
]));
|
||||
<?php endif; ?>
|
||||
|
||||
override(\Illuminate\Support\Arr::add(0), type(0));
|
||||
override(\Illuminate\Support\Arr::except(0), type(0));
|
||||
override(\Illuminate\Support\Arr::first(0), elementType(0));
|
||||
|
||||
+67
-18
@@ -10,10 +10,13 @@
|
||||
|
||||
namespace Barryvdh\LaravelIdeHelper;
|
||||
|
||||
use Closure;
|
||||
use ReflectionClass;
|
||||
use Barryvdh\Reflection\DocBlock;
|
||||
use Barryvdh\Reflection\DocBlock\Context;
|
||||
use Barryvdh\Reflection\DocBlock\Tag\MethodTag;
|
||||
use Illuminate\Config\Repository as ConfigRepository;
|
||||
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
|
||||
use ReflectionClass;
|
||||
|
||||
class Alias
|
||||
{
|
||||
@@ -34,17 +37,22 @@ class Alias
|
||||
protected $interfaces = array();
|
||||
protected $phpdoc = null;
|
||||
|
||||
/** @var ConfigRepository */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param string $alias
|
||||
* @param string $facade
|
||||
* @param array $magicMethods
|
||||
* @param array $interfaces
|
||||
* @param ConfigRepository $config
|
||||
* @param string $alias
|
||||
* @param string $facade
|
||||
* @param array $magicMethods
|
||||
* @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->magicMethods = $magicMethods;
|
||||
$this->interfaces = $interfaces;
|
||||
$this->config = $config;
|
||||
|
||||
// Make the class absolute
|
||||
$facade = '\\' . ltrim($facade, '\\');
|
||||
@@ -171,10 +179,14 @@ class Alias
|
||||
/**
|
||||
* Get the methods found by this Alias
|
||||
*
|
||||
* @return array
|
||||
* @return array|Method[]
|
||||
*/
|
||||
public function getMethods()
|
||||
{
|
||||
if (count($this->methods) > 0) {
|
||||
return $this->methods;
|
||||
}
|
||||
|
||||
$this->addMagicMethods();
|
||||
$this->detectMethods();
|
||||
return $this->methods;
|
||||
@@ -304,13 +316,13 @@ class Alias
|
||||
{
|
||||
foreach ($this->magicMethods as $magic => $real) {
|
||||
list($className, $name) = explode('::', $real);
|
||||
if (!class_exists($className) && !interface_exists($className)) {
|
||||
if ((!class_exists($className) && !interface_exists($className)) || !method_exists($className, $name)) {
|
||||
continue;
|
||||
}
|
||||
$method = new \ReflectionMethod($className, $name);
|
||||
$class = new \ReflectionClass($className);
|
||||
|
||||
if (!in_array($method->name, $this->usedMethods)) {
|
||||
if (!in_array($magic, $this->usedMethods)) {
|
||||
if ($class !== $this->root) {
|
||||
$this->methods[] = new Method($method, $this->alias, $class, $magic, $this->interfaces);
|
||||
}
|
||||
@@ -356,14 +368,17 @@ class Alias
|
||||
$properties = $reflection->getStaticProperties();
|
||||
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
||||
foreach ($macros as $macro_name => $macro_func) {
|
||||
// Add macros
|
||||
$this->methods[] = new Macro(
|
||||
$this->getMacroFunction($macro_func),
|
||||
$this->alias,
|
||||
$reflection,
|
||||
$macro_name,
|
||||
$this->interfaces
|
||||
);
|
||||
if (!in_array($macro_name, $this->usedMethods)) {
|
||||
// Add macros
|
||||
$this->methods[] = new Macro(
|
||||
$this->getMacroFunction($macro_func),
|
||||
$this->alias,
|
||||
$reflection,
|
||||
$macro_name,
|
||||
$this->interfaces
|
||||
);
|
||||
$this->usedMethods[] = $macro_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,6 +396,10 @@ class Alias
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -395,12 +414,42 @@ class Alias
|
||||
$serializer = new DocBlockSerializer(1, $prefix);
|
||||
|
||||
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();
|
||||
return $serializer->getDocComment($this->phpdoc);
|
||||
}
|
||||
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes method tags from the doc comment that already appear as functions inside the class.
|
||||
* This prevents duplicate function errors in the IDE.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function removeDuplicateMethodsFromPhpDoc()
|
||||
{
|
||||
$methodNames = array_map(function (Method $method) {
|
||||
return $method->getName();
|
||||
}, $this->getMethods());
|
||||
|
||||
foreach ($this->phpdoc->getTags() as $tag) {
|
||||
if ($tag instanceof MethodTag && in_array($tag->getMethodName(), $methodNames)) {
|
||||
$this->phpdoc->deleteTag($tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an error.
|
||||
*
|
||||
|
||||
@@ -115,7 +115,10 @@ class GeneratorCommand extends Command
|
||||
|
||||
if ($written !== false) {
|
||||
$this->info("A new helper file was written to $filename");
|
||||
Eloquent::writeEloquentModelHelper($this, $this->files);
|
||||
|
||||
if ($this->option('write_mixins')) {
|
||||
Eloquent::writeEloquentModelHelper($this, $this->files);
|
||||
}
|
||||
} else {
|
||||
$this->error("The helper file could not be created at $filename");
|
||||
}
|
||||
@@ -159,9 +162,11 @@ class GeneratorCommand extends Command
|
||||
protected function getOptions()
|
||||
{
|
||||
$format = $this->config->get('ide-helper.format');
|
||||
$writeMixins = $this->config->get('ide-helper.write_eloquent_model_mixins');
|
||||
|
||||
return array(
|
||||
array('format', "F", InputOption::VALUE_OPTIONAL, 'The format for the IDE Helper', $format),
|
||||
array('write_mixins', "W", InputOption::VALUE_OPTIONAL, 'Write mixins to Laravel Model?', $writeMixins),
|
||||
array('helpers', "H", InputOption::VALUE_NONE, 'Include the helper files'),
|
||||
array('memory', "M", InputOption::VALUE_NONE, 'Use sqlite memory driver'),
|
||||
array('sublime', "S", InputOption::VALUE_NONE, 'DEPRECATED: Use different style for SublimeText CodeIntel'),
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
namespace Barryvdh\LaravelIdeHelper\Console;
|
||||
|
||||
use Barryvdh\LaravelIdeHelper\Factories;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -47,6 +48,7 @@ class MetaCommand extends Command
|
||||
|
||||
protected $methods = [
|
||||
'new \Illuminate\Contracts\Container\Container',
|
||||
'\Illuminate\Container\Container::makeWith(0)',
|
||||
'\Illuminate\Contracts\Container\Container::make(0)',
|
||||
'\Illuminate\Contracts\Container\Container::makeWith(0)',
|
||||
'\App::make(0)',
|
||||
@@ -76,6 +78,9 @@ class MetaCommand extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// Needs to run before exception handler is registered
|
||||
$factories = $this->config->get('ide-helper.include_factory_builders') ? Factories::all() : [];
|
||||
|
||||
$this->registerClassAutoloadExceptions();
|
||||
|
||||
$bindings = array();
|
||||
@@ -87,10 +92,11 @@ class MetaCommand extends Command
|
||||
|
||||
try {
|
||||
$concrete = $this->laravel->make($abstract);
|
||||
if (is_object($concrete)) {
|
||||
$reflectionClass = new \ReflectionClass($concrete);
|
||||
if (is_object($concrete) && !$reflectionClass->isAnonymous()) {
|
||||
$bindings[$abstract] = get_class($concrete);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
|
||||
$this->comment("Cannot make '$abstract': ".$e->getMessage());
|
||||
}
|
||||
@@ -100,6 +106,7 @@ class MetaCommand extends Command
|
||||
$content = $this->view->make('meta', [
|
||||
'bindings' => $bindings,
|
||||
'methods' => $this->methods,
|
||||
'factories' => $factories,
|
||||
])->render();
|
||||
|
||||
$filename = $this->option('filename');
|
||||
@@ -135,7 +142,7 @@ class MetaCommand extends Command
|
||||
protected function registerClassAutoloadExceptions()
|
||||
{
|
||||
spl_autoload_register(function ($class) {
|
||||
throw new \Exception("Class '$class' not found.");
|
||||
throw new \ReflectionException("Class '$class' not found.");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ class ModelsCommand extends Command
|
||||
//If filename is default and Write is not specified, ask what to do
|
||||
if (!$this->write && $filename === $this->filename && !$this->option('nowrite')) {
|
||||
if ($this->confirm(
|
||||
"Do you want to overwrite the existing model files? Choose no to write to $filename instead?"
|
||||
"Do you want to overwrite the existing model files? Choose no to write to $filename instead"
|
||||
)
|
||||
) {
|
||||
$this->write = true;
|
||||
@@ -217,7 +217,7 @@ class ModelsCommand extends Command
|
||||
$output .= $this->createPhpDocs($name);
|
||||
$ignore[] = $name;
|
||||
$this->nullableColumns = [];
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
$this->error("Exception: " . $e->getMessage() . "\nCould not analyze class $name.");
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ class ModelsCommand extends Command
|
||||
$realType = '\Illuminate\Support\Collection';
|
||||
break;
|
||||
default:
|
||||
$realType = 'mixed';
|
||||
$realType = class_exists($type) ? ('\\' . $type) : 'mixed';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -444,12 +444,27 @@ class ModelsCommand extends Command
|
||||
array_shift($args);
|
||||
$this->setMethod($name, '\Illuminate\Database\Eloquent\Builder|\\' . $reflection->class, $args);
|
||||
}
|
||||
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) {
|
||||
$reflection = new \ReflectionClass($model);
|
||||
|
||||
$builder = get_class($model->newModelQuery());
|
||||
|
||||
$this->setMethod($method, "\\{$builder}|\\" . $reflection->getName());
|
||||
} elseif (!method_exists('Illuminate\Database\Eloquent\Model', $method)
|
||||
&& !Str::startsWith($method, 'get')
|
||||
) {
|
||||
//Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
|
||||
$reflection = new \ReflectionMethod($model, $method);
|
||||
|
||||
if ($returnType = $reflection->getReturnType()) {
|
||||
$type = $returnType instanceof \ReflectionNamedType
|
||||
? $returnType->getName()
|
||||
: (string)$returnType;
|
||||
} else {
|
||||
// php 7.x type or fallback to docblock
|
||||
$type = (string)$this->getReturnTypeFromDocBlock($reflection);
|
||||
}
|
||||
|
||||
$file = new \SplFileObject($reflection->getFileName());
|
||||
$file->seek($reflection->getStartLine() - 1);
|
||||
|
||||
@@ -463,23 +478,24 @@ class ModelsCommand extends Command
|
||||
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
|
||||
|
||||
foreach (array(
|
||||
'hasMany',
|
||||
'hasManyThrough',
|
||||
'belongsToMany',
|
||||
'hasOne',
|
||||
'belongsTo',
|
||||
'morphOne',
|
||||
'morphTo',
|
||||
'morphMany',
|
||||
'morphToMany',
|
||||
'morphedByMany'
|
||||
) as $relation) {
|
||||
'hasMany' => '\Illuminate\Database\Eloquent\Relations\HasMany',
|
||||
'hasManyThrough' => '\Illuminate\Database\Eloquent\Relations\HasManyThrough',
|
||||
'hasOneThrough' => '\Illuminate\Database\Eloquent\Relations\HasOneThrough',
|
||||
'belongsToMany' => '\Illuminate\Database\Eloquent\Relations\BelongsToMany',
|
||||
'hasOne' => '\Illuminate\Database\Eloquent\Relations\HasOne',
|
||||
'belongsTo' => '\Illuminate\Database\Eloquent\Relations\BelongsTo',
|
||||
'morphOne' => '\Illuminate\Database\Eloquent\Relations\MorphOne',
|
||||
'morphTo' => '\Illuminate\Database\Eloquent\Relations\MorphTo',
|
||||
'morphMany' => '\Illuminate\Database\Eloquent\Relations\MorphMany',
|
||||
'morphToMany' => '\Illuminate\Database\Eloquent\Relations\MorphToMany',
|
||||
'morphedByMany' => '\Illuminate\Database\Eloquent\Relations\MorphToMany'
|
||||
) as $relation => $impl) {
|
||||
$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.
|
||||
$methodReflection = new \ReflectionMethod($model, $method);
|
||||
if ($methodReflection->getNumberOfParameters()) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
$relationObj = $model->$method();
|
||||
@@ -495,7 +511,7 @@ class ModelsCommand extends Command
|
||||
'morphToMany',
|
||||
'morphedByMany',
|
||||
];
|
||||
if (in_array($relation, $relations)) {
|
||||
if (strpos(get_class($relationObj), 'Many') !== false) {
|
||||
//Collection or array of models (because Collection is Arrayable)
|
||||
$this->setProperty(
|
||||
$method,
|
||||
@@ -503,6 +519,12 @@ class ModelsCommand extends Command
|
||||
true,
|
||||
null
|
||||
);
|
||||
$this->setProperty(
|
||||
Str::snake($method) . '_count',
|
||||
'int|null',
|
||||
true,
|
||||
false
|
||||
);
|
||||
} elseif ($relation === "morphTo") {
|
||||
// Model isn't specified because relation is polymorphic
|
||||
$this->setProperty(
|
||||
@@ -716,7 +738,7 @@ class ModelsCommand extends Command
|
||||
if (is_bool($default)) {
|
||||
$default = $default ? 'true' : 'false';
|
||||
} elseif (is_array($default)) {
|
||||
$default = 'array()';
|
||||
$default = '[]';
|
||||
} elseif (is_null($default)) {
|
||||
$default = 'null';
|
||||
} elseif (is_int($default)) {
|
||||
|
||||
+37
-7
@@ -32,27 +32,57 @@ class Eloquent
|
||||
$reflection = new \ReflectionClass($class);
|
||||
$namespace = $reflection->getNamespaceName();
|
||||
$originalDoc = $reflection->getDocComment();
|
||||
|
||||
if (!$originalDoc) {
|
||||
$command->info('Unexpected no document on ' . $class);
|
||||
}
|
||||
$phpdoc = new DocBlock($reflection, new Context($namespace));
|
||||
|
||||
$mixins = $phpdoc->getTagsByName('mixin');
|
||||
foreach ($mixins as $m) {
|
||||
if ($m->getContent() === '\Eloquent') {
|
||||
$command->info('Tag Exists: @mixin \Eloquent in ' . $class);
|
||||
$expectedMixins = [
|
||||
'\Eloquent' => false,
|
||||
'\Illuminate\Database\Eloquent\Builder' => false,
|
||||
'\Illuminate\Database\Query\Builder' => false,
|
||||
];
|
||||
|
||||
return;
|
||||
foreach ($mixins as $m) {
|
||||
$mixin = $m->getContent();
|
||||
|
||||
if (isset($expectedMixins[$mixin])) {
|
||||
$command->info('Tag Exists: @mixin ' . $mixin . ' in ' . $class);
|
||||
|
||||
$expectedMixins[$mixin] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// add the Eloquent mixin
|
||||
$phpdoc->appendTag(Tag::createInstance("@mixin \\Eloquent", $phpdoc));
|
||||
$changed = false;
|
||||
foreach ($expectedMixins as $expectedMixin => $present) {
|
||||
if ($present === false) {
|
||||
$phpdoc->appendTag(Tag::createInstance('@mixin ' . $expectedMixin, $phpdoc));
|
||||
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing's changed, stop here.
|
||||
if (!$changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
$serializer = new DocBlockSerializer();
|
||||
$serializer->getDocComment($phpdoc);
|
||||
$docComment = $serializer->getDocComment($phpdoc);
|
||||
|
||||
/*
|
||||
The new DocBlock is appended to the beginning of the class declaration.
|
||||
Since there is no DocBlock, the declaration is used as a guide.
|
||||
*/
|
||||
if (!$originalDoc) {
|
||||
$originalDoc = 'abstract class Model implements';
|
||||
|
||||
$docComment .= "\nabstract class Model implements";
|
||||
}
|
||||
|
||||
$filename = $reflection->getFileName();
|
||||
if ($filename) {
|
||||
$contents = $files->get($filename);
|
||||
@@ -61,7 +91,7 @@ class Eloquent
|
||||
$contents = str_replace($originalDoc, $docComment, $contents, $count);
|
||||
if ($count > 0) {
|
||||
if ($files->put($filename, $contents)) {
|
||||
$command->info('Wrote @mixin \Eloquent to ' . $filename);
|
||||
$command->info('Wrote expected docblock to ' . $filename);
|
||||
} else {
|
||||
$command->error('File write failed to ' . $filename);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Barryvdh\LaravelIdeHelper;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Factory;
|
||||
use ReflectionClass;
|
||||
|
||||
class Factories
|
||||
{
|
||||
|
||||
public static function all()
|
||||
{
|
||||
$factories = [];
|
||||
|
||||
$factory = app(Factory::class);
|
||||
|
||||
$definitions = (new ReflectionClass(Factory::class))->getProperty('definitions');
|
||||
$definitions->setAccessible(true);
|
||||
|
||||
foreach ($definitions->getValue($factory) as $factory_target => $config) {
|
||||
try {
|
||||
$factories[] = new ReflectionClass($factory_target);
|
||||
} catch (Exception $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
return $factories;
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -86,6 +86,7 @@ class Generator
|
||||
->with('helpers', $this->helpers)
|
||||
->with('version', $app->version())
|
||||
->with('include_fluent', $this->config->get('ide-helper.include_fluent', true))
|
||||
->with('factories', $this->config->get('ide-helper.include_factory_builders') ? Factories::all() : [])
|
||||
->render();
|
||||
}
|
||||
|
||||
@@ -198,12 +199,12 @@ class Generator
|
||||
// Get all aliases
|
||||
foreach ($this->getAliases() as $name => $facade) {
|
||||
// Skip the Redis facade, if not available (otherwise Fatal PHP Error)
|
||||
if ($facade == 'Illuminate\Support\Facades\Redis' && !class_exists('Predis\Client')) {
|
||||
if ($facade == 'Illuminate\Support\Facades\Redis' && $name == 'Redis' && !class_exists('Predis\Client')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$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()) {
|
||||
//Add extra methods, from other classes (magic static calls)
|
||||
if (array_key_exists($name, $this->extra)) {
|
||||
@@ -272,9 +273,13 @@ class Generator
|
||||
$facades = array_merge($facades, $this->config->get('app.aliases', []));
|
||||
|
||||
// Only return the ones that actually exist
|
||||
return array_filter($facades, function ($alias) {
|
||||
return class_exists($alias);
|
||||
});
|
||||
return array_filter(
|
||||
$facades,
|
||||
function ($alias) {
|
||||
return class_exists($alias);
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,8 +37,10 @@ class IdeHelperServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$viewPath = __DIR__.'/../resources/views';
|
||||
$this->loadViewsFrom($viewPath, 'ide-helper');
|
||||
if ($this->app->has('view')) {
|
||||
$viewPath = __DIR__ . '/../resources/views';
|
||||
$this->loadViewsFrom($viewPath, 'ide-helper');
|
||||
}
|
||||
|
||||
$configPath = __DIR__ . '/../config/ide-helper.php';
|
||||
if (function_exists('config_path')) {
|
||||
|
||||
+16
-22
@@ -17,36 +17,30 @@ class Macro extends Method
|
||||
* @param array $interfaces
|
||||
*/
|
||||
public function __construct(
|
||||
\ReflectionFunctionAbstract $method,
|
||||
$method,
|
||||
$alias,
|
||||
$class,
|
||||
$methodName = null,
|
||||
$interfaces = array()
|
||||
) {
|
||||
$this->method = $method;
|
||||
$this->interfaces = $interfaces;
|
||||
$this->name = $methodName ?: $method->name;
|
||||
$this->namespace = $class->getNamespaceName();
|
||||
parent::__construct($method, $alias, $class, $methodName, $interfaces);
|
||||
}
|
||||
|
||||
//Create a DocBlock and serializer instance
|
||||
/**
|
||||
* @param \ReflectionFunctionAbstract $method
|
||||
*/
|
||||
protected function initPhpDoc($method)
|
||||
{
|
||||
$this->phpdoc = new DocBlock($method);
|
||||
}
|
||||
|
||||
//Normalize the description and inherit the docs from parents/interfaces
|
||||
try {
|
||||
$this->normalizeParams($this->phpdoc);
|
||||
$this->normalizeReturn($this->phpdoc);
|
||||
$this->normalizeDescription($this->phpdoc);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
//Get the parameters, including formatted default values
|
||||
$this->getParameters($method);
|
||||
|
||||
//Make the method static
|
||||
$this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc));
|
||||
|
||||
//Reference the 'real' function in the declaringclass
|
||||
/**
|
||||
* @param \ReflectionFunctionAbstract $method
|
||||
* @param \ReflectionClass $class
|
||||
*/
|
||||
protected function initClassDefinedProperties($method, \ReflectionClass $class)
|
||||
{
|
||||
$this->namespace = $class->getNamespaceName();
|
||||
$this->declaringClassName = '\\' . ltrim($class->name, '\\');
|
||||
$this->root = '\\' . ltrim($class->getName(), '\\');
|
||||
}
|
||||
}
|
||||
|
||||
+62
-7
@@ -26,29 +26,36 @@ class Method
|
||||
protected $method;
|
||||
|
||||
protected $output = '';
|
||||
protected $declaringClassName;
|
||||
protected $name;
|
||||
protected $namespace;
|
||||
protected $params = array();
|
||||
protected $params_with_default = array();
|
||||
protected $interfaces = array();
|
||||
protected $real_name;
|
||||
protected $return = null;
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
* @param \ReflectionMethod|\ReflectionFunctionAbstract $method
|
||||
* @param string $alias
|
||||
* @param \ReflectionClass $class
|
||||
* @param string|null $methodName
|
||||
* @param array $interfaces
|
||||
*/
|
||||
public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array())
|
||||
public function __construct($method, $alias, $class, $methodName = null, $interfaces = array())
|
||||
{
|
||||
$this->method = $method;
|
||||
$this->interfaces = $interfaces;
|
||||
$this->name = $methodName ?: $method->name;
|
||||
$this->namespace = $method->getDeclaringClass()->getNamespaceName();
|
||||
$this->real_name = $method->isClosure() ? $this->name : $method->name;
|
||||
$this->initClassDefinedProperties($method, $class);
|
||||
|
||||
//Reference the 'real' function in the declaring class
|
||||
$this->root = '\\' . ltrim($class->getName(), '\\');
|
||||
|
||||
//Create a DocBlock and serializer instance
|
||||
$this->phpdoc = new DocBlock($method, new Context($this->namespace));
|
||||
$this->initPhpDoc($method);
|
||||
|
||||
//Normalize the description and inherit the docs from parents/interfaces
|
||||
try {
|
||||
@@ -63,11 +70,25 @@ class Method
|
||||
|
||||
//Make the method static
|
||||
$this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc));
|
||||
}
|
||||
|
||||
//Reference the 'real' function in the declaringclass
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
*/
|
||||
protected function initPhpDoc($method)
|
||||
{
|
||||
$this->phpdoc = new DocBlock($method, new Context($this->namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
* @param \ReflectionClass $class
|
||||
*/
|
||||
protected function initClassDefinedProperties($method, \ReflectionClass $class)
|
||||
{
|
||||
$declaringClass = $method->getDeclaringClass();
|
||||
$this->namespace = $declaringClass->getNamespaceName();
|
||||
$this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\');
|
||||
$this->root = '\\' . ltrim($class->getName(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +111,26 @@ class Method
|
||||
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
|
||||
*
|
||||
@@ -112,6 +153,16 @@ class Method
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real method name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRealName()
|
||||
{
|
||||
return $this->real_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameters for this method
|
||||
*
|
||||
@@ -213,6 +264,10 @@ class Method
|
||||
// Set the changed content
|
||||
$tag->setContent($returnValue . ' ' . $tag->getDescription());
|
||||
$this->return = $returnValue;
|
||||
|
||||
if ($tag->getType() === '$this') {
|
||||
$tag->setType($this->root);
|
||||
}
|
||||
} else {
|
||||
$this->return = null;
|
||||
}
|
||||
@@ -266,7 +321,7 @@ class Method
|
||||
if (is_bool($default)) {
|
||||
$default = $default ? 'true' : 'false';
|
||||
} elseif (is_array($default)) {
|
||||
$default = 'array()';
|
||||
$default = '[]';
|
||||
} elseif (is_null($default)) {
|
||||
$default = 'null';
|
||||
} elseif (is_int($default)) {
|
||||
|
||||
Reference in New Issue
Block a user