diff --git a/.gitignore b/.gitignore index 335df2d..d53f981 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor composer.lock -.idea +.idea/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6825241 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +language: php +php: + - 5.4 + - 5.5 + - 5.6 + - hhvm + +matrix: + include: + - php: 5.3 + dist: precise + allow_failures: + - php: hhvm + fast_finish: true + +cache: + directories: + - vendor + - $HOME/.composer/cache + +before_script: + - travis_retry composer self-update + - travis_retry composer install --no-interaction --no-suggest --no-progress + +script: + - vendor/bin/phpunit diff --git a/composer.json b/composer.json index 5363cd8..1fe035d 100644 --- a/composer.json +++ b/composer.json @@ -11,14 +11,18 @@ ], "require": { "php": ">=5.3.0", + "illuminate/config": "4.x", "illuminate/support": "4.x", "illuminate/console": "4.x", "illuminate/filesystem": "4.x", - "barryvdh/reflection-docblock": "^2.0.4", + "illuminate/database": "4.x", + "illuminate/view": "4.x", + "phpdocumentor/reflection-docblock": "^2.0.4", "symfony/class-loader": "~2.3" }, "require-dev": { - "doctrine/dbal": "~2.3" + "doctrine/dbal": "~2.3", + "phpunit/phpunit": "~4.0" }, "suggest": { "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..7660980 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + diff --git a/readme.md b/readme.md index e2696a3..9d2efb1 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ _Checkout [this Laracasts video](https://laracasts.com/series/how-to-be-awesome-in-phpstorm/episodes/15) for a quick introduction/explanation!_ -This packages generates a file that your IDE can understand, so it can provide accurate autocompletion. Generation is done, based on the files in your project, so they are alway up-to-date. +This packages generates a file that your IDE can understand, so it can provide accurate autocompletion. Generation is done, based on the files in your project, so they are always up-to-date. If you don't want to generate it, you can add a pre-generated file to the root folder of your laravel project. (But this isn't as up-to-date as self generated files) * Generated version: https://gist.github.com/barryvdh/5227822 @@ -18,15 +18,18 @@ Note: You do need CodeIntel for Sublime Text: https://github.com/SublimeCodeInte 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 ann `Illuminate\Events\Dispatcher` object, so with the meta file you can call `app('events')` and it will autocomplete the Dispatcher methods. - php artisan ide-helper:meta - - app('events')->fire(); - \App::make('events')->fire(); - - /** @var \Illuminate\Foundation\Application $app */ - $app->make('events')->fire(); +```bash +php artisan ide-helper:meta +``` +```php +app('events')->fire(); +\App::make('events')->fire(); -Pre-generated example: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67 +/** @var \Illuminate\Foundation\Application $app */ +$app->make('events')->fire(); +``` + +Pre-generated example: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67 > Note: You might need to restart PhpStorm and make sure `.phpstorm.meta.php` is indexed. @@ -34,31 +37,41 @@ Pre-generated example: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67 Require this package with composer using the following command: - composer require barryvdh/laravel-ide-helper ~1.11 +```bash +composer require barryvdh/laravel-ide-helper ~1.11 +``` After updating composer, add the ServiceProvider to the providers array in `app/config/app.php` - 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', +```php +'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', +``` You can now re-generate the docs yourself (for future updates) in artisan - php artisan ide-helper:generate +```bash +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..) You can configure your composer.json to do this after each commit: - "scripts":{ - "post-update-cmd":[ - "php artisan clear-compiled", - "php artisan ide-helper:generate", - "php artisan optimize" - ] - }, +```json +"scripts":{ + "post-update-cmd":[ + "php artisan clear-compiled", + "php artisan ide-helper:generate", + "php artisan optimize" + ] +}, +``` You can also publish the config-file to change implementations (ie. interface to specific class) or set defaults for --helpers or --sublime. - php artisan config:publish barryvdh/laravel-ide-helper +```bash +php artisan config:publish barryvdh/laravel-ide-helper +``` The generator tries to identify the real class, but if it cannot be found, you can define it in the config file. @@ -70,7 +83,7 @@ The Illuminate/Support/helpers.php is already set-up, but you can add/remove you ### Automatic phpDocs for Models -> **Note:** Since v1.10 you need to require `doctrine/dbal: ~2.3` in your own composer.json. +> **Note:** Since v1.10 you need to require `doctrine/dbal: ~2.3` in your own composer.json. If you don't want to write your properties yourself, you can use the command `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)`). @@ -78,34 +91,43 @@ Please make sure to backup your models, before writing the info. It should keep the existing comments and only append new properties/methods. The existing phpdoc is replaced, or added if not found. With the `--reset (-R)` option, the existing phpdocs are ignored, only the newly found columns/relations are saved as phpdocs. - php artisan ide-helper:models Post - - /** - * An Eloquent Model: 'Post' - * - * @property integer $id - * @property integer $author_id - * @property string $title - * @property string $text - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property-read \User $author - * @property-read \Illuminate\Database\Eloquent\Collection|\Comment[] $comments - */ +```bash +php artisan ide-helper:models Post +``` +```php +/** + * An Eloquent Model: 'Post' + * + * @property integer $id + * @property integer $author_id + * @property string $title + * @property string $text + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property-read \User $author + * @property-read \Illuminate\Database\Eloquent\Collection|\Comment[] $comments + */ +``` By default, models in app/models are scanned. The optional argument tells what models to use (also outside app/models). - php artisan ide-helper:models Post User +```bash +php artisan ide-helper:models Post User +``` You can also scan a different directory, using the --dir option (relative from the base path): - php artisan ide-helper:models --dir="app/workbench/name/package/models" --dir="app/src/Model" - +```bash +php artisan ide-helper:models --dir="app/workbench/name/package/models" --dir="app/src/Model" +``` + You can publish the config file (`php artisan config:publish barryvdh/laravel-ide-helper`) and set the default directories. Models can be ignored using the --ignore (-I) option - php artisan ide-helper:models --ignore="Post,User" +```bash +php artisan ide-helper:models --ignore="Post,User" +``` Note: With namespaces, wrap your model name in " signs: `php artisan ide-helper:models "API\User"`, or escape the slashes (`Api\\User`) diff --git a/src/Alias.php b/src/Alias.php index 3996931..745b327 100644 --- a/src/Alias.php +++ b/src/Alias.php @@ -1,284 +1,287 @@ - - * @copyright 2014 Barry vd. Heuvel / 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; - -class Alias -{ - protected $alias; - protected $facade; - protected $extends = null; - protected $classType = 'class'; - protected $short; - protected $namespace = '__root'; - protected $root = null; - protected $classes = array(); - protected $methods = array(); - protected $usedMethods = array(); - protected $valid = false; - protected $magicMethods = array(); - protected $interfaces = array(); - - /** - * @param string $alias - * @param string $facade - * @param array $magicMethods - * @param array $interfaces - */ - public function __construct($alias, $facade, $magicMethods = array(), $interfaces = array()) - { - $this->alias = $alias; - $this->magicMethods = $magicMethods; - $this->interfaces = $interfaces; - - // Make the class absolute - $facade = '\\' . ltrim($facade, '\\'); - $this->facade = $facade; - - $this->detectRoot(); - - if ((!$this->isTrait() && $this->root)) { - $this->valid = true; - } else { - return; - } - - $this->addClass($this->root); - $this->detectNamespace(); - $this->detectClassType(); - - if($facade === '\Illuminate\Database\Eloquent\Model'){ - $this->usedMethods = array('decrement', 'increment'); - } - } - - /** - * Add one or more classes to analyze - * - * @param array|string $classes - */ - public function addClass($classes) - { - $classes = (array)$classes; - foreach ($classes as $class) { - if (class_exists($class) || interface_exists($class)) { - $this->classes[] = $class; - }else{ - echo "Class not exists: $class\r\n"; - } - } - } - - /** - * Check if this class is valid to process. - * @return bool - */ - public function isValid() - { - return $this->valid; - } - - /** - * Get the classtype, 'interface' or 'class' - * - * @return string - */ - public function getClasstype() - { - return $this->classType; - } - - /** - * Get the class which this alias extends - * - * @return null|string - */ - public function getExtends() - { - return $this->extends; - } - - /** - * Get the Alias by which this class is called - * - * @return string - */ - public function getAlias() - { - return $this->alias; - } - - /** - * Return the short name (without namespace) - */ - public function getShortName(){ - return $this->short; - } - /** - * Get the namespace from the alias - * - * @return string - */ - public function getNamespace() - { - return $this->namespace; - } - - /** - * Get the methods found by this Alias - * - * @return array - */ - public function getMethods() - { - $this->addMagicMethods(); - $this->detectMethods(); - return $this->methods; - } - - /** - * Detect the namespace - */ - protected function detectNamespace() - { - if (strpos($this->alias, '\\')) { - $nsParts = explode('\\', $this->alias); - $this->short = array_pop($nsParts); - $this->namespace = implode('\\', $nsParts); - }else{ - $this->short = $this->alias; - } - } - - /** - * Detect the class type - */ - protected function detectClassType() - { - //Some classes extend the facade - if (interface_exists($this->facade)) { - $this->classType = 'interface'; - $this->extends = $this->facade; - } else { - $this->classType = 'class'; - if (class_exists($this->facade)) { - $this->extends = $this->facade; - } - } - } - - /** - * Get the real root of a facade - * - * @return bool|string - */ - protected function detectRoot() - { - $facade = $this->facade; - - try { - //If possible, get the facade root - if (method_exists($facade, 'getFacadeRoot')) { - $root = get_class($facade::getFacadeRoot()); - } else { - $root = $facade; - } - - //If it doesn't exist, skip it - if (!class_exists($root) && !interface_exists($root)) { - return; - } - - $this->root = $root; - - //When the database connection is not set, some classes will be skipped - } catch (\PDOException $e) { - $this->error( - "PDOException: " . $e->getMessage() . "\nPlease configure your database connection correctly, or use the sqlite memory driver (-M). Skipping $facade." - ); - } catch (\Exception $e) { - $this->error("Exception: " . $e->getMessage() . "\nSkipping $facade."); - } - } - - /** - * Detect if this class is a trait or not. - * - * @return bool - */ - protected function isTrait() - { - // Check if the facade is not a Trait - if (function_exists('trait_exists') && trait_exists($this->facade)) { - return true; - } - return false; - } - - /** - * Add magic methods, as defined in the configuration files - */ - protected function addMagicMethods() - { - foreach($this->magicMethods as $magic => $real){ - list($className, $name) = explode('::', $real); - if(!class_exists($className) && !interface_exists($className)){ - continue; - } - $method = new \ReflectionMethod($className, $name); - $class = new \ReflectionClass($className); - - if(!in_array($method->name, $this->usedMethods)){ - if($class !== $this->root){ - $this->methods[] = new Method($method, $this->alias, $class, $magic, $this->interfaces); - } - $this->usedMethods[] = $magic; - } - } - } - - /** - * Get the methods for one or multiple classes. - * - * @return string - */ - protected function detectMethods() - { - - foreach ($this->classes as $class) { - $reflection = new \ReflectionClass($class); - - $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); - if ($methods) { - foreach ($methods as $method) { - if (!in_array($method->name, $this->usedMethods)) { - // Only add the methods to the output when the root is not the same as the class. - // And don't add the __*() methods - if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') { - $this->methods[] = new Method($method, $this->alias, $reflection, $method->name, $this->interfaces); - } - $this->usedMethods[] = $method->name; - } - } - } - } - } - - /** - * Output an error. - * - * @param string $string - * @return void - */ - protected function error($string) - { - echo $string . "\r\n"; - } -} + + * @copyright 2014 Barry vd. Heuvel / 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; + +class Alias +{ + protected $alias; + protected $facade; + protected $extends = null; + protected $classType = 'class'; + protected $short; + protected $namespace = '__root'; + protected $root = null; + protected $classes = array(); + protected $methods = array(); + protected $usedMethods = array(); + protected $valid = false; + protected $magicMethods = array(); + protected $interfaces = array(); + + /** + * @param string $alias + * @param string $facade + * @param array $magicMethods + * @param array $interfaces + */ + public function __construct($alias, $facade, $magicMethods = array(), $interfaces = array()) + { + $this->alias = $alias; + $this->magicMethods = $magicMethods; + $this->interfaces = $interfaces; + + // Make the class absolute + $facade = '\\' . ltrim($facade, '\\'); + $this->facade = $facade; + + $this->detectRoot(); + + if ((!$this->isTrait() && $this->root)) { + $this->valid = true; + } else { + return; + } + + $this->addClass($this->root); + $this->detectNamespace(); + $this->detectClassType(); + + if ($facade === '\Illuminate\Database\Eloquent\Model') { + $this->usedMethods = array('decrement', 'increment'); + } + } + + /** + * Add one or more classes to analyze + * + * @param array|string $classes + */ + public function addClass($classes) + { + $classes = (array)$classes; + foreach ($classes as $class) { + if (class_exists($class) || interface_exists($class)) { + $this->classes[] = $class; + } else { + $this->error('Class not exists: ' . $class); + } + } + } + + /** + * Check if this class is valid to process. + * @return bool + */ + public function isValid() + { + return $this->valid; + } + + /** + * Get the classType, 'interface' or 'class' + * + * @return string + */ + public function getClassType() + { + return $this->classType; + } + + /** + * Get the class which this alias extends + * + * @return null|string + */ + public function getExtends() + { + return $this->extends; + } + + /** + * Get the Alias by which this class is called + * + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * Return the short name (without namespace) + * + * @return string + */ + public function getShortName() + { + return $this->short; + } + + /** + * Get the namespace from the alias + * + * @return string + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * Get the methods found by this Alias + * + * @return array|Method[] + */ + public function getMethods() + { + $this->addMagicMethods(); + $this->detectMethods(); + return $this->methods; + } + + /** + * Detect the namespace + */ + protected function detectNamespace() + { + if (strpos($this->alias, '\\')) { + $nsParts = explode('\\', $this->alias); + $this->short = array_pop($nsParts); + $this->namespace = implode('\\', $nsParts); + } else { + $this->short = $this->alias; + } + } + + /** + * Detect the class type + */ + protected function detectClassType() + { + //Some classes extend the facade + if (interface_exists($this->facade)) { + $this->classType = 'interface'; + $this->extends = $this->facade; + } else { + $this->classType = 'class'; + if (class_exists($this->facade)) { + $this->extends = $this->facade; + } + } + } + + /** + * Get the real root of a facade + * + * @return bool|string + */ + protected function detectRoot() + { + $facade = $this->facade; + + try { + //If possible, get the facade root + if (method_exists($facade, 'getFacadeRoot')) { + $root = get_class($facade::getFacadeRoot()); + } else { + $root = $facade; + } + + //If it doesn't exist, skip it + if (!class_exists($root) && !interface_exists($root)) { + return; + } + + $this->root = $root; + + //When the database connection is not set, some classes will be skipped + } catch (\PDOException $e) { + $this->error( + 'PDOException: ' . $e->getMessage() . "\nPlease configure your database connection correctly, or use the sqlite memory driver (-M). Skipping $facade." + ); + } catch (\Exception $e) { + $this->error('Exception: ' . $e->getMessage() . "\nSkipping $facade."); + } + } + + /** + * Detect if this class is a trait or not. + * + * @return bool + */ + protected function isTrait() + { + // Check if the facade is not a Trait + if (function_exists('trait_exists') && trait_exists($this->facade)) { + return true; + } + return false; + } + + /** + * Add magic methods, as defined in the configuration files + */ + protected function addMagicMethods() + { + foreach ($this->magicMethods as $magic => $real) { + list($className, $name) = explode('::', $real); + if (!class_exists($className) && !interface_exists($className)) { + continue; + } + $method = new \ReflectionMethod($className, $name); + $class = new \ReflectionClass($className); + + if (!in_array($method->name, $this->usedMethods)) { + if ($class !== $this->root) { + $this->methods[] = new Method($method, $this->alias, $class, $magic, $this->interfaces); + } + $this->usedMethods[] = $magic; + } + } + } + + /** + * Get the methods for one or multiple classes. + * + * @return string + */ + protected function detectMethods() + { + foreach ($this->classes as $class) { + $reflection = new \ReflectionClass($class); + + $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); + if ($methods) { + foreach ($methods as $method) { + if (!in_array($method->name, $this->usedMethods)) { + // Only add the methods to the output when the root is not the same as the class. + // And don't add the __*() methods + if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') { + $this->methods[] = new Method($method, $this->alias, $reflection, $method->name, $this->interfaces); + } + $this->usedMethods[] = $method->name; + } + } + } + } + } + + /** + * Output an error. + * + * @param string $string + * @return void + */ + protected function error($string) + { + echo $string . "\r\n"; + } +} diff --git a/src/Console/GeneratorCommand.php b/src/Console/GeneratorCommand.php index e1a9477..cc19df5 100644 --- a/src/Console/GeneratorCommand.php +++ b/src/Console/GeneratorCommand.php @@ -17,7 +17,6 @@ use Illuminate\Filesystem\Filesystem; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; - /** * A command to generate autocomplete information for your IDE * @@ -27,16 +26,12 @@ class GeneratorCommand extends Command { /** - * The console command name. - * - * @var string + * {@inheritdoc} */ protected $name = 'ide-helper:generate'; /** - * The console command description. - * - * @var string + * {@inheritdoc} */ protected $description = 'Generate a new IDE Helper file.'; @@ -51,18 +46,14 @@ class GeneratorCommand extends Command protected $onlyExtend; - /** + * {@inheritdoc} * * @param \Illuminate\Config\Repository $config * @param \Illuminate\Filesystem\Filesystem $files * @param \Illuminate\View\Factory $view */ - public function __construct( - ConfigRepository $config, - Filesystem $files, /* Illuminate\View\Factory */ - $view - ) { + public function __construct(ConfigRepository $config, Filesystem $files, $view) { $this->config = $config; $this->files = $files; $this->view = $view; @@ -95,7 +86,6 @@ class GeneratorCommand extends Command $this->useMemoryDriver(); } - $helpers = ''; if ($this->option('helpers') || ($this->config->get('laravel-ide-helper::include_helpers'))) { foreach ($this->config->get('laravel-ide-helper::helper_files', array()) as $helper) { @@ -133,9 +123,7 @@ class GeneratorCommand extends Command } /** - * Get the console command arguments. - * - * @return array + * {@inheritdoc} */ protected function getArguments() { @@ -149,19 +137,17 @@ class GeneratorCommand extends Command } /** - * Get the console command options. - * - * @return array + * {@inheritdoc} */ protected function getOptions() { $format = $this->config->get('laravel-ide-helper::format'); return array( - array('format', "F", InputOption::VALUE_OPTIONAL, 'The format for the IDE Helper', $format), - 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'), + array('format', 'F', InputOption::VALUE_OPTIONAL, 'The format for the IDE Helper', $format), + 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'), ); } diff --git a/src/Console/MetaCommand.php b/src/Console/MetaCommand.php index 23e29bb..1e36bf0 100644 --- a/src/Console/MetaCommand.php +++ b/src/Console/MetaCommand.php @@ -17,21 +17,18 @@ use Symfony\Component\Console\Input\InputOption; * A command to generate phpstorm meta data * * @author Barry vd. Heuvel + * @property \Illuminate\Container\Container $laravel */ class MetaCommand extends Command { /** - * The console command name. - * - * @var string + * {@inheritdoc} */ protected $name = 'ide-helper:meta'; protected $filename = '.phpstorm.meta.php'; /** - * The console command description. - * - * @var string + * {@inheritdoc} */ protected $description = 'Generate metadata for PhpStorm'; @@ -40,22 +37,25 @@ class MetaCommand extends Command { /** @var \Illuminate\View\Factory */ protected $view; - + protected $methods = array( - '\Illuminate\Foundation\Application::make', - '\Illuminate\Container\Container::make', - '\App::make', - 'app', + //'\Illuminate\Foundation\Application::make', + 'new \Illuminate\Container\Container', + '\Illuminate\Container\Container::make', + '\App::make', + 'app', ); /** + * {@inheritdoc} * - * @param \Illuminate\Filesystem\Filesystem $files - * @param \Illuminate\View\Factory $view + * @param \Illuminate\Container\Container $app */ - public function __construct($files, $view) { - $this->files = $files; - $this->view = $view; + public function __construct($app) + { + $this->laravel = $app; + $this->files = $app['files']; + $this->view = $app['view']; parent::__construct(); } @@ -66,23 +66,32 @@ class MetaCommand extends Command { */ public function fire() { - $bindings = array(); + $bindings = array_flip($this->getAppAliases()); + $exclude = $this->option('exclude'); + if (!empty($exclude)) { + $exclude = '/' . str_replace('\|', '|', preg_quote($exclude, '/')) . '/'; + } + foreach ($this->getAbstracts() as $abstract) { + if (!empty($exclude) && preg_match($exclude, $abstract)) + continue; + try { $concrete = $this->laravel->make($abstract); if (is_object($concrete)) { $bindings[$abstract] = get_class($concrete); } - }catch (\Exception $e) { - $this->error("Cannot make $abstract: ".$e->getMessage()); + } catch (\Exception $e) { + $this->error("Cannot make $abstract: " . $e->getMessage()); } } - + asort($bindings); + $content = $this->view->make('laravel-ide-helper::meta', array( - 'bindings' => $bindings, - 'methods' => $this->methods, + 'bindings' => $bindings, + 'methods' => $this->methods, ))->render(); - + $filename = $this->option('filename'); $written = $this->files->put($filename, $content); @@ -92,10 +101,10 @@ class MetaCommand extends Command { $this->error("The meta file could not be created at $filename"); } } - + /** * Get a list of abstracts from the Laravel Application. - * + * * @return array */ protected function getAbstracts() @@ -104,14 +113,28 @@ class MetaCommand extends Command { } /** - * Get the console command options. + * Get a list of aliases from the Laravel Application. * * @return array */ + protected function getAppAliases() + { + static $aliasProp; + if (!isset($aliasProp)) { + $aliasProp = new \ReflectionProperty('Illuminate\Container\Container', 'aliases'); + $aliasProp->setAccessible(true); + } + return $aliasProp->getValue($this->laravel); + } + + /** + * {@inheritdoc} + */ protected function getOptions() { return array( array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the meta file', $this->filename), + array('exclude', 'E', InputOption::VALUE_OPTIONAL, 'Laravel bindings to exclude (e.g. "bar.|.foo")'), ); } } diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 1100e58..a9f1e40 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -15,31 +15,27 @@ use Illuminate\Support\Str; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\ClassLoader\ClassMapGenerator; -use Barryvdh\Reflection\DocBlock; -use Barryvdh\Reflection\DocBlock\Context; -use Barryvdh\Reflection\DocBlock\Tag; -use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; +use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\DocBlock\Context; +use phpDocumentor\Reflection\DocBlock\Tag; /** * A command to generate autocomplete information for your IDE * * @author Barry vd. Heuvel + * @property \Illuminate\Container\Container $laravel */ class ModelsCommand extends Command { /** - * The console command name. - * - * @var string + * {@inheritdoc} */ protected $name = 'ide-helper:models'; protected $filename = '_ide_helper_models.php'; /** - * The console command description. - * - * @var string + * {@inheritdoc} */ protected $description = 'Generate autocompletion for models'; @@ -49,6 +45,20 @@ class ModelsCommand extends Command protected $dirs = array(); protected $reset; + /** @var \Illuminate\Filesystem\Filesystem */ + protected $files; + + /** + * {@inheritdoc} + * + * @param \Illuminate\Container\Container $app + */ + public function __construct($app) + { + $this->laravel = $app; + $this->files = $app['files']; + parent::__construct(); + } /** * Execute the console command. @@ -69,10 +79,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? (Yes/No): " - ) - ) { + if ($this->confirm("Do you want to overwrite the existing model files? Choose no to write to $filename instead? (Yes/No): ")) { $this->write = true; } } @@ -80,7 +87,7 @@ class ModelsCommand extends Command $content = $this->generateDocs($model, $ignore); if (!$this->write) { - $written = \File::put($filename, $content); + $written = $this->files->put($filename, $content); if ($written !== false) { $this->info("Model information was written to $filename"); } else { @@ -89,11 +96,8 @@ class ModelsCommand extends Command } } - /** - * Get the console command arguments. - * - * @return array + * {@inheritdoc} */ protected function getArguments() { @@ -103,9 +107,7 @@ class ModelsCommand extends Command } /** - * Get the console command options. - * - * @return array + * {@inheritdoc} */ protected function getOptions() { @@ -121,8 +123,6 @@ class ModelsCommand extends Command protected function generateDocs($loadModels, $ignore = '') { - - $output = "comment("Loading model '$name'"); - if (!$reflectionClass->IsInstantiable()) { + if (!$reflectionClass->isInstantiable()) { throw new \Exception($name . ' is not instantiable.'); } @@ -177,7 +177,7 @@ class ModelsCommand extends Command $this->getPropertiesFromMethods($model); $output .= $this->createPhpDocs($name); } catch (\Exception $e) { - $this->error("Exception: " . $e->getMessage() . "\nCould not analyze class $name."); + $this->error('Exception: ' . $e->getMessage() . "\nCould not analyze class $name."); } } @@ -190,10 +190,8 @@ class ModelsCommand extends Command } return $output; - } - protected function loadModels() { $models = array(); @@ -259,7 +257,7 @@ class ModelsCommand extends Command $comment = $column->getComment(); $this->setProperty($name, $type, true, true, $comment); $this->setMethod( - Str::camel("where_" . $name), + Str::camel('where_' . $name), '\Illuminate\Database\Query\Builder|\\' . get_class($model), array('$value') ); @@ -275,21 +273,13 @@ class ModelsCommand extends Command $methods = get_class_methods($model); if ($methods) { foreach ($methods as $method) { - if (Str::startsWith($method, 'get') && Str::endsWith( - $method, - 'Attribute' - ) && $method !== 'getAttribute' - ) { + if (Str::startsWith($method, 'get') && Str::endsWith($method, 'Attribute') && $method !== 'getAttribute') { //Magic getAttribute $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { $this->setProperty($name, null, true, null); } - } elseif (Str::startsWith($method, 'set') && Str::endsWith( - $method, - 'Attribute' - ) && $method !== 'setAttribute' - ) { + } elseif (Str::startsWith($method, 'set') && Str::endsWith($method, 'Attribute') && $method !== 'setAttribute') { //Magic setAttribute $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { @@ -321,22 +311,14 @@ class ModelsCommand extends Command $begin = strpos($code, 'function('); $code = substr($code, $begin, strrpos($code, '}') - $begin + 1); - foreach (array( - 'hasMany', - 'belongsToMany', - 'hasOne', - 'belongsTo', - 'morphTo', - 'morphMany', - 'morphToMany' - ) as $relation) { + foreach (array('hasMany', 'belongsToMany', 'hasOne', 'belongsTo', 'morphTo', 'morphMany', 'morphToMany') as $relation) { $search = '$this->' . $relation . '('; if ($pos = stripos($code, $search)) { $code = substr($code, $pos + strlen($search)); $arguments = explode(',', substr($code, 0, strpos($code, ');'))); //Remove quotes, ensure 1 \ in front of the model $returnModel = $this->getClassName($arguments[0], $model); - if ($relation === "belongsToMany" or $relation === 'hasMany' or $relation === 'morphMany' or $relation === 'morphToMany') { + if ($relation === 'belongsToMany' or $relation === 'hasMany' or $relation === 'morphMany' or $relation === 'morphToMany') { //Collection or array of models (because Collection is Arrayable) $this->setProperty( $method, @@ -363,14 +345,14 @@ class ModelsCommand extends Command * @param bool|null $write * @param string|null $comment */ - protected function setProperty($name, $type = null, $read = null, $write = null, $comment='') + protected function setProperty($name, $type = null, $read = null, $write = null, $comment = '') { if (!isset($this->properties[$name])) { $this->properties[$name] = array(); $this->properties[$name]['type'] = 'mixed'; $this->properties[$name]['read'] = false; $this->properties[$name]['write'] = false; - $this->properties[$name]['comment'] = (string) $comment; + $this->properties[$name]['comment'] = (string)$comment; } if ($type !== null) { $this->properties[$name]['type'] = $type; @@ -398,10 +380,9 @@ class ModelsCommand extends Command */ protected function createPhpDocs($class) { - $reflection = new \ReflectionClass($class); $namespace = $reflection->getNamespaceName(); - $classname = $reflection->getShortName(); + $className = $reflection->getShortName(); $originalDoc = $reflection->getDocComment(); if ($this->reset) { @@ -417,10 +398,11 @@ class ModelsCommand extends Command $properties = array(); $methods = array(); foreach ($phpdoc->getTags() as $tag) { + /* @var Tag|Tag\PropertyTag|Tag\MethodTag $tag */ $name = $tag->getName(); - if ($name == "property" || $name == "property-read" || $name == "property-write") { + if ($name == 'property' || $name == 'property-read' || $name == 'property-write') { $properties[] = $tag->getVariableName(); - } elseif ($name == "method") { + } elseif ($name == 'method') { $methods[] = $tag->getMethodName(); } } @@ -450,47 +432,46 @@ class ModelsCommand extends Command $phpdoc->appendTag($tag); } - $serializer = new DocBlockSerializer(); + $serializer = new DocBlock\Serializer(); $serializer->getDocComment($phpdoc); $docComment = $serializer->getDocComment($phpdoc); - if ($this->write) { $filename = $reflection->getFileName(); - $contents = \File::get($filename); + $contents = $this->files->get($filename); if ($originalDoc) { $contents = str_replace($originalDoc, $docComment, $contents); } else { - $needle = "class {$classname}"; - $replace = "{$docComment}\nclass {$classname}"; + $needle = "class {$className}"; + $replace = "{$docComment}\nclass {$className}"; $pos = strpos($contents, $needle); if ($pos !== false) { $contents = substr_replace($contents, $replace, $pos, strlen($needle)); } } - if (\File::put($filename, $contents)) { + if ($this->files->put($filename, $contents)) { $this->info('Written new phpDocBlock to ' . $filename); } } - $output = "namespace {$namespace}{\n{$docComment}\n\tclass {$classname} {}\n}\n\n"; + $output = "namespace {$namespace}{\n{$docComment}\n\tclass {$className} {}\n}\n\n"; return $output; } /** * Get the parameters and format them correctly * - * @param $method + * @param \ReflectionMethod $method * @return array */ public function getParameters($method) { - //Loop through the default values for paremeters, and make the correct output string - $params = array(); + //Loop through the default values for parameters, and make the correct output string $paramsWithDefault = array(); + foreach ($method->getParameters() as $param) { $paramStr = '$' . $param->getName(); - $params[] = $paramStr; + if ($param->isOptional()) { $default = $param->getDefaultValue(); if (is_bool($default)) { @@ -508,6 +489,7 @@ class ModelsCommand extends Command } $paramsWithDefault[] = $paramStr; } + return $paramsWithDefault; } @@ -529,6 +511,6 @@ class ModelsCommand extends Command return substr($className, 0, $end); } - return "\\" . ltrim(trim($className, " \"'"), "\\") ; + return '\\' . ltrim(trim($className, ' "\''), '\\'); } } diff --git a/src/Generator.php b/src/Generator.php index 74d8fd8..39e2bf5 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -1,235 +1,245 @@ - - * @copyright 2014 Barry vd. Heuvel / 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; - -use Illuminate\Foundation\AliasLoader; -use Illuminate\Config\Repository as ConfigRepository; -use Symfony\Component\Console\Output\OutputInterface; - -class Generator -{ - /** @var \Illuminate\Config\Repository */ - protected $config; - - /** @var \Illuminate\View\Factory */ - protected $view; - - /** @var \Symfony\Component\Console\Output\OutputInterface */ - protected $output; - - protected $extra = array(); - protected $magic = array(); - protected $interfaces = array(); - protected $helpers; - - /** - * @param \Illuminate\Config\Repository $config - * @param \Illuminate\View\Factory $view - * @param \Symfony\Component\Console\Output\OutputInterface $output - * @param string $helpers - */ - public function __construct(ConfigRepository $config, - /* Illuminate\View\Factory */ $view, - OutputInterface $output = null, - $helpers = '' - ) { - $this->config = $config; - $this->view = $view; - - // Find the drivers to add to the extra/interfaces - $this->detectDrivers(); - - $this->extra = array_merge($this->extra, $this->config->get('laravel-ide-helper::extra')); - $this->magic = array_merge($this->magic, $this->config->get('laravel-ide-helper::magic')); - $this->interfaces = array_merge($this->interfaces, $this->config->get('laravel-ide-helper::interfaces')); - // Make all interface classes absolute - foreach ($this->interfaces as &$interface) { - $interface = '\\' . ltrim($interface, '\\'); - } - $this->helpers = $helpers; - } - - /** - * Generate the helper file contents; - * - * @param string $format The format to generate the helper in (php/json) - * @return string; - */ - public function generate($format = 'php') - { - // Check if the generator for this format exists - $method = 'generate'.ucfirst($format).'Helper'; - if (method_exists($this, $method)) { - return $this->$method(); - } - - return $this->generatePhpHelper(); - } - - public function generatePhpHelper() - { - $app = app(); - return $this->view->make('laravel-ide-helper::ide-helper') - ->with('namespaces', $this->getNamespaces()) - ->with('helpers', $this->helpers) - ->with('version', $app::VERSION) - ->render(); - } - - public function generateJsonHelper() - { - $classes = array(); - foreach ($this->getNamespaces() as $aliases) { - foreach($aliases as $alias) { - $functions = array(); - foreach ($alias->getMethods() as $method) { - $functions[$method->getName()] = '('. $method->getParamsWithDefault().')'; - } - $classes[$alias->getAlias()] = array( - 'functions' => $functions, - ); - } - } - - $flags = JSON_FORCE_OBJECT; - if (defined('JSON_PRETTY_PRINT')) { - $flags |= JSON_PRETTY_PRINT; - } - - return json_encode(array( - 'php' => array( - 'classes' => $classes, - ), - ), $flags); - } - - protected function detectDrivers() - { - try{ + + * @copyright 2014 Barry vd. Heuvel / 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; + +use /** @noinspection PhpUndefinedNamespaceInspection,PhpUndefinedClassInspection */Illuminate\Foundation\AliasLoader; +use Illuminate\Config\Repository as ConfigRepository; +use Symfony\Component\Console\Output\OutputInterface; + +class Generator +{ + /** @var \Illuminate\Config\Repository */ + protected $config; + + /** @var \Illuminate\View\Factory */ + protected $view; + + /** @var \Symfony\Component\Console\Output\OutputInterface */ + protected $output; + + protected $extra = array(); + protected $magic = array(); + protected $interfaces = array(); + protected $helpers; + + /** + * @param \Illuminate\Config\Repository $config + * @param \Illuminate\View\Factory $view + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @param string $helpers + */ + public function __construct(ConfigRepository $config, $view, OutputInterface $output = null, $helpers = '') + { + $this->config = $config; + $this->view = $view; + + // Find the drivers to add to the extra/interfaces + $this->detectDrivers(); + + $this->extra = array_merge($this->extra, $this->config->get('laravel-ide-helper::extra')); + $this->magic = array_merge($this->magic, $this->config->get('laravel-ide-helper::magic')); + $this->interfaces = array_merge($this->interfaces, $this->config->get('laravel-ide-helper::interfaces')); + + // Make all interface classes absolute + foreach ($this->interfaces as &$interface) { + $interface = '\\' . ltrim($interface, '\\'); + } + $this->helpers = $helpers; + } + + /** + * Generate the helper file contents; + * + * @param string $format The format to generate the helper in (php/json) + * @return string; + */ + public function generate($format = 'php') + { + // Check if the generator for this format exists + $method = 'generate' . ucfirst($format) . 'Helper'; + if (method_exists($this, $method)) { + return $this->$method(); + } + + return $this->generatePhpHelper(); + } + + public function generatePhpHelper() + { + $app = app(); + return $this->view->make('laravel-ide-helper::ide-helper') + ->with('namespaces', $this->getNamespaces()) + ->with('helpers', $this->helpers) + ->with('version', $app::VERSION) + ->render(); + } + + public function generateJsonHelper() + { + $classes = array(); + foreach ($this->getNamespaces() as $aliases) { + foreach ($aliases as $alias) { + $functions = array(); + foreach ($alias->getMethods() as $method) { + $functions[$method->getName()] = '(' . $method->getParamsWithDefault() . ')'; + } + $classes[$alias->getAlias()] = array( + 'functions' => $functions, + ); + } + } + + $flags = JSON_FORCE_OBJECT; + if (defined('JSON_PRETTY_PRINT')) { + $flags |= JSON_PRETTY_PRINT; + } + + return json_encode(array( + 'php' => array( + 'classes' => $classes, + ), + ), $flags); + } + + protected function detectDrivers() + { + try { if (class_exists('Auth') && is_a('Auth', '\Illuminate\Support\Facades\Auth', true)) { - $class = get_class(\Auth::driver()); - $this->extra['Auth'] = array($class); - $this->interfaces['\Illuminate\Auth\UserProviderInterface'] = $class; - } - }catch (\Exception $e) {} - - try{ - if (class_exists('DB') && is_a('DB', '\Illuminate\Support\Facades\DB', true)) { - $class = get_class(\DB::connection()); - $this->extra['DB'] = array($class); - $this->interfaces['\Illuminate\Database\ConnectionInterface'] = $class; - } - }catch (\Exception $e) {} - - try{ - if (class_exists('Cache') && is_a('Cache', '\Illuminate\Support\Facades\Cache', true)) { - $driver = get_class(\Cache::driver()); - $store = get_class(\Cache::getStore()); - $this->extra['Cache'] = array($driver, $store); - $this->interfaces['\Illuminate\Cache\StoreInterface'] = $store; - } - }catch (\Exception $e) {} - - try{ - if (class_exists('Queue') && is_a('Queue', '\Illuminate\Support\Facades\Queue', true)) { - $class = get_class(\Queue::connection()); - $this->extra['Queue'] = array($class); - $this->interfaces['\Illuminate\Queue\QueueInterface'] = $class; - } - }catch (\Exception $e) {} - - try{ - if (class_exists('SSH') && is_a('SSH', '\Illuminate\Support\Facades\SSH', true)){ - $class = get_class(\SSH::connection()); - $this->extra['SSH'] = array($class); - $this->interfaces['\Illuminate\Remote\ConnectionInterface'] = $class; - } - }catch (\Exception $e) {} - - } - - /** - * Find all namespaces/aliases that are valid for us to render - * - * @return array - */ - protected function getNamespaces() - { - $namespaces = array(); - - // Get all aliases - foreach (AliasLoader::getInstance()->getAliases() as $name => $facade) { - $magicMethods = array_key_exists($name, $this->magic) ? $this->magic[$name] : array(); - $alias = new Alias($name, $facade, $magicMethods, $this->interfaces); - if ($alias->isValid()) { - - //Add extra methods, from other classes (magic static calls) - if (array_key_exists($name, $this->extra)) { - $alias->addClass($this->extra[$name]); - } - - $namespace = $alias->getNamespace(); - if (!isset($namespaces[$namespace])) { - $namespaces[$namespace] = array(); - } - $namespaces[$namespace][] = $alias; - } - - } - - return $namespaces; - } - - /** - * Get the driver/connection/store from the managers - * - * @param $alias - * @return array|bool|string - */ - public function getDriver($alias) - { - try { - if ($alias == "Auth") { - $driver = \Auth::driver(); - } elseif ($alias == "DB") { - $driver = \DB::connection(); - } elseif ($alias == "Cache") { - $driver = get_class(\Cache::driver()); - $store = get_class(\Cache::getStore()); - return array($driver, $store); - } elseif ($alias == "Queue") { - $driver = \Queue::connection(); - } else { - return false; - } - - return get_class($driver); - } catch (\Exception $e) { - $this->error("Could not determine driver/connection for $alias."); - return false; - } - } - - /** - * Write a string as error output. - * - * @param string $string - * @return void - */ - protected function error($string) - { - if($this->output){ - $this->output->writeln("$string"); - }else{ - echo $string . "\r\n"; - } - } -} + /** @noinspection PhpUndefinedClassInspection */ + $class = get_class(\Auth::driver()); + $this->extra['Auth'] = array($class); + $this->interfaces['\Illuminate\Auth\UserProviderInterface'] = $class; + } + } catch (\Exception $e) {} + + try { + if (class_exists('DB') && is_a('DB', '\Illuminate\Support\Facades\DB', true)) { + /** @noinspection PhpUndefinedClassInspection */ + $class = get_class(\DB::connection()); + $this->extra['DB'] = array($class); + $this->interfaces['\Illuminate\Database\ConnectionInterface'] = $class; + } + } catch (\Exception $e) {} + + try { + if (class_exists('Cache') && is_a('Cache', '\Illuminate\Support\Facades\Cache', true)) { + /** @noinspection PhpUndefinedClassInspection */ + $driver = get_class(\Cache::driver()); + /** @noinspection PhpUndefinedClassInspection */ + $store = get_class(\Cache::getStore()); + $this->extra['Cache'] = array($driver, $store); + $this->interfaces['\Illuminate\Cache\StoreInterface'] = $store; + } + } catch (\Exception $e) {} + + try { + if (class_exists('Queue') && is_a('Queue', '\Illuminate\Support\Facades\Queue', true)) { + /** @noinspection PhpUndefinedClassInspection */ + $class = get_class(\Queue::connection()); + $this->extra['Queue'] = array($class); + $this->interfaces['\Illuminate\Queue\QueueInterface'] = $class; + } + } catch (\Exception $e) {} + + try { + if (class_exists('SSH') && is_a('SSH', '\Illuminate\Support\Facades\SSH', true)) { + /** @noinspection PhpUndefinedClassInspection */ + $class = get_class(\SSH::connection()); + $this->extra['SSH'] = array($class); + $this->interfaces['\Illuminate\Remote\ConnectionInterface'] = $class; + } + } catch (\Exception $e) {} + + } + + /** + * Find all namespaces/aliases that are valid for us to render + * + * @return array|Alias[][] + */ + protected function getNamespaces() + { + $namespaces = array(); + + // Get all aliases + /** @noinspection PhpUndefinedClassInspection */ + foreach (AliasLoader::getInstance()->getAliases() as $name => $facade) { + $magicMethods = array_key_exists($name, $this->magic) ? $this->magic[$name] : array(); + $alias = new Alias($name, $facade, $magicMethods, $this->interfaces); + if ($alias->isValid()) { + + //Add extra methods, from other classes (magic static calls) + if (array_key_exists($name, $this->extra)) { + $alias->addClass($this->extra[$name]); + } + + $namespace = $alias->getNamespace(); + if (!isset($namespaces[$namespace])) { + $namespaces[$namespace] = array(); + } + $namespaces[$namespace][] = $alias; + } + + } + + return $namespaces; + } + + /** + * Get the driver/connection/store from the managers + * + * @param $alias + * @return array|bool|string + */ + public function getDriver($alias) + { + try { + if ($alias == 'Auth') { + /** @noinspection PhpUndefinedClassInspection */ + $driver = \Auth::driver(); + } elseif ($alias == 'DB') { + /** @noinspection PhpUndefinedClassInspection */ + $driver = \DB::connection(); + } elseif ($alias == 'Cache') { + /** @noinspection PhpUndefinedClassInspection */ + $driver = get_class(\Cache::driver()); + /** @noinspection PhpUndefinedClassInspection */ + $store = get_class(\Cache::getStore()); + return array($driver, $store); + } elseif ($alias == 'Queue') { + /** @noinspection PhpUndefinedClassInspection */ + $driver = \Queue::connection(); + } else { + return false; + } + + return get_class($driver); + } catch (\Exception $e) { + $this->error("Could not determine driver/connection for $alias."); + return false; + } + } + + /** + * Write a string as error output. + * + * @param string $string + * @return void + */ + protected function error($string) + { + if ($this->output) { + $this->output->writeln("$string"); + } else { + echo $string . "\r\n"; + } + } +} diff --git a/src/IdeHelperServiceProvider.php b/src/IdeHelperServiceProvider.php index ceace1e..7d70d5d 100644 --- a/src/IdeHelperServiceProvider.php +++ b/src/IdeHelperServiceProvider.php @@ -15,20 +15,19 @@ use Barryvdh\LaravelIdeHelper\Console\MetaCommand; use Barryvdh\LaravelIdeHelper\Console\ModelsCommand; use Barryvdh\LaravelIdeHelper\Console\GeneratorCommand; +/** + * @property \Illuminate\Container\Container $app + */ class IdeHelperServiceProvider extends ServiceProvider { /** - * Indicates if loading of the provider is deferred. - * - * @var bool + * {@inheritdoc} */ protected $defer = true; /** - * Bootstrap the application events. - * - * @return void + * {@inheritdoc} */ public function boot() { @@ -36,9 +35,7 @@ class IdeHelperServiceProvider extends ServiceProvider } /** - * Register the service provider. - * - * @return void + * {@inheritdoc} */ public function register() { @@ -49,60 +46,34 @@ class IdeHelperServiceProvider extends ServiceProvider ); $this->app['command.ide-helper.models'] = $this->app->share( - function () { - return new ModelsCommand(); + function ($app) { + return new ModelsCommand($app); } ); - + $this->app['command.ide-helper.meta'] = $this->app->share( - function ($app) { - return new MetaCommand($app['files'], $app['view']); - } + function ($app) { + return new MetaCommand($app); + } ); $this->commands('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta'); } /** - * Get the services provided by the provider. - * - * @return array + * {@inheritdoc} */ public function provides() { - return array('command.ide-helper.generate', 'command.ide-helper.models'); + return array('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta'); } - + /** - * Register the package's component namespaces. - * - * @param string $package - * @param string $namespace - * @param string $path - * @return void + * {@inheritdoc} */ - public function package($package, $namespace = null, $path = null) + protected function getAppViewPath($package, $namespace = null) { - - // Is it possible to register the config? - if (method_exists($this->app['config'], 'package')) { - $this->app['config']->package($package, $path.'/config', $namespace); - } else { - // Load the config for now.. - $config = $this->app['files']->getRequire($path .'/config/config.php'); - foreach($config as $key => $value){ - $this->app['config']->set($namespace.'::'.$key, $value); - } - } - - // Register view files - $appView = $this->app['path']."/views/packages/{$package}"; - if ($this->app['files']->isDirectory($appView)) - { - $this->app['view']->addNamespace($namespace, $appView); - } - - $this->app['view']->addNamespace($namespace, $path.'/views'); + return $this->app['path'] . "/views/packages/{$package}"; } } diff --git a/src/Method.php b/src/Method.php index be343e2..4b65ba6 100644 --- a/src/Method.php +++ b/src/Method.php @@ -1,311 +1,332 @@ - - * @copyright 2014 Barry vd. Heuvel / 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; - -use Barryvdh\Reflection\DocBlock; -use Barryvdh\Reflection\DocBlock\Context; -use Barryvdh\Reflection\DocBlock\Tag; -use Barryvdh\Reflection\DocBlock\Tag\ReturnTag; -use Barryvdh\Reflection\DocBlock\Tag\ParamTag; -use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; - -class Method -{ - /** @var \Barryvdh\Reflection\DocBlock */ - protected $phpdoc; - - /** @var \ReflectionMethod */ - protected $method; - - protected $output = ''; - protected $name; - protected $namespace; - protected $params = array(); - protected $params_with_default = array(); - protected $interfaces = array(); - protected $return = null; - - /** - * @param \ReflectionMethod $method - * @param string $alias - * @param string $class - * @param string|null $methodName - * @param array $interfaces - */ - public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array()) - { - $this->method = $method; - $this->interfaces = $interfaces; - $this->name = $methodName ?: $method->name; - $this->namespace = $method->getDeclaringClass()->getNamespaceName(); - - //Create a DocBlock and serializer instance - $this->phpdoc = new DocBlock($method, new Context($this->namespace)); - - //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 - $declaringClass = $method->getDeclaringClass(); - $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\'); - $this->root = '\\' . ltrim($class->getName(), '\\'); - } - - /** - * Get the class wherein the function resides - * - * @return string - */ - public function getDeclaringClass() - { - return $this->declaringClassName; - } - - /** - * Return the class from which this function would be called - * - * @return string - */ - public function getRoot() - { - return $this->root; - } - - /** - * Get the docblock for this method - * - * @param string $prefix - * @return mixed - */ - public function getDocComment($prefix = "\t\t") - { - $serializer = new DocBlockSerializer(1, $prefix); - return $serializer->getDocComment($this->phpdoc); - } - - /** - * Get the method name - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Get the parameters for this method - * - * @param bool $implode Wether to implode the array or not - * @return string - */ - public function getParams($implode = true) - { - return $implode ? implode(', ', $this->params) : $this->params; - } - - /** - * Get the parameters for this method including default values - * - * @param bool $implode Wether to implode the array or not - * @return string - */ - public function getParamsWithDefault($implode = true) - { - return $implode ? implode(', ', $this->params_with_default) : $this->params_with_default; - } - - /** - * Get the description and get the inherited docs. - * - * @param DocBlock $phpdoc - */ - protected function normalizeDescription(DocBlock $phpdoc) - { - //Get the short + long description from the DocBlock - $description = $phpdoc->getText(); - - //Loop through parents/interfaces, to fill in {@inheritdoc} - if (strpos($description, '{@inheritdoc}') !== false) { - $inheritdoc = $this->getInheritDoc($this->method); - $inheritDescription = $inheritdoc->getText(); - - $description = str_replace('{@inheritdoc}', $inheritDescription, $description); - $phpdoc->setText($description); - - $this->normalizeParams($inheritdoc); - $this->normalizeReturn($inheritdoc); - - //Add the tags that are inherited - $inheritTags = $inheritdoc->getTags(); - if ($inheritTags) { - /** @var Tag $tag */ - foreach ($inheritTags as $tag) { - $tag->setDocBlock(); - $phpdoc->appendTag($tag); - } - } - } - } - - /** - * Normalize the parameters - * - * @param DocBlock $phpdoc - */ - protected function normalizeParams(DocBlock $phpdoc) - { - //Get the return type and adjust them for beter autocomplete - $paramTags = $phpdoc->getTagsByName('param'); - if ($paramTags) { - /** @var ParamTag $tag */ - foreach($paramTags as $tag){ - // Convert the keywords - $content = $this->convertKeywords($tag->getContent()); - $tag->setContent($content); - - // Get the expanded type and re-set the content - $content = $tag->getType() . ' ' . $tag->getVariableName() . ' ' . $tag->getDescription(); - $tag->setContent(trim($content)); - } - } - } - - /** - * Normalize the return tag (make full namespace, replace interfaces) - * - * @param DocBlock $phpdoc - */ - protected function normalizeReturn(DocBlock $phpdoc) - { - //Get the return type and adjust them for beter autocomplete - $returnTags = $phpdoc->getTagsByName('return'); - if ($returnTags) { - /** @var ReturnTag $tag */ - $tag = reset($returnTags); - // Get the expanded type - $returnValue = $tag->getType(); - - // Replace the interfaces - foreach($this->interfaces as $interface => $real){ - $returnValue = str_replace($interface, $real, $returnValue); - } - - // Set the changed content - $tag->setContent($returnValue . ' ' . $tag->getDescription()); - $this->return = $returnValue; - }else{ - $this->return = null; - } - } - - /** - * Convert keywwords that are incorrect. - * - * @param string $string - * @return string - */ - protected function convertKeywords($string) - { - $string = str_replace('\Closure', 'Closure', $string); - $string = str_replace('Closure', '\Closure', $string); - $string = str_replace('dynamic', 'mixed', $string); - - return $string; - } - - /** - * Should the function return a value? - * - * @return bool - */ - public function shouldReturn() - { - if($this->return !== "void" && $this->method->name !== "__construct"){ - return true; - } - - return false; - } - - /** - * Get the parameters and format them correctly - * - * @param $method - * @return array - */ - public function getParameters($method) - { - //Loop through the default values for paremeters, and make the correct output string - $params = array(); - $paramsWithDefault = array(); - foreach ($method->getParameters() as $param) { - $paramStr = '$' . $param->getName(); - $params[] = $paramStr; - if ($param->isOptional()) { - $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; - if (is_bool($default)) { - $default = $default ? 'true' : 'false'; - } elseif (is_array($default)) { - $default = 'array()'; - } elseif (is_null($default)) { - $default = 'null'; - } elseif (is_int($default)) { - //$default = $default; - } else { - $default = "'" . trim($default) . "'"; - } - $paramStr .= " = $default"; - } - $paramsWithDefault[] = $paramStr; - } - - $this->params = $params; - $this->params_with_default = $paramsWithDefault; - } - - /** - * @param \ReflectionMethod $reflectionMethod - * @return DocBlock - */ - protected function getInheritDoc($reflectionMethod) - { - $parentClass = $reflectionMethod->getDeclaringClass()->getParentClass(); - - //Get either a parent or the interface - if ($parentClass) { - $method = $parentClass->getMethod($reflectionMethod->getName()); - } else { - $method = $reflectionMethod->getPrototype(); - } - if ($method) { - $namespace = $method->getDeclaringClass()->getNamespaceName(); - $phpdoc = new DocBlock($method, new Context($namespace)); - - if (strpos($phpdoc->getText(), '{@inheritdoc}') !== false) { - //Not at the end yet, try another parent/interface.. - return $this->getInheritDoc($method); - } else { - return $phpdoc; - } - } - } -} + + * @copyright 2014 Barry vd. Heuvel / 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; + +use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\DocBlock\Context; +use phpDocumentor\Reflection\DocBlock\Tag; +use phpDocumentor\Reflection\DocBlock\Tag\ReturnTag; + +class Method +{ + /** @var \phpDocumentor\Reflection\DocBlock */ + protected $phpdoc; + + /** @var \ReflectionMethod */ + protected $method; + + protected $name; + protected $namespace; + protected $params = array(); + protected $params_with_default = array(); + protected $interfaces = array(); + protected $return = null; + + /** + * @param \ReflectionMethod $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()) + { + $this->method = $method; + $this->interfaces = $interfaces; + $this->name = $methodName ?: $method->name; + $declaringClass = $method->getDeclaringClass(); + $this->namespace = $declaringClass->getNamespaceName(); + + //Create a DocBlock and serializer instance + $this->phpdoc = new DocBlock($method, new Context($this->namespace, static::getUseStatements($declaringClass))); + + //Normalize the description and inherit the docs from parents/interfaces + try { + $this->normalizeReturnTags($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 + $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\'); + $this->root = '\\' . ltrim($class->getName(), '\\'); + } + + /** + * Get the class wherein the function resides + * + * @return string + */ + public function getDeclaringClass() + { + return $this->declaringClassName; + } + + /** + * Return the class from which this function would be called + * + * @return string + */ + public function getRoot() + { + return $this->root; + } + + /** + * Get the docblock for this method + * + * @param string $prefix + * @param bool $trim + * @return string + */ + public function getDocComment($prefix = "\t\t", $trim = false) + { + $serializer = new DocBlock\Serializer(1, $prefix); + $str = $serializer->getDocComment($this->phpdoc); + if ($trim) { + $str = preg_replace(array('/\s+$/m', '#^(\s*/\*\*[\r\n])(?:\s*\*[\r\n])+#u', '#(?:[\r\n]\s*\*)+([\r\n]\s*\*/)$#u'), array('', '$1', '$1'), $str); + } + return $str; + } + + /** + * Get the method name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Checks whether the method is deprecated + * + * @return bool + */ + public function isDeprecated() + { + return $this->phpdoc->hasTag('deprecated'); + } + + /** + * Get the declared parameters for this method + * + * @return array + */ + public function getDocParams() + { + return $this->phpdoc->getTagsByName('param'); + } + + /** + * Get the parameters for this method + * + * @param bool $implode Whether to implode the array or not + * @return string|array + */ + public function getParams($implode = true) + { + return $implode ? implode(', ', $this->params) : $this->params; + } + + /** + * Get the parameters for this method including default values + * + * @param bool $implode Whether to implode the array or not + * @return string|array + */ + public function getParamsWithDefault($implode = true) + { + return $implode ? implode(', ', $this->params_with_default) : $this->params_with_default; + } + + /** + * Get the description and get the inherited docs. + * + * @param DocBlock $phpdoc + */ + protected function normalizeDescription(DocBlock $phpdoc) + { + //Get the short + long description from the DocBlock + $description = $phpdoc->getText(); + + //Loop through parents/interfaces, to fill in {@inheritdoc} + if (stripos($description, '{@inheritdoc}') !== false && ($inheritdoc = $this->getInheritDoc($this->method))) { + $inheritDescription = $inheritdoc->getText(); + + $description = str_ireplace('{@inheritdoc}', $inheritDescription, $description); + $phpdoc->setText($description); + + $this->normalizeReturnTags($inheritdoc); + + //Add the tags that are inherited + foreach ($inheritdoc->getTags() as $tag) { + $tag->setDocBlock(); + $phpdoc->appendTag($tag); + } + } + } + + /** + * Normalize the return tag (make full namespace, replace interfaces) + * + * @param DocBlock $phpdoc + */ + protected function normalizeReturnTags(DocBlock $phpdoc) + { + static $typeProp; + if (!isset($typeProp)) { + $typeProp = new \ReflectionProperty('phpDocumentor\Reflection\DocBlock\Tag\ReturnTag', 'type'); + $typeProp->setAccessible(true); + } + + $this->return = null; + //Get the return type and adjust them for better autocomplete + foreach ($phpdoc->getTags() as $tag) { + if ($tag instanceof ReturnTag) { + // Convert the keywords + $typeValue = static::convertKeywords($typeProp->getValue($tag)); + $typeProp->setValue($tag, $typeValue); + + // Get the expanded type + $typeValue = $tag->getType(); + + // Replace the interfaces + if (preg_match('/\bReturnTag$/', get_class($tag))) { + foreach ($this->interfaces as $interface => $real) { + $typeValue = preg_replace('/(^|\|)' . preg_quote($interface, '/') . '\b/', $real, $typeValue); + } + $this->return = $typeValue; + } + + // Re-set the type + $typeProp->setValue($tag, $typeValue); + $tag->setDescription($tag->getDescription()); + } + } + } + + /** + * Convert keywords that are incorrect. + * + * @param string $string + * @return string + */ + protected static function convertKeywords($string) + { + $types = explode('|', $string); + foreach ($types as &$type) { + if ($type === 'Closure') + $type = '\Closure'; + elseif ($type === 'dynamic') + $type = 'mixed'; + elseif (strrpos($type, '\\') && $type[0] !== '\\' && (class_exists($type) || interface_exists($type))) + $type = '\\' . $type; + } + return implode('|', $types); + } + + /** + * Should the function return a value? + * + * @return bool|int + */ + public function shouldReturn() + { + if ($this->return !== 'void' && $this->method->name !== '__construct') { + return isset($this->return) ? true : 1; + } + + return false; + } + + /** + * Get the parameters and format them correctly + * + * @param \ReflectionMethod $method + * @return void + */ + public function getParameters($method) + { + //Loop through the default values for parameters, and make the correct output string + $params = array(); + $paramsWithDefault = array(); + + foreach ($method->getParameters() as $param) { + $paramStr = '$' . $param->getName(); + $params[] = $paramStr; + + if ($param->isOptional()) { + $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; + if (is_bool($default)) { + $default = $default ? 'true' : 'false'; + } elseif (is_array($default)) { + $default = 'array()'; + } elseif (is_null($default)) { + $default = 'null'; + } elseif (is_int($default)) { + //$default = $default; + } else { + $default = "'" . trim($default) . "'"; + } + $paramStr .= " = $default"; + } + + $paramsWithDefault[] = $paramStr; + } + + $this->params = $params; + $this->params_with_default = $paramsWithDefault; + } + + /** + * @param \ReflectionMethod $reflectionMethod + * @return DocBlock|null + */ + protected function getInheritDoc($reflectionMethod) + { + $parentClass = $reflectionMethod->getDeclaringClass()->getParentClass(); + + //Get either a parent or the interface + if ($parentClass) { + $method = $parentClass->getMethod($reflectionMethod->getName()); + } else { + $method = $reflectionMethod->getPrototype(); + } + if ($method) { + $namespace = $method->getDeclaringClass()->getNamespaceName(); + $phpdoc = new DocBlock($method, new Context($namespace, static::getUseStatements($method->getDeclaringClass()))); + + if (stripos($phpdoc->getText(), '{@inheritdoc}') !== false) { + //Not at the end yet, try another parent/interface.. + return $this->getInheritDoc($method); + } else { + return $phpdoc; + } + } + return null; + } + + protected static function getUseStatements(\ReflectionClass $class) + { + try { + return PhpReflection::getUseStatements($class); + } catch (\Exception $e) { + return array(); + } + } +} diff --git a/src/PhpReflection.php b/src/PhpReflection.php new file mode 100644 index 0000000..053f6a8 --- /dev/null +++ b/src/PhpReflection.php @@ -0,0 +1,166 @@ +getName(); + } elseif ($name[0] === '\\') { // fully qualified name + return ltrim($name, '\\'); + } + + $uses = self::getUseStatements($rc); + $parts = explode('\\', $name, 2); + if (isset($uses[$parts[0]])) { + $parts[0] = $uses[$parts[0]]; + return implode('\\', $parts); + } elseif ($rc->inNamespace()) { + return $rc->getNamespaceName() . '\\' . $name; + } else { + return $name; + } + } + + /** + * @param \ReflectionClass + * @return array of [alias => class] + */ + public static function getUseStatements(\ReflectionClass $class) + { + static $cache = array(); + if (!isset($cache[$name = $class->getName()])) { + if ($class->isInternal() || !($code = @file_get_contents($class->getFileName()))) { + $cache[$name] = array(); + } else { + $cache = self::parseUseStatements($code, $name) + $cache; + } + } + return $cache[$name]; + } + + /** + * @param string + * @return bool + */ + public static function isBuiltinType($type) + { + return in_array(strtolower($type), array('string', 'int', 'float', 'bool', 'array', 'callable'), true); + } + + /** + * Parses PHP code. + * + * @param string $code + * @param string $forClass + * @return array of [class => [alias => class, ...]] + */ + public static function parseUseStatements($code, $forClass = null) + { + $tokens = token_get_all($code); + $namespace = $class = $classLevel = $level = null; + $res = $uses = array(); + + while ($token = current($tokens)) { + next($tokens); + switch (is_array($token) ? $token[0] : $token) { + case T_NAMESPACE: + $namespace = ltrim(self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)) . '\\', '\\'); + $uses = array(); + break; + + case T_CLASS: + case T_INTERFACE: + case PHP_VERSION_ID < 50400 ? -1 : T_TRAIT: + if ($name = self::fetch($tokens, T_STRING)) { + $class = $namespace . $name; + $classLevel = $level + 1; + $res[$class] = $uses; + if ($class === $forClass) { + return $res; + } + } + break; + + case T_USE: + while (!$class && ($name = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)))) { + $name = ltrim($name, '\\'); + if (self::fetch($tokens, '{')) { + while ($suffix = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR))) { + if (self::fetch($tokens, T_AS)) { + $uses[self::fetch($tokens, T_STRING)] = $name . $suffix; + } else { + $tmp = explode('\\', $suffix); + $uses[end($tmp)] = $name . $suffix; + } + if (!self::fetch($tokens, ',')) { + break; + } + } + + } elseif (self::fetch($tokens, T_AS)) { + $uses[self::fetch($tokens, T_STRING)] = $name; + + } else { + $tmp = explode('\\', $name); + $uses[end($tmp)] = $name; + } + if (!self::fetch($tokens, ',')) { + break; + } + } + break; + + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': + $level++; + break; + + case '}': + if ($level === $classLevel) { + $class = $classLevel = null; + } + $level--; + } + } + + return $res; + } + + private static function fetch(&$tokens, $take) + { + $res = null; + while ($token = current($tokens)) { + list($token, $s) = is_array($token) ? $token : array($token, $token); + if (in_array($token, (array)$take, true)) { + $res .= $s; + } elseif (!in_array($token, array(T_DOC_COMMENT, T_WHITESPACE, T_COMMENT), true)) { + break; + } + next($tokens); + } + return $res; + } +} diff --git a/src/views/ide-helper.php b/src/views/ide-helper.php index 473dc71..0f2679b 100644 --- a/src/views/ide-helper.php +++ b/src/views/ide-helper.php @@ -1,39 +1,46 @@ - - -/** - * An helper file for Laravel 4, to provide autocomplete information to your IDE - * Generated for Laravel on . - * - * @author Barry vd. Heuvel - * @see https://github.com/barryvdh/laravel-ide-helper - */ - - $aliases): ?> -namespace { - - exit("This file should not be included, only analyzed by your IDE"); - - - - - getClassType() ?> getShortName() ?> getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{ - getMethods() as $method): ?> - - getDocComment(' ')) ?> - - public static function getName() ?>(getParamsWithDefault() ?>){getDeclaringClass() !== $method->getRoot()): ?> - - //Method inherited from getDeclaringClass() ?> - - - shouldReturn() ? 'return ': '' ?>getRoot() ?>::getName() ?>(getParams() ?>); - } - - - } - - - -} - - + + +/** + * An helper file for Laravel 4, to provide autocomplete information to your IDE + * Generated for Laravel on . + * + * @author Barry vd. Heuvel + * @see https://github.com/barryvdh/laravel-ide-helper + */ + + $aliases/* @var \Barryvdh\LaravelIdeHelper\Alias[] $aliases */): ?> +namespace { + + exit('This file should not be included, only analyzed by your IDE'); + + + + +getExtends())) != $alias->getExtends() && $cBase != $alias->getShortName()): ?> + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + + getClassType() ?> getShortName() ?> getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{ +getMethods() as $method): ?> + +getDocParams())) > count($mParams = $method->getParamsWithDefault(false))): ?> + /** @noinspection PhpDocSignatureInspection */ + +getDocComment("\t\t", true)))): ?> + + + + public static function getName() ?>(getParamsWithDefault() ?>){ +getDeclaringClass() !== $method->getRoot()): ?> + //Method inherited from getDeclaringClass() ?> + + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection,PhpDynamicAsStaticMethodCallInspectionshouldReturn() === 1 ? ',PhpVoidFunctionResultUsedInspection' : '') . ($method->isDeprecated() ? ',PhpDeprecationInspection' : '') ?> */ + shouldReturn() ? 'return ' : '' ?>getRoot() ?>::getName() ?>(getParams() ?>); + } + + + } + + +} + diff --git a/src/views/meta.php b/src/views/meta.php index c51754a..837617a 100644 --- a/src/views/meta.php +++ b/src/views/meta.php @@ -1,22 +1,22 @@ namespace PHPSTORM_META { - /** - * PhpStorm Meta file, to provide autocomplete information for PhpStorm - * Generated on . - * - * @author Barry vd. Heuvel - * @see https://github.com/barryvdh/laravel-ide-helper - */ + /** + * PhpStorm Meta file, to provide autocomplete information for PhpStorm + * Generated on . + * + * @author Barry vd. Heuvel + * @see https://github.com/barryvdh/laravel-ide-helper + */ - /** @noinspection PhpIllegalArrayKeyTypeInspection */ - /** @noinspection PhpUnusedLocalVariableInspection */ - /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ - $STATIC_METHOD_TYPES = array( - - ('') => array( - $class): ?> - '' instanceof \, - ), + /** @noinspection PhpIllegalArrayKeyTypeInspection,PhpUnusedLocalVariableInspection,PhpUnnecessaryFullyQualifiedNameInspection */ + $STATIC_METHOD_TYPES = array( + + => array( + $class): ?> + instanceof \, - ); + ), + + ); + } diff --git a/tests/MethodTest.php b/tests/MethodTest.php new file mode 100644 index 0000000..c8b64bc --- /dev/null +++ b/tests/MethodTest.php @@ -0,0 +1,38 @@ +assertSame('\PHPUnit_Framework_TestCase', $object->getDeclaringClass()); + $this->assertSame('\\' . get_class($this), $object->getRoot()); + $this->assertSame('getMock', $object->getName()); + + $prop = new \ReflectionProperty(get_class($object), 'namespace'); + $prop->setAccessible(true); + $this->assertSame('', $prop->getValue($object)); + + $this->assertFalse($object->isDeprecated()); + $this->assertCount($method->getNumberOfParameters(), $object->getDocParams()); + + $doc = $object->getDocComment('', true); + $this->assertContains("\n * " . '@param array|null $methods', $doc); + $this->assertContains("\n * " . '@return \PHPUnit_Framework_MockObject_MockObject', $doc); + $this->assertContains("\n * " . '@throws \PHPUnit_Framework_Exception', $doc); + + $this->assertTrue($object->shouldReturn()); + } + +} diff --git a/tests/ServiceProviderTest.php b/tests/ServiceProviderTest.php new file mode 100644 index 0000000..ae72be0 --- /dev/null +++ b/tests/ServiceProviderTest.php @@ -0,0 +1,83 @@ +getMock('Illuminate\Container\Container', array('make', 'bind')); + + $fs = $testCase->getMock('Illuminate\Filesystem\Filesystem', null); + $config = $testCase->getMock('Illuminate\Config\Repository', array('get', 'set', 'package'), array(), '', false); + $events = $testCase->getMock('Illuminate\Events\Dispatcher', array('listen'), array($app)); + $view = $testCase->getMock('Illuminate\View\Factory', array('addNamespace'), array(), '', false); + + $app->expects($testCase->any())->method('make')->willReturnMap(array( + array('files', array(), $fs), + array('config', array(), $config), + array('events', array(), $events), + array('view', array(), $view), + array('path', array(), __DIR__), + )); + + return $app; + } + + /** + * {@inheritdoc} + */ + protected function setUp() + { + $this->app = static::makeAppMock($this); + /** @noinspection PhpParamsInspection */ + $this->provider = new IdeHelperServiceProvider($this->app); + } + + public function testDeferred() + { + $this->assertTrue($this->provider->isDeferred()); + } + + public function testProvides() + { + $this->assertEquals(array('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta'), $this->provider->provides()); + } + + public function testRegister() + { + $this->app->expects($this->exactly(3))->method('bind')->withConsecutive( + array('command.ide-helper.generate', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()), + array('command.ide-helper.models', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()), + array('command.ide-helper.meta', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()) + ); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\Events\Dispatcher $events */ + $events = $this->app['events']; + $events->expects($this->once())->method('listen')->with('artisan.start', $this->callback(function ($listener) { + $params = print_r(array('commands' => array('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta')), true); + return strpos(preg_replace('/^\s+/mu', '', print_r($listener, true)), preg_replace('/^\s+/mu', '', $params)); + }), 0); + + $this->provider->register(); + } + + public function testBoot() + { + $path = realpath(__DIR__ . '/../src'); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\Config\Repository $config */ + $config = $this->app['config']; + $config->expects($this->once())->method('package')->with('barryvdh/laravel-ide-helper', $path . '/config', 'laravel-ide-helper'); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\View\Factory $view */ + $view = $this->app['view']; + $view->expects($this->once())->method('addNamespace')->with('laravel-ide-helper', $path . '/views'); + + $this->provider->boot(); + } + +}