diff --git a/composer.json b/composer.json index 1af907b..cfaedee 100644 --- a/composer.json +++ b/composer.json @@ -11,15 +11,15 @@ ], "require": { "php": ">=5.4.0", - "illuminate/support": "^5.0,<5.6", - "illuminate/console": "^5.0,<5.6", - "illuminate/filesystem": "^5.0,<5.6", + "illuminate/support": "^5.0,<5.7", + "illuminate/console": "^5.0,<5.7", + "illuminate/filesystem": "^5.0,<5.7", "barryvdh/reflection-docblock": "^2.0.4", - "symfony/class-loader": "^2.3|^3.0" + "composer/composer": "^1.6", }, "require-dev": { - "illuminate/config": "^5.0,<5.6", - "illuminate/view": "^5.0,<5.6", + "illuminate/config": "^5.0,<5.7", + "illuminate/view": "^5.0,<5.7", "phpunit/phpunit" : "4.*", "scrutinizer/ocular": "~1.1", "squizlabs/php_codesniffer": "~2.3", diff --git a/config/ide-helper.php b/config/ide-helper.php index f481d4c..48a06db 100644 --- a/config/ide-helper.php +++ b/config/ide-helper.php @@ -13,6 +13,8 @@ return array( 'filename' => '_ide_helper', 'format' => 'php', + + 'meta_filename' => '.phpstorm.meta.php', /* |-------------------------------------------------------------------------- diff --git a/readme.md b/readme.md index 0ec60ae..fbdc6db 100644 --- a/readme.md +++ b/readme.md @@ -22,7 +22,7 @@ If you don't want to generate it, you can add a pre-generated file to the root f * Generated version for Lumen: https://gist.github.com/barryvdh/be17164b0ad51f832f20 * Generated Phpstorm Meta file: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67 -Note: You do need CodeIntel for Sublime Text: https://github.com/SublimeCodeIntel/SublimeCodeIntel +Note: You do need CodeComplice for Sublime Text: https://github.com/spectacles/CodeComplice ### Install @@ -66,7 +66,7 @@ You can now re-generate the docs yourself (for future updates) php artisan ide-helper:generate ``` -Note: `bootstrap/compiled.php` has to be cleared first, so run `php artisan clear-compiled` before generating (and `php artisan optimize` after). +Note: `bootstrap/compiled.php` has to be cleared first, so run `php artisan clear-compiled` before generating. You can configure your composer.json to do this after each commit: @@ -75,8 +75,7 @@ You can configure your composer.json to do this after each commit: "post-update-cmd": [ "Illuminate\\Foundation\\ComposerScripts::postUpdate", "php artisan ide-helper:generate", - "php artisan ide-helper:meta", - "php artisan optimize" + "php artisan ide-helper:meta" ] }, ``` @@ -151,9 +150,9 @@ php artisan ide-helper:models --ignore="Post,User" Note: With namespaces, wrap your model name in double-quotes (`"`): `php artisan ide-helper:models "API\User"`, or escape the slashes (`Api\\User`) -For properly recognition of `Model` methods (i.e. `paginate`, `findOrFail`) you should extend `\Eloquent` or add +For properly recognition of `Model` methods (i.e. `paginate`, `findOrFail`) you should extend `\Eloquent` or add ```php -/** @mixin \Eloquent */ +/** @mixin \Eloquent */ ``` for your model class. @@ -166,7 +165,7 @@ After publishing vendor, simply change the `include_fluent` line your `config/id ```php 'include_fluent' => true, ``` -And then run `php artisan ide-helper:generate` , you will now see all of the Fluent methods are recognized by your IDE now. +And then run `php artisan ide-helper:generate` , you will now see all of the Fluent methods are recognized by your IDE. ## PhpStorm Meta for Container instances diff --git a/resources/views/helper.php b/resources/views/helper.php index 89e69ad..e517a60 100644 --- a/resources/views/helper.php +++ b/resources/views/helper.php @@ -2,20 +2,20 @@ /** * A helper file for Laravel 5, to provide autocomplete information to your IDE - * Generated for Laravel on . + * Generated for Laravel on . + * + * This file should not be included in your code, only analyzed by your IDE! * * @author Barry vd. Heuvel * @see https://github.com/barryvdh/laravel-ide-helper */ -namespace { - exit("This file should not be included, only analyzed by your IDE"); -} $aliases): ?> namespace { + getDocComment(' ')) ?> getClassType() ?> getExtendsClass() ?> { getMethods() as $method): ?> @@ -72,7 +72,7 @@ namespace Illuminate\Support { * @method Fluent charset(string $charset) Add the character set modifier * @method Fluent collation(string $collation) Add the collation modifier * @method Fluent comment(string $comment) Add comment - * @method Fluent default(mixed $value) Add the default modifier + * @method Fluent default($value) Add the default modifier * @method Fluent first() Select first row * @method Fluent index(string $name = null) Add the in dex clause * @method Fluent on(string $table) `on` of a foreign key diff --git a/resources/views/meta.php b/resources/views/meta.php index f97a7ac..38ef3a6 100644 --- a/resources/views/meta.php +++ b/resources/views/meta.php @@ -4,7 +4,7 @@ namespace PHPSTORM_META { /** * PhpStorm Meta file, to provide autocomplete information for PhpStorm - * Generated on . + * Generated on . * * @author Barry vd. Heuvel * @see https://github.com/barryvdh/laravel-ide-helper @@ -46,5 +46,6 @@ namespace PHPSTORM_META { override(\head(0), elementType(0)); override(\last(0), elementType(0)); override(\with(0), type(0)); + override(\tap(0), type(0)); } diff --git a/src/Alias.php b/src/Alias.php index 171f373..52ab659 100644 --- a/src/Alias.php +++ b/src/Alias.php @@ -10,6 +10,11 @@ namespace Barryvdh\LaravelIdeHelper; +use Barryvdh\Reflection\DocBlock; +use Barryvdh\Reflection\DocBlock\Context; +use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; +use ReflectionClass; + class Alias { protected $alias; @@ -27,6 +32,7 @@ class Alias protected $valid = false; protected $magicMethods = array(); protected $interfaces = array(); + protected $phpdoc = null; /** * @param string $alias @@ -56,7 +62,13 @@ class Alias $this->detectNamespace(); $this->detectClassType(); $this->detectExtendsNamespace(); - + + if(!empty($this->namespace)) { + //Create a DocBlock and serializer instance + $this->phpdoc = new DocBlock(new ReflectionClass($alias), new Context($this->namespace)); + } + + if ($facade === '\Illuminate\Database\Eloquent\Model') { $this->usedMethods = array('decrement', 'increment'); } @@ -346,6 +358,17 @@ class Alias return new \ReflectionFunction($macro_func); } + + * Get the docblock for this alias + * + * @param string $prefix + * @return mixed + */ + public function getDocComment($prefix = "\t\t") + { + $serializer = new DocBlockSerializer(1, $prefix); + return ($this->phpdoc) ? $serializer->getDocComment($this->phpdoc) : ''; + } /** * Output an error. diff --git a/src/Console/EloquentCommand.php b/src/Console/EloquentCommand.php new file mode 100644 index 0000000..0dd8533 --- /dev/null +++ b/src/Console/EloquentCommand.php @@ -0,0 +1,61 @@ + + * @copyright 2017 Charles A. Peterson / Fruitcake Studio (http://www.fruitcakestudio.nl) + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link https://github.com/barryvdh/laravel-ide-helper + */ + +namespace Barryvdh\LaravelIdeHelper\Console; + +use Barryvdh\LaravelIdeHelper\Eloquent; +use Illuminate\Console\Command; +use Illuminate\Filesystem\Filesystem; + +/** + * A command to add \Eloquent mixin to Eloquent\Model + * + * @author Charles A. Peterson + */ +class EloquentCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'ide-helper:eloquent'; + + /** + * @var Filesystem $files + */ + protected $files; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Add \Eloquent helper to \Eloquent\Model'; + + /** + * @param Filesystem $files + */ + public function __construct(Filesystem $files) + { + parent::__construct(); + $this->files = $files; + } + + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + Eloquent::writeEloquentModelHelper($this, $this->files); + } +} diff --git a/src/Console/GeneratorCommand.php b/src/Console/GeneratorCommand.php index be753e0..02cce24 100644 --- a/src/Console/GeneratorCommand.php +++ b/src/Console/GeneratorCommand.php @@ -10,8 +10,8 @@ namespace Barryvdh\LaravelIdeHelper\Console; +use Barryvdh\LaravelIdeHelper\Eloquent; use Barryvdh\LaravelIdeHelper\Generator; -use Illuminate\Config\Repository as ConfigRepository; use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use Symfony\Component\Console\Input\InputOption; @@ -115,6 +115,7 @@ class GeneratorCommand extends Command if ($written !== false) { $this->info("A new helper file was written to $filename"); + Eloquent::writeEloquentModelHelper($this, $this->files); } else { $this->error("The helper file could not be created at $filename"); } diff --git a/src/Console/MetaCommand.php b/src/Console/MetaCommand.php index e2bd73f..13c9ed0 100644 --- a/src/Console/MetaCommand.php +++ b/src/Console/MetaCommand.php @@ -28,7 +28,6 @@ class MetaCommand extends Command * @var string */ protected $name = 'ide-helper:meta'; - protected $filename = '.phpstorm.meta.php'; /** * The console command description. @@ -43,6 +42,9 @@ class MetaCommand extends Command /** @var \Illuminate\Contracts\View\Factory */ protected $view; + /** @var \Illuminate\Contracts\Config */ + protected $config; + protected $methods = [ 'new \Illuminate\Contracts\Container\Container', '\Illuminate\Contracts\Container\Container::make(0)', @@ -57,11 +59,13 @@ class MetaCommand extends Command * * @param \Illuminate\Contracts\Filesystem\Filesystem $files * @param \Illuminate\Contracts\View\Factory $view + * @param \Illuminate\Contracts\Config $config */ - public function __construct($files, $view) + public function __construct($files, $view, $config) { $this->files = $files; $this->view = $view; + $this->config = $config; parent::__construct(); } @@ -138,8 +142,10 @@ class MetaCommand extends Command */ protected function getOptions() { + $filename = $this->config->get('ide-helper.meta_filename'); + return array( - array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the meta file', $this->filename), + array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the meta file', $filename), ); } } diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 7359a84..4c366a6 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -10,6 +10,7 @@ namespace Barryvdh\LaravelIdeHelper\Console; +use Composer\Autoload\ClassMapGenerator; use Illuminate\Console\Command; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Str; @@ -17,7 +18,6 @@ use Illuminate\Filesystem\Filesystem; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\ClassLoader\ClassMapGenerator; use Barryvdh\Reflection\DocBlock; use Barryvdh\Reflection\DocBlock\Context; use Barryvdh\Reflection\DocBlock\Tag; @@ -145,6 +145,7 @@ class ModelsCommand extends Command $output = "' . $relation . '('; if ($pos = stripos($code, $search)) { @@ -470,7 +472,14 @@ class ModelsCommand extends Command if ($relationObj instanceof Relation) { $relatedModel = '\\' . get_class($relationObj->getRelated()); - $relations = ['hasManyThrough', 'belongsToMany', 'hasMany', 'morphMany', 'morphToMany']; + $relations = [ + 'hasManyThrough', + 'belongsToMany', + 'hasMany', + 'morphMany', + 'morphToMany', + 'morphedByMany', + ]; if (in_array($relation, $relations)) { //Collection or array of models (because Collection is Arrayable) $this->setProperty( diff --git a/src/Eloquent.php b/src/Eloquent.php new file mode 100644 index 0000000..c27b1c1 --- /dev/null +++ b/src/Eloquent.php @@ -0,0 +1,78 @@ + + */ +namespace Barryvdh\LaravelIdeHelper; + +use Illuminate\Console\Command; +use Illuminate\Filesystem\Filesystem; +use Barryvdh\Reflection\DocBlock; +use Barryvdh\Reflection\DocBlock\Context; +use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; +use Barryvdh\Reflection\DocBlock\Tag; + +class Eloquent +{ + /** + * Write mixin helper to the Eloquent\Model + * This is needed since laravel/framework v5.4.29 + * + * @param Command $command + * @param Filesystem $files + * + * @return void + */ + public static function writeEloquentModelHelper(Command $command, Filesystem $files) + { + $class = 'Illuminate\Database\Eloquent\Model'; + + $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); + + return; + } + } + + // add the Eloquent mixin + $phpdoc->appendTag(Tag::createInstance("@mixin \\Eloquent", $phpdoc)); + + $serializer = new DocBlockSerializer(); + $serializer->getDocComment($phpdoc); + $docComment = $serializer->getDocComment($phpdoc); + + $filename = $reflection->getFileName(); + if ($filename) { + $contents = $files->get($filename); + if ($contents) { + $count = 0; + $contents = str_replace($originalDoc, $docComment, $contents, $count); + if ($count > 0) { + if ($files->put($filename, $contents)) { + $command->info('Wrote @mixin \Eloquent to ' . $filename); + } else { + $command->error('File write failed to ' . $filename); + } + } else { + $command->error('Content did not change ' . $contents); + } + } else { + $command->error('No file contents found ' . $filename); + } + } else { + $command->error('Filename not found ' . $class); + } + } +} diff --git a/src/IdeHelperServiceProvider.php b/src/IdeHelperServiceProvider.php index 0b4c6d5..91a64cd 100644 --- a/src/IdeHelperServiceProvider.php +++ b/src/IdeHelperServiceProvider.php @@ -10,10 +10,11 @@ namespace Barryvdh\LaravelIdeHelper; -use Illuminate\Support\ServiceProvider; +use Barryvdh\LaravelIdeHelper\Console\EloquentCommand; +use Barryvdh\LaravelIdeHelper\Console\GeneratorCommand; use Barryvdh\LaravelIdeHelper\Console\MetaCommand; use Barryvdh\LaravelIdeHelper\Console\ModelsCommand; -use Barryvdh\LaravelIdeHelper\Console\GeneratorCommand; +use Illuminate\Support\ServiceProvider; use Illuminate\View\Engines\EngineResolver; use Illuminate\View\Engines\PhpEngine; use Illuminate\View\Factory; @@ -38,7 +39,7 @@ class IdeHelperServiceProvider extends ServiceProvider { $viewPath = __DIR__.'/../resources/views'; $this->loadViewsFrom($viewPath, 'ide-helper'); - + $configPath = __DIR__ . '/../config/ide-helper.php'; if (function_exists('config_path')) { $publishPath = config_path('ide-helper.php'); @@ -58,7 +59,7 @@ class IdeHelperServiceProvider extends ServiceProvider $configPath = __DIR__ . '/../config/ide-helper.php'; $this->mergeConfigFrom($configPath, 'ide-helper'); $localViewFactory = $this->createLocalViewFactory(); - + $this->app->singleton( 'command.ide-helper.generate', function ($app) use ($localViewFactory) { @@ -72,15 +73,27 @@ class IdeHelperServiceProvider extends ServiceProvider return new ModelsCommand($app['files']); } ); - + $this->app->singleton( 'command.ide-helper.meta', function ($app) use ($localViewFactory) { - return new MetaCommand($app['files'], $localViewFactory); + return new MetaCommand($app['files'], $localViewFactory, $app['config']); } ); - $this->commands('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta'); + $this->app->singleton( + 'command.ide-helper.eloquent', + function ($app) use ($localViewFactory) { + return new EloquentCommand($app['files']); + } + ); + + $this->commands( + 'command.ide-helper.generate', + 'command.ide-helper.models', + 'command.ide-helper.meta', + 'command.ide-helper.eloquent' + ); } /**