Compare commits

..
1 Commits
Author SHA1 Message Date
Barry vd. Heuvel eda37f3442 Catch PDO errors when getting drivers/connections 2013-07-12 14:39:12 +02:00
16 changed files with 1013 additions and 2157 deletions
+9 -19
View File
@@ -1,7 +1,7 @@
{
"name": "barryvdh/laravel-ide-helper",
"description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.",
"keywords": ["laravel", "autocomplete", "ide", "helper", "phpstorm", "netbeans", "sublime", "codeintel", "phpdoc"],
"keywords": ["laravel", "autocomplete", "phpstorm", "netbeans", "sublime", "codeintel", "phpdoc"],
"license": "MIT",
"authors": [
{
@@ -10,27 +10,17 @@
}
],
"require": {
"php": ">=5.4.0",
"illuminate/support": "5.0.x|5.1.x|5.2.x",
"illuminate/console": "5.0.x|5.1.x|5.2.x",
"illuminate/filesystem": "5.0.x|5.1.x|5.2.x",
"phpdocumentor/reflection-docblock": "2.0.4",
"php": ">=5.3.0",
"illuminate/support": "4.x",
"illuminate/console": "4.x",
"illuminate/filesystem": "4.x",
"barryvdh/reflection-docblock": ">=2.0.1",
"symfony/class-loader": "~2.3"
},
"require-dev": {
"doctrine/dbal": "~2.3"
},
"suggest": {
"doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)"
},
"autoload": {
"psr-4": {
"Barryvdh\\LaravelIdeHelper\\": "src"
"psr-0": {
"Barryvdh\\LaravelIdeHelper": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
}
"minimum-stability": "dev"
}
-119
View File
@@ -1,119 +0,0 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Filename & Format
|--------------------------------------------------------------------------
|
| The default filename (without extension) and the format (php or json)
|
*/
'filename' => '_ide_helper',
'format' => 'php',
/*
|--------------------------------------------------------------------------
| Helper files to include
|--------------------------------------------------------------------------
|
| Include helper files. By default not included, but can be toggled with the
| -- helpers (-H) option. Extra helper files can be included.
|
*/
'include_helpers' => false,
'helper_files' => array(
base_path().'/vendor/laravel/framework/src/Illuminate/Support/helpers.php',
),
/*
|--------------------------------------------------------------------------
| Model locations to include
|--------------------------------------------------------------------------
|
| Define in which directories the ide-helper:models command should look
| for models.
|
*/
'model_locations' => array(
'app',
),
/*
|--------------------------------------------------------------------------
| Extra classes
|--------------------------------------------------------------------------
|
| These implementations are not really extended, but called with magic functions
|
*/
'extra' => array(
'Eloquent' => array('Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'),
'Session' => array('Illuminate\Session\Store'),
),
'magic' => array(
'Log' => array(
'debug' => 'Monolog\Logger::addDebug',
'info' => 'Monolog\Logger::addInfo',
'notice' => 'Monolog\Logger::addNotice',
'warning' => 'Monolog\Logger::addWarning',
'error' => 'Monolog\Logger::addError',
'critical' => 'Monolog\Logger::addCritical',
'alert' => 'Monolog\Logger::addAlert',
'emergency' => 'Monolog\Logger::addEmergency',
)
),
/*
|--------------------------------------------------------------------------
| Interface implementations
|--------------------------------------------------------------------------
|
| These interfaces will be replaced with the implementing class. Some interfaces
| are detected by the helpers, others can be listed below.
|
*/
'interfaces' => array(
),
/*
|--------------------------------------------------------------------------
| Support for custom DB types
|--------------------------------------------------------------------------
|
| This setting allow you to map any custom database type (that you may have
| created using CREATE TYPE statement or imported using database plugin
| / extension to a Doctrine type.
|
| Each key in this array is a name of the Doctrine2 DBAL Platform. Currently valid names are:
| 'postgresql', 'db2', 'drizzle', 'mysql', 'oracle', 'sqlanywhere', 'sqlite', 'mssql'
|
| This name is returned by getName() method of the specific Doctrine/DBAL/Platforms/AbstractPlatform descendant
|
| The value of the array is an array of type mappings. Key is the name of the custom type,
| (for example, "jsonb" from Postgres 9.4) and the value is the name of the corresponding Doctrine2 type (in
| our case it is 'json_array'. Doctrine types are listed here:
| http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html
|
| So to support jsonb in your models when working with Postgres, just add the following entry to the array below:
|
| "postgresql" => array(
| "jsonb" => "json_array",
| ),
|
*/
'custom_db_types' => array(
),
);
+49 -121
View File
@@ -1,155 +1,83 @@
## Laravel 5 IDE Helper Generator
## Laravel IDE Helper Generator
[![Latest Stable Version](https://poser.pugx.org/barryvdh/laravel-ide-helper/version.png)](https://packagist.org/packages/barryvdh/laravel-ide-helper) [![Total Downloads](https://poser.pugx.org/barryvdh/laravel-ide-helper/d/total.png)](https://packagist.org/packages/barryvdh/laravel-ide-helper)
__For Laravel 4.x, check [version 1.11](https://github.com/barryvdh/laravel-ide-helper/tree/1.11)__
### Complete phpDocs, directly from the source
_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.
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)
* [`php artisan ide-helper:generate` - phpDoc generation for Laravel Facades ](#automatic-phpdoc-generation-for-laravel-facades)
* [`php artisan ide-helper:models` - phpDocs for models](#automatic-phpdocs-for-models)
* [`php artisan ide-helper:meta` - PhpStorm Meta file](#phpstorm-meta-for-container-instances)
This package generates a file that your IDE understands, 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 for L5: https://gist.github.com/barryvdh/5227822
* Generated version for Lumen: https://gist.github.com/barryvdh/be17164b0ad51f832f20
* Generated Phpstorm Meta file: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67
* Generated version: https://gist.github.com/barryvdh/5227822
Note: You do need CodeIntel for Sublime Text: https://github.com/SublimeCodeIntel/SublimeCodeIntel
### Install
Require this package with composer using the following command:
```bash
composer require barryvdh/laravel-ide-helper
```
After updating composer, add the service provider to the `providers` array in `config/app.php`
```php
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
```
### Automatic phpDoc generation for Laravel Facades
Require this package in your composer.json and run composer update (or run `composer require barryvdh/laravel-ide-helper:1.*` directly):
You can now re-generate the docs yourself (for future updates)
"barryvdh/laravel-ide-helper": "1.*"
```bash
php artisan ide-helper:generate
```
After updating composer, add the ServiceProvider to the providers array in app/config/app.php
Note: `bootstrap/compiled.php` has to be cleared first, so run `php artisan clear-compiled` before generating (and `php artisan optimize` after).
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
You can now re-generate the docs yourself (for future updates) in artisan
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:
```js
"scripts":{
"post-update-cmd": [
"php artisan clear-compiled",
"php artisan ide-helper:generate",
"php artisan optimize"
]
},
```
"scripts":{
"post-update-cmd":[
"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`.
You can also publish the config-file to change implementations (ie. interface to specific class) or set defaults for --helpers or --sublime.
```bash
php artisan vendor:publish --provider="Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider" --tag=config
```
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.
Some classes need a working database connection. If you do not have a default working connection, some facades will not be included.
You can use an in-memory SQLite driver, using the -M option.
Some classes need a working database connection. If you do not have a working default connection, some facades will not be included.
You can use a in-memory sqlite driver, using the -M option.
You can choose to include helper files. This is not enabled by default, but you can override it with the `--helpers (-H)` option.
The `Illuminate/Support/helpers.php` is already set-up, but you can add/remove your own files in the config file.
### Automatic phpDocs for models
> You need to require `doctrine/dbal: ~2.3` in your own composer.json to get database columns.
You can choose to include helper files. This is not enabled by default, but you can override this with the --helpers (-H) option.
The Illuminate/Support/helpers.php is already set-up, but you can add/remove your own files in the config file.
```bash
composer require doctrine/dbal
```
### Automatic phpDocs for Models
If you don't want to write your properties yourself, you can use the command `php artisan ide-helper:models` to generate
phpDocs, based on table columns, relations and getters/setters. You can write the comments directly to your Model file, using the `--write (-W)` option. By default, you are asked to overwrite or write to a separate file (`_ide_helper_models.php`). You can force No with `--nowrite (-N)`.
Please make sure to backup your models, before writing the info.
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. Still in beta, so please provide feedback if you want.
Docs are written to a phpfile (_ide_helper_models.php) in the root of the project, so you can move the docs to the real model.
You can now also write the comments directly to your Model file, using the `--write (-W)` option. 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, and only the newly found columns/relations are saved as phpdocs.
With the `--reset (-R)` option, the existing phpdocs are ignored, only the newly found columns/relations are saved as phpdocs.
```bash
php artisan ide-helper:models Post
```
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
*/
```
/**
* 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).
For now, only models in app/models are scanned. The optional argument tells what models to use (also outside app/models).
```bash
php artisan ide-helper:models Post User
```
php artisan ide-helper:models Post,User
You can also scan a different directory, using the `--dir` option (relative from the base path):
```bash
php artisan ide-helper:models --dir="path/to/models" --dir="app/src/Model"
```
You can publish the config file (`php artisan vendor:publish`) and set the default directories.
Models can be ignored using the `--ignore (-I)` option
```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`)
## PhpStorm Meta for Container instances
It's possible to generate a PhpStorm meta file, to [add support for factory design pattern](https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata). For Laravel, this means we can make PhpStorm understand what kind of object we are resolving from the IoC Container. For example, `events` will return an `Illuminate\Events\Dispatcher` object, so with the meta file you can call `app('events')` and it will autocomplete the Dispatcher methods.
``` bash
php artisan ide-helper:meta
```
```php
app('events')->fire();
\App::make('events')->fire();
/** @var \Illuminate\Foundation\Application $app */
$app->make('events')->fire();
// When the key is not found, it uses the argument as class name
app('App\SomeClass');
```
Pre-generated example: https://gist.github.com/barryvdh/bb6ffc5d11e0a75dba67
> Note: You might need to restart PhpStorm and make sure `.phpstorm.meta.php` is indexed.
> Note: When you receive a FatalException about a class that is not found, check your config (for example, remove S3 as cloud driver when you don't have S3 configured. Remove Redis ServiceProvider when you don't use it).
Note: With namespaces, uses `\\` instead of `\`: `php artisan ide-helper:models API\\User`
### License
-39
View File
@@ -1,39 +0,0 @@
<?= '<?php' ?>
/**
* A helper file for Laravel 5, to provide autocomplete information to your IDE
* Generated for Laravel <?= $version ?> on <?= date("Y-m-d") ?>.
*
* @author Barry vd. Heuvel <[email protected]>
* @see https://github.com/barryvdh/laravel-ide-helper
*/
<?php foreach($namespaces as $namespace => $aliases): ?>
namespace <?= $namespace == '__root' ? '' : $namespace ?>{
<?php if($namespace == '__root'): ?>
exit("This file should not be included, only analyzed by your IDE");
<?= $helpers ?>
<?php endif; ?>
<?php foreach($aliases as $alias): ?>
<?= $alias->getClassType() ?> <?= $alias->getShortName() ?> <?= $alias->getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{
<?php foreach($alias->getMethods() as $method): ?>
<?= trim($method->getDocComment(' ')) ?>
public static function <?= $method->getName() ?>(<?= $method->getParamsWithDefault() ?>){<?php if($method->getDeclaringClass() !== $method->getRoot()): ?>
//Method inherited from <?= $method->getDeclaringClass() ?>
<?php endif; ?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getName() ?>(<?= $method->getParams() ?>);
}
<?php endforeach; ?>
}
<?php endforeach; ?>
}
<?php endforeach; ?>
-21
View File
@@ -1,21 +0,0 @@
<?= '<?php' ?>
namespace PHPSTORM_META {
/**
* PhpStorm Meta file, to provide autocomplete information for PhpStorm
* Generated on <?= date("Y-m-d") ?>.
*
* @author Barry vd. Heuvel <[email protected]>
* @see https://github.com/barryvdh/laravel-ide-helper
*/
$STATIC_METHOD_TYPES = [
<?php foreach($methods as $method): ?>
<?= $method ?> => [
'' == '@',
<?php foreach($bindings as $abstract => $class): ?>
'<?= $abstract ?>' instanceof \<?= $class ?>,
<?php endforeach ?> ],
<?php endforeach ?>
];
}
-284
View File
@@ -1,284 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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";
}
}
+454
View File
@@ -0,0 +1,454 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @copyright 2013 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\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Foundation\AliasLoader;
use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Context;
use Barryvdh\Reflection\DocBlock\Tag;
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
/**
* A command to generate autocomplete information for your IDE
*
* @author Barry vd. Heuvel <[email protected]>
*/
class GeneratorCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'ide-helper:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate a new IDE Helper file.';
protected $extra;
protected $onlyExtend;
protected $helpers;
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (file_exists($compiled = base_path().'/bootstrap/compiled.php')){
$this->error('Error generating IDE Helper: first delete bootstrap/compiled.php (php artisan clear-compiled)');
}else{
$filename = $this->argument('filename');
if($this->option('memory')){
$this->useMemoryDriver();
}
$this->extra = \Config::get('laravel-ide-helper::extra');
if( $this->option('helpers') || (\Config::get('laravel-ide-helper::include_helpers') )){
$this->helpers = \Config::get('laravel-ide-helper::helper_files');
}else{
$this->helpers = array();
}
$content = $this->generateDocs();
$written = \File::put($filename, $content);
if($written !== false){
$this->info("A new helper file was written to $filename");
}else{
$this->error("The helper file could not be created at $filename");
}
}
}
protected function useMemoryDriver(){
//Use a sqlite database in memory, to avoid connection errors on Database facades
\Config::set('database.connections.sqlite',array(
'driver' => 'sqlite',
'database' => ':memory:',
));
\Config::set('database.default', 'sqlite');
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('filename', InputArgument::OPTIONAL, 'The path to the helper file', \Config::get('laravel-ide-helper::filename')),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
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'),
);
}
/**
* Generate the docs for all facades in the AliasLoader
*
* @return string
*/
protected function generateDocs(){
$aliasLoader = AliasLoader::getInstance();
$output = "<?php
/**
* An helper file for Laravel 4, to provide autocomplete information to your IDE
* Generated with https://github.com/barryvdh/laravel-ide-helper
*
* @author Barry vd. Heuvel <[email protected]>
*/
exit('Only to be used as an helper for your IDE');\n\n";
//Get all aliases
$aliases = $aliasLoader->getAliases();
foreach($aliases as $alias => $facade){
$root = $this->getRoot($facade);
if(!$root){
continue;
}
try{
//Some classes extend the facade
if(class_exists($facade)){
$output .= "class $alias extends $facade{\n";
}else{
$output .= "class $alias{\n";
}
$usedMethods = array();
//Only add the methods to the output when the root is not the same as the facade.
$addOutput = ($root !== $facade);
$output .= $this->getMethods($root, $alias, $usedMethods, $addOutput);
$driver = $this->getDriver($alias);
if($driver){
$output .= $this->getMethods($driver, $alias, $usedMethods);
}
//Add extra methods, from other classes (magic static calls)
if(array_key_exists($alias, $this->extra)){
$output .= $this->getMethods($this->extra[$alias], $alias, $usedMethods);
}
$output .= "}\n\n";
}catch(\Exception $e){
$this->error("Exception: ".$e->getMessage()."\nCould not analyze $root.");
}
}
//Include the helper file, if requested
if(!empty($helpers)){
foreach($helpers as $helper){
if (file_exists($helper)){
$output .= str_replace(array('<?php', '?>'), '', \File::get($helper));
}
}
}
return $output;
}
/**
* Get the real root of a facade
*
* @param $facade
* @return bool|string
*/
protected function getRoot($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)){
$this->error("Class $root is not found.");
return false;
}
return $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.");
return false;
}catch(\Exception $e){
$this->error("Exception: ".$e->getMessage()."\nSkipping $facade.");
return false;
}
}
public function getDriver($alias){
try{
if($alias == "Auth"){
$driver = \Auth::driver();
}elseif($alias == "DB"){
$driver = \DB::connection();
}elseif($alias == "Cache"){
$driver = \Cache::driver();
}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;
}
}
/**
* Get the methods for one or multiple classes.
*
* @param $classes
* @param $alias
* @param $usedMethods
* @param bool $addOutput
* @return string
*/
protected function getMethods($classes, $alias, &$usedMethods, $addOutput = true){
if(!is_array($classes)){
$classes = array($classes);
}
$output = '';
foreach($classes as $class){
if(!class_exists($class) && !interface_exists($class)){
continue;
}
$reflection = new \ReflectionClass($class);
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
if($methods)
{
foreach ($methods as $method)
{
if(!in_array($method->name, $usedMethods)){
if( $addOutput){
$output .= $this->parseMethod($method, $alias, $reflection);
}
$usedMethods[] = $method->name;
}
}
}
}
return $output;
}
/**
* @param \ReflectionMethod $method
* @param string $alias
* @return string
*/
protected function parseMethod($method, $alias, $class){
$output = '';
// Don't add the __clone() functions
if($method->name === '__clone'){
return $output;
}
$namespace = $method->getDeclaringClass()->getNamespaceName();
//Create a DocBlock and serializer instance
$phpdoc = new DocBlock($method, new Context($namespace));
$serializer = new DocBlockSerializer(1, "\t");
//Normalize the description and inherit the docs from parents/interfaces
$this->normalizeDescription($phpdoc, $method);
//Correct the return values
$returnValue = $this->normalizeReturn($phpdoc, $method, $alias);
//Get the parameters, including formatted default values
list($params, $paramsWithDefault) = $this->getParameters($method);
//Make the method static
$phpdoc->appendTag(Tag::createInstance('@static', $phpdoc));
//Write the output, using the DocBlock serializer
$output .= $serializer->getDocComment($phpdoc) ."\n\t public static function ".$method->name."(";
$output .= implode($paramsWithDefault, ", ");
$output .= "){\r\n";
//Only return when not a constructor and not void.
$return = ($returnValue && $returnValue !== "void" && $method->name !== "__construct") ? 'return' : '';
//Reference the 'real' function in the declaringclass
$declaringClass = $method->getDeclaringClass();
$root = $class->getName();
if($declaringClass->name != $root){
$output .= "\t\t//Method inherited from $declaringClass->name\r\n";
}
$output .= "\t\t$return $root::";
//Write the default parameters in the function call
$output .= $method->name."(".implode($params, ", ").");\r\n";
$output .= "\t }\n\n";
return $output;
}
/**
* Get the description and get the inherited docs.
*
* @param $phpdoc
* @param $method
*/
protected function normalizeDescription(&$phpdoc, $method){
//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($method);
$inheritDescription = $inheritdoc->getText();
$description = str_replace('{@inheritdoc}', $inheritDescription, $description);
$phpdoc->setText($description);
//Add the tags that are inherited
$inheritTags = $inheritdoc->getTags();
if($inheritTags){
foreach($inheritTags as $tag){
$tag->setDocBlock();
$phpdoc->appendTag($tag);
}
}
}
}
/**
* Make some changes to the return types, if needed.
*
* @param $phpdoc
* @param $method
* @param $alias
* @return null
*/
protected function normalizeReturn(&$phpdoc, $method, $alias){
//Get the return type and adjust them for beter autocomplete
$returnTags = $phpdoc->getTagsByName('return');
if($returnTags){
/** @var $tag */
$tag = reset($returnTags);
$returnValue = $tag->getType();
if($method->name == "__construct"){
$tag->setType('self');
}elseif($alias == 'Eloquent' and in_array($method->name, array('hasOne', 'hasMany', 'belongsTo', 'belongsToMany', 'morphOne', 'morphTo', 'morphMany'))){
$tag->addType('\Eloquent');
}
}else{
$returnValue = null;
}
return $returnValue;
}
/**
* 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->getDefaultValue();
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;
}
return array($params, $paramsWithDefault);
}
/**
* @param \ReflectionMethod $reflectionMethod
* @return string
*/
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){
$phpdoc = new DocBlock($method);
if(strpos($phpdoc->getText(), '{@inheritdoc}') !== false ){
//Not at the end yet, try another parent/interface..
return $this->getInheritDoc($method);
}else{
return $phpdoc;
}
}
}
}
@@ -0,0 +1,65 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @copyright 2013 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\Support\ServiceProvider;
class IdeHelperServiceProvider extends ServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->package('barryvdh/laravel-ide-helper');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app['command.ide-helper.generate'] = $this->app->share(function($app)
{
return new GeneratorCommand;
});
$this->commands('command.ide-helper.generate');
$this->app['command.ide-helper.models'] = $this->app->share(function($app)
{
return new ModelsCommand();
});
$this->commands('command.ide-helper.models');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('command.ide-helper.generate', 'command.ide-helper.models');
}
}
@@ -0,0 +1,390 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @copyright 2013 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\Console\Command;
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;
/**
* A command to generate autocomplete information for your IDE
*
* @author Barry vd. Heuvel <[email protected]>
*/
class ModelsCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'ide-helper:models';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate autocompletion for models';
protected $properties = array();
protected $methods = array();
protected $write = false;
protected $dir;
protected $reset;
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$filename = $this->option('filename');
$this->write = $this->option('write');
$this->dir = $this->option('dir');
$model = $this->argument('model');
$this->reset = $this->option('reset');
$content = $this->generateDocs($model);
if(!$this->write){
$written = \File::put($filename, $content);
if($written !== false){
$this->info("Model information was written to $filename");
}else{
$this->error("Failed to write model information to $filename");
}
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('model', InputArgument::OPTIONAL, 'Which models to include', '*'),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the helper file', '_ide_helper_models.php'),
array('dir', 'D', InputOption::VALUE_OPTIONAL, 'The model dir','app/models'),
array('write', 'W', InputOption::VALUE_NONE, 'Write to Model file'),
array('reset', 'R', InputOption::VALUE_NONE, 'Remove the original phpdocs instead of appending'),
);
}
protected function generateDocs($model){
$output = "<?php
/**
* An helper file for your Eloquent Models
* Copy the phpDocs from this file to the correct Model,
* And remove them from this file, to prevent double declarations.
*
* @author Barry vd. Heuvel <[email protected]>
*/
\n\n";
if($model === '*'){
$models = $this->loadModels();
}else{
$models = explode(',', $model);
}
foreach($models as $name){
$this->properties = array();
$this->methods = array();
if(class_exists($name)){
try{
$model = new $name();
$this->getPropertiesFromTable($model);
$this->getPropertiesFromMethods($model);
$output .= $this->createPhpDocs($name);
}catch(\Exception $e){
$this->error("Exception: ".$e->getMessage()."\nCould not analyze class $name.");
}
}else{
$this->error("Class $name does not exist");
}
}
return $output;
}
protected function loadModels(){
$dir = base_path().'/'.$this->dir;
$models = array();
if(file_exists($dir)){
foreach(ClassMapGenerator::createMap($dir) as $model=> $path){
$models[] = $model;
}
}
return $models;
}
/**
* Load the properties from the database table.
*
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromTable($model){
$table = $model->getTable();
$schema = $model->getConnection()->getDoctrineSchemaManager($table);
$schema->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
$columns = $schema->listTableColumns($table);
if($columns){
foreach ($columns as $column) {
$name = $column->getName();
$type = $column->getType()->getName();
switch($type){
case 'string':
case 'text':
case 'date':
case 'time':
case 'guid':
$type = 'string';
break;
case 'integer':
case 'bigint':
case 'smallint':
$type = 'integer';
break;
case 'decimal':
case 'float':
$type = 'float';
break;
case 'boolean':
$type = 'boolean';
break;
case 'datetimetz': //String or DateTime, depending on $dates
case 'datetime':
$type = '\Carbon\Carbon';
break;
default:
$type = 'mixed';
break;
}
$this->setProperty($name, $type, true, true);
}
}
}
/**
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromMethods($model){
$methods = get_class_methods($model);
if($methods){
foreach($methods as $method){
if(\Str::startsWith($method, 'get') && \Str::endsWith($method, 'Attribute') && $method !== 'setAttribute'){
//Magic get<name>Attribute
$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'){
//Magic set<name>Attribute
$name = \Str::snake(substr($method, 3, -9));
if(!empty($name)){
$this->setProperty($name, null, null, true);
}
}elseif(\Str::startsWith($method, 'scope') && $method !== 'scopeQuery'){
//Magic set<name>Attribute
$name = \Str::snake(substr($method, 5));
if(!empty($name)){
$this->setMethod($name, 'static');
}
}elseif(!method_exists('Eloquent', $method) && !\Str::startsWith($method, 'get')){
//Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
$reflection = new \ReflectionMethod($model, $method);
$file = new \SplFileObject($reflection->getFileName());
$file->seek($reflection->getStartLine() - 1);
$code = '';
while ($file->key() < $reflection->getEndLine())
{
$code .= $file->current(); $file->next();
}
$begin = strpos($code, 'function(');
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
$begin = stripos($code, 'return $this->');
$parts = explode("'", substr($code, $begin+14),3); //"return $this->" is 14 chars
if (isset($parts[2]))
{
list($relation, $returnModel, $rest) = $parts;
$returnModel = "\\".ltrim($returnModel, "\\");
$relation = trim($relation, ' (');
if($relation === "belongsTo" or $relation === 'hasOne'){
//Single model is returned
$this->setProperty($method, $returnModel, true, null);
}elseif($relation === "belongsToMany" or $relation === 'hasMany'){
//Collection or array of models (because Collection is Arrayable)
$this->setProperty($method, '\Illuminate\Database\Eloquent\Collection|'.$returnModel.'[]', true, null);
}
}else{
//Not a relation
}
}
}
}
}
/**
* @param string $name
* @param string|null $type
* @param bool|null $read
* @param bool|null $write
*/
protected function setProperty($name, $type = null, $read = null, $write = null){
if(!isset($this->properties[$name])){
$this->properties[$name] = array();
$this->properties[$name]['type'] = 'mixed';
$this->properties[$name]['read'] = false;
$this->properties[$name]['write'] = false;
}
if($type !== null){
$this->properties[$name]['type'] = $type;
}
if($read !== null){
$this->properties[$name]['read'] = $read;
}
if($write !== null){
$this->properties[$name]['write'] = $write;
}
}
protected function setMethod($name, $type = null){
if(!isset($this->methods[$name])){
$this->methods[$name] = array();
$this->methods[$name]['type'] = 'static';
}
if($type !== null){
$this->methods[$name]['type'] = $type;
}
}
/**
* @param string $class
* @return string
*/
protected function createPhpDocs($class){
$reflection = new \ReflectionClass($class);
$namespace = $reflection->getNamespaceName();
$classname = $reflection->getShortName();
$originalDoc = $reflection->getDocComment();
if($this->reset){
$phpdoc = new DocBlock('', new Context($namespace));
}else{
$phpdoc = new DocBlock($reflection, new Context($namespace));
}
if(!$phpdoc->getText()){
$phpdoc->setText("An Eloquent Model: '$class'");
}
$properties = array();
$methods = array();
foreach($phpdoc->getTags() as $tag){
$name = $tag->getName();
if($name == "property" || $name == "property-read" || $name == "property-write"){
$properties[] =$tag->getVariableName();
}elseif($name == "method"){
$methods[] = $tag->getMethodName();
}
}
foreach($this->properties as $name => $property){
$name = "\$$name";
if(in_array($name, $properties)){
continue;
}
if($property['read'] && $property['write']){
$attr = 'property';
}elseif($property['write']){
$attr = 'property-write';
}else{
$attr = 'property-read';
}
$tag = Tag::createInstance("@{$attr} {$property['type']} {$name}", $phpdoc);
$phpdoc->appendTag($tag);
}
foreach($this->methods as $name => $method){
if(in_array($name, $methods)){
continue;
}
$name = "$name()";
$tag = Tag::createInstance("@method {$method['type']} {$name}", $phpdoc);
$phpdoc->appendTag($tag);
}
$serializer = new DocBlockSerializer();
$serializer->getDocComment($phpdoc);
$docComment = $serializer->getDocComment($phpdoc);
if($this->write){
$filename = $reflection->getFileName();
$contents = \File::get($filename);
if($originalDoc){
$contents = str_replace($originalDoc, $docComment, $contents);
}else{
$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)){
$this->info('Written new phpDocBlock to '.$filename);
}
}
$output = "namespace {$namespace}{\n{$docComment}\n\tclass {$classname} {}\n}\n\n";
return $output;
}
}
-170
View File
@@ -1,170 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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\Console;
use Barryvdh\LaravelIdeHelper\Generator;
use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Console\Command;
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
*
* @author Barry vd. Heuvel <[email protected]>
*/
class GeneratorCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'ide-helper:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate a new IDE Helper file.';
/** @var \Illuminate\Config\Repository */
protected $config;
/** @var \Illuminate\Filesystem\Filesystem */
protected $files;
/** @var \Illuminate\View\Factory */
protected $view;
protected $onlyExtend;
/**
*
* @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
) {
$this->config = $config;
$this->files = $files;
$this->view = $view;
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (file_exists(base_path() . '/vendor/compiled.php') ||
file_exists(base_path() . '/bootstrap/cache/compiled.php') ||
file_exists(base_path() . '/storage/framework/compiled.php')) {
$this->error(
'Error generating IDE Helper: first delete your compiled file (php artisan clear-compiled)'
);
} else {
$filename = $this->argument('filename');
$format = $this->option('format');
// Strip the php extension
if (substr($filename, -4, 4) == '.php') {
$filename = substr($filename, 0, -4);
}
$filename .= '.' . $format;
if ($this->option('memory')) {
$this->useMemoryDriver();
}
$helpers = '';
if ($this->option('helpers') || ($this->config->get('ide-helper.include_helpers'))) {
foreach ($this->config->get('ide-helper.helper_files', array()) as $helper) {
if (file_exists($helper)) {
$helpers .= str_replace(array('<?php', '?>'), '', $this->files->get($helper));
}
}
} else {
$helpers = '';
}
$generator = new Generator($this->config, $this->view, $this->getOutput(), $helpers);
$content = $generator->generate($format);
$written = $this->files->put($filename, $content);
if ($written !== false) {
$this->info("A new helper file was written to $filename");
} else {
$this->error("The helper file could not be created at $filename");
}
}
}
protected function useMemoryDriver()
{
//Use a sqlite database in memory, to avoid connection errors on Database facades
$this->config->set(
'database.connections.sqlite',
array(
'driver' => 'sqlite',
'database' => ':memory:',
)
);
$this->config->set('database.default', 'sqlite');
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
$filename = $this->config->get('ide-helper.filename');
return array(
array(
'filename', InputArgument::OPTIONAL, 'The path to the helper file', $filename
),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
$format = $this->config->get('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'),
);
}
}
-140
View File
@@ -1,140 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @copyright 2015 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\Console;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* A command to generate phpstorm meta data
*
* @author Barry vd. Heuvel <[email protected]>
*/
class MetaCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'ide-helper:meta';
protected $filename = '.phpstorm.meta.php';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate metadata for PhpStorm';
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
protected $files;
/** @var \Illuminate\Contracts\View\Factory */
protected $view;
protected $methods = [
'new \Illuminate\Contracts\Container\Container',
'\Illuminate\Contracts\Container\Container::make(\'\')',
'\App::make(\'\')',
'app(\'\')',
];
/**
*
* @param \Illuminate\Contracts\Filesystem\Filesystem $files
* @param \Illuminate\Contracts\View\Factory $view
*/
public function __construct($files, $view) {
$this->files = $files;
$this->view = $view;
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$this->registerClassAutoloadExceptions();
$bindings = array();
foreach ($this->getAbstracts() as $abstract) {
// Validator causes problems in Lumen
if ($abstract == 'validator') {
continue;
}
try {
$concrete = $this->laravel->make($abstract);
if (is_object($concrete)) {
$bindings[$abstract] = get_class($concrete);
}
}catch (\Exception $e) {
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$this->comment("Cannot make '$abstract': ".$e->getMessage());
}
}
}
$content = $this->view->make('ide-helper::meta', [
'bindings' => $bindings,
'methods' => $this->methods,
])->render();
$filename = $this->option('filename');
$written = $this->files->put($filename, $content);
if ($written !== false) {
$this->info("A new meta file was written to $filename");
} else {
$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()
{
$abstracts = $this->laravel->getBindings();
// Return the abstract names only
return array_keys($abstracts);
}
/**
* Register an autoloader the throws exceptions when a class is not found.
*/
protected function registerClassAutoloadExceptions()
{
spl_autoload_register(function ($class) {
throw new \Exception("Class '$class' not found.");
});
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the meta file', $this->filename),
);
}
}
-568
View File
@@ -1,568 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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\Console;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Str;
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 phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Serializer as DocBlockSerializer;
/**
* A command to generate autocomplete information for your IDE
*
* @author Barry vd. Heuvel <[email protected]>
*/
class ModelsCommand extends Command
{
/**
* @var Filesystem $files
*/
protected $files;
/**
* The console command name.
*
* @var string
*/
protected $name = 'ide-helper:models';
protected $filename = '_ide_helper_models.php';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate autocompletion for models';
protected $properties = array();
protected $methods = array();
protected $write = false;
protected $dirs = array();
protected $reset;
/**
* @param Filesystem $files
*/
public function __construct(Filesystem $files)
{
parent::__construct();
$this->files = $files;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$filename = $this->option('filename');
$this->write = $this->option('write');
$this->dirs = array_merge(
$this->laravel['config']->get('ide-helper.model_locations'),
$this->option('dir')
);
$model = $this->argument('model');
$ignore = $this->option('ignore');
$this->reset = $this->option('reset');
//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): "
)
) {
$this->write = true;
}
}
$content = $this->generateDocs($model, $ignore);
if (!$this->write) {
$written = $this->files->put($filename, $content);
if ($written !== false) {
$this->info("Model information was written to $filename");
} else {
$this->error("Failed to write model information to $filename");
}
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('model', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Which models to include', array()),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the helper file', $this->filename),
array('dir', 'D', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The model dir', array()),
array('write', 'W', InputOption::VALUE_NONE, 'Write to Model file'),
array('nowrite', 'N', InputOption::VALUE_NONE, 'Don\'t write to Model file'),
array('reset', 'R', InputOption::VALUE_NONE, 'Remove the original phpdocs instead of appending'),
array('ignore', 'I', InputOption::VALUE_OPTIONAL, 'Which models to ignore', ''),
);
}
protected function generateDocs($loadModels, $ignore = '')
{
$output = "<?php
/**
* An helper file for your Eloquent Models
* Copy the phpDocs from this file to the correct Model,
* And remove them from this file, to prevent double declarations.
*
* @author Barry vd. Heuvel <[email protected]>
*/
\n\n";
$hasDoctrine = interface_exists('Doctrine\DBAL\Driver');
if (empty($loadModels)) {
$models = $this->loadModels();
} else {
$models = array();
foreach ($loadModels as $model) {
$models = array_merge($models, explode(',', $model));
}
}
$ignore = explode(',', $ignore);
foreach ($models as $name) {
if (in_array($name, $ignore)) {
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$this->comment("Ignoring model '$name'");
}
continue;
}
$this->properties = array();
$this->methods = array();
if (class_exists($name)) {
try {
// handle abstract classes, interfaces, ...
$reflectionClass = new \ReflectionClass($name);
if (!$reflectionClass->isSubclassOf('Illuminate\Database\Eloquent\Model')) {
continue;
}
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$this->comment("Loading model '$name'");
}
if (!$reflectionClass->IsInstantiable()) {
throw new \Exception($name . ' is not instantiable.');
}
$model = $this->laravel->make($name);
if ($hasDoctrine) {
$this->getPropertiesFromTable($model);
}
$this->getPropertiesFromMethods($model);
$output .= $this->createPhpDocs($name);
$ignore[] = $name;
} catch (\Exception $e) {
$this->error("Exception: " . $e->getMessage() . "\nCould not analyze class $name.");
}
}
}
if (!$hasDoctrine) {
$this->error(
'Warning: `"doctrine/dbal": "~2.3"` is required to load database information. Please require that in your composer.json and run `composer update`.'
);
}
return $output;
}
protected function loadModels()
{
$models = array();
foreach ($this->dirs as $dir) {
$dir = base_path() . '/' . $dir;
if (file_exists($dir)) {
foreach (ClassMapGenerator::createMap($dir) as $model => $path) {
$models[] = $model;
}
}
}
return $models;
}
/**
* Load the properties from the database table.
*
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromTable($model)
{
$table = $model->getConnection()->getTablePrefix() . $model->getTable();
$schema = $model->getConnection()->getDoctrineSchemaManager($table);
$databasePlatform = $schema->getDatabasePlatform();
$databasePlatform->registerDoctrineTypeMapping('enum', 'string');
$platformName = $databasePlatform->getName();
$customTypes = $this->laravel['config']->get("ide-helper.custom_db_types.{$platformName}", array());
foreach ($customTypes as $yourTypeName => $doctrineTypeName) {
$databasePlatform->registerDoctrineTypeMapping($yourTypeName, $doctrineTypeName);
}
$database = null;
if (strpos($table, '.')) {
list($database, $table) = explode('.', $table);
}
$columns = $schema->listTableColumns($table, $database);
if ($columns) {
foreach ($columns as $column) {
$name = $column->getName();
if (in_array($name, $model->getDates())) {
$type = '\Carbon\Carbon';
} else {
$type = $column->getType()->getName();
switch ($type) {
case 'string':
case 'text':
case 'date':
case 'time':
case 'guid':
case 'datetimetz':
case 'datetime':
$type = 'string';
break;
case 'integer':
case 'bigint':
case 'smallint':
$type = 'integer';
break;
case 'decimal':
case 'float':
$type = 'float';
break;
case 'boolean':
$type = 'boolean';
break;
default:
$type = 'mixed';
break;
}
}
$comment = $column->getComment();
$this->setProperty($name, $type, true, true, $comment);
}
}
}
/**
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromMethods($model)
{
$methods = get_class_methods($model);
if ($methods) {
foreach ($methods as $method) {
if (Str::startsWith($method, 'get') && Str::endsWith(
$method,
'Attribute'
) && $method !== 'getAttribute'
) {
//Magic get<name>Attribute
$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'
) {
//Magic set<name>Attribute
$name = Str::snake(substr($method, 3, -9));
if (!empty($name)) {
$this->setProperty($name, null, null, true);
}
} elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') {
//Magic set<name>Attribute
$name = Str::camel(substr($method, 5));
if (!empty($name)) {
$reflection = new \ReflectionMethod($model, $method);
$args = $this->getParameters($reflection);
//Remove the first ($query) argument
array_shift($args);
$this->setMethod($name, '\Illuminate\Database\Query\Builder|\\' . $reflection->class, $args);
}
} elseif (!method_exists('Eloquent', $method) && !Str::startsWith($method, 'get')) {
//Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
$reflection = new \ReflectionMethod($model, $method);
$file = new \SplFileObject($reflection->getFileName());
$file->seek($reflection->getStartLine() - 1);
$code = '';
while ($file->key() < $reflection->getEndLine()) {
$code .= $file->current();
$file->next();
}
$code = trim(preg_replace('/\s\s+/', '', $code));
$begin = strpos($code, 'function(');
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
foreach (array(
'hasMany',
'belongsToMany',
'hasOne',
'belongsTo',
'morphTo',
'morphMany',
'morphToMany'
) as $relation) {
$search = '$this->' . $relation . '(';
if ($pos = stripos($code, $search)) {
//Resolve the relation's model to a Relation object.
$relationObj = $model->$method();
if ($relationObj instanceof Relation) {
$relatedModel = '\\' . get_class($relationObj->getRelated());
if (in_array($relation, ['belongsToMany', 'hasMany', 'morphMany', 'morphToMany'])) {
//Collection or array of models (because Collection is Arrayable)
$this->setProperty(
$method,
$this->getCollectionClass($relatedModel) . '|' . $relatedModel . '[]',
true,
null
);
} else {
//Single model is returned
$this->setProperty($method, $relatedModel, true, null);
}
}
}
}
}
}
}
}
/**
* @param string $name
* @param string|null $type
* @param bool|null $read
* @param bool|null $write
* @param string|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;
}
if ($type !== null) {
$this->properties[$name]['type'] = $type;
}
if ($read !== null) {
$this->properties[$name]['read'] = $read;
}
if ($write !== null) {
$this->properties[$name]['write'] = $write;
}
}
protected function setMethod($name, $type = '', $arguments = array())
{
$methods = array_change_key_case($this->methods, CASE_LOWER);
if (!isset($methods[strtolower($name)])) {
$this->methods[$name] = array();
$this->methods[$name]['type'] = $type;
$this->methods[$name]['arguments'] = $arguments;
}
}
/**
* @param string $class
* @return string
*/
protected function createPhpDocs($class)
{
$reflection = new \ReflectionClass($class);
$namespace = $reflection->getNamespaceName();
$classname = $reflection->getShortName();
$originalDoc = $reflection->getDocComment();
if ($this->reset) {
$phpdoc = new DocBlock('', new Context($namespace));
} else {
$phpdoc = new DocBlock($reflection, new Context($namespace));
}
if (!$phpdoc->getText()) {
$phpdoc->setText($class);
}
$properties = array();
$methods = array();
foreach ($phpdoc->getTags() as $tag) {
$name = $tag->getName();
if ($name == "property" || $name == "property-read" || $name == "property-write") {
$properties[] = $tag->getVariableName();
} elseif ($name == "method") {
$methods[] = $tag->getMethodName();
}
}
foreach ($this->properties as $name => $property) {
$name = "\$$name";
if (in_array($name, $properties)) {
continue;
}
if ($property['read'] && $property['write']) {
$attr = 'property';
} elseif ($property['write']) {
$attr = 'property-write';
} else {
$attr = 'property-read';
}
$tagLine = trim("@{$attr} {$property['type']} {$name} {$property['comment']}");
$tag = Tag::createInstance($tagLine, $phpdoc);
$phpdoc->appendTag($tag);
}
foreach ($this->methods as $name => $method) {
if (in_array($name, $methods)) {
continue;
}
$arguments = implode(', ', $method['arguments']);
$tag = Tag::createInstance("@method static {$method['type']} {$name}({$arguments})", $phpdoc);
$phpdoc->appendTag($tag);
}
$serializer = new DocBlockSerializer();
$serializer->getDocComment($phpdoc);
$docComment = $serializer->getDocComment($phpdoc);
if ($this->write) {
$filename = $reflection->getFileName();
$contents = $this->files->get($filename);
if ($originalDoc) {
$contents = str_replace($originalDoc, $docComment, $contents);
} else {
$needle = "class {$classname}";
$replace = "{$docComment}\nclass {$classname}";
$pos = strpos($contents, $needle);
if ($pos !== false) {
$contents = substr_replace($contents, $replace, $pos, strlen($needle));
}
}
if ($this->files->put($filename, $contents)) {
$this->info('Written new phpDocBlock to ' . $filename);
}
}
$output = "namespace {$namespace}{\n{$docComment}\n\tclass {$classname} {}\n}\n\n";
return $output;
}
/**
* 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();
/** @var \ReflectionParameter $param */
foreach ($method->getParameters() as $param) {
$paramStr = '$' . $param->getName();
$params[] = $paramStr;
if ($param->isOptional() && $param->isDefaultValueAvailable()) {
$default = $param->getDefaultValue();
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;
}
return $paramsWithDefault;
}
/**
* Determine a model classes' collection type.
*
* @see http://laravel.com/docs/eloquent-collections#custom-collections
* @param string $className
* @return string
*/
private function getCollectionClass($className)
{
// Return something in the very very unlikely scenario the model doesn't
// have a newCollection() method.
if (!method_exists($className, 'newCollection')) {
return '\Illuminate\Database\Eloquent\Collection';
}
/** @var \Illuminate\Database\Eloquent\Model $model */
$model = new $className;
return '\\' . get_class($model->newCollection());
}
}
-275
View File
@@ -1,275 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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('ide-helper.extra'));
$this->magic = array_merge($this->magic, $this->config->get('ide-helper.magic'));
$this->interfaces = array_merge($this->interfaces, $this->config->get('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('ide-helper::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()
{
$this->interfaces['\Illuminate\Contracts\Auth\Authenticatable'] = config('auth.model', 'App\User');
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 ($this->getAliases() as $name => $facade) {
// Skip the Redis facade, if not available (otherwise Fatal PHP Error)
if ($facade == 'Illuminate\Support\Facades\Redis' && !class_exists('Predis\Client')) {
continue;
}
$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;
}
protected function getAliases()
{
// For Laravel, use the AliasLoader
if (class_exists('Illuminate\Foundation\AliasLoader')) {
return AliasLoader::getInstance()->getAliases();
}
$facades = [
'App' => 'Illuminate\Support\Facades\App',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Bus' => 'Illuminate\Support\Facades\Bus',
'DB' => 'Illuminate\Support\Facades\DB',
'Cache' => 'Illuminate\Support\Facades\Cache',
'Cookie' => 'Illuminate\Support\Facades\Cookie',
'Crypt' => 'Illuminate\Support\Facades\Crypt',
'Event' => 'Illuminate\Support\Facades\Event',
'Hash' => 'Illuminate\Support\Facades\Hash',
'Log' => 'Illuminate\Support\Facades\Log',
'Mail' => 'Illuminate\Support\Facades\Mail',
'Queue' => 'Illuminate\Support\Facades\Queue',
'Request' => 'Illuminate\Support\Facades\Request',
'Schema' => 'Illuminate\Support\Facades\Schema',
'Session' => 'Illuminate\Support\Facades\Session',
'Storage' => 'Illuminate\Support\Facades\Storage',
//'Validator' => 'Illuminate\Support\Facades\Validator',
];
// Only return the ones that actually exist
return array_filter($facades, function($alias){
return class_exists($alias);
});
}
/**
* 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("<error>$string</error>");
}else{
echo $string . "\r\n";
}
}
}
-88
View File
@@ -1,88 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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\Support\ServiceProvider;
use Barryvdh\LaravelIdeHelper\Console\MetaCommand;
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\LaravelIdeHelper\Console\GeneratorCommand;
class IdeHelperServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$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');
} else {
$publishPath = base_path('config/ide-helper.php');
}
$this->publishes([$configPath => $publishPath], 'config');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$configPath = __DIR__ . '/../config/ide-helper.php';
$this->mergeConfigFrom($configPath, 'ide-helper');
$this->app['command.ide-helper.generate'] = $this->app->share(
function ($app) {
return new GeneratorCommand($app['config'], $app['files'], $app['view']);
}
);
$this->app['command.ide-helper.models'] = $this->app->share(
function ($app) {
return new ModelsCommand($app['files']);
}
);
$this->app['command.ide-helper.meta'] = $this->app->share(
function ($app) {
return new MetaCommand($app['files'], $app['view']);
}
);
$this->commands('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('command.ide-helper.generate', 'command.ide-helper.models');
}
}
-313
View File
@@ -1,313 +0,0 @@
<?php
/**
* Laravel IDE Helper Generator
*
* @author Barry vd. Heuvel <[email protected]>
* @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;
use phpDocumentor\Reflection\DocBlock\Tag\ParamTag;
use phpDocumentor\Reflection\DocBlock\Serializer as DocBlockSerializer;
class Method
{
/** @var \phpDocumentor\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;
} elseif (is_resource($default)) {
//skip to not fail
} 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;
}
}
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Filename
|--------------------------------------------------------------------------
|
| The default path to the helper file
|
*/
'filename' => '_ide_helper.php',
/*
|--------------------------------------------------------------------------
| Helper files to include
|--------------------------------------------------------------------------
|
| Include helper files. By default not included, but can be toggled with the
| -- helpers (-H) option. Extra helper files can be included.
|
*/
'include_helpers' => false,
'helper_files' => array(
base_path().'/vendor/laravel/framework/src/Illuminate/Support/helpers.php',
),
/*
|--------------------------------------------------------------------------
| Extra classes
|--------------------------------------------------------------------------
|
| These implementations are not really extended, but called with magic functions
|
*/
'extra' => array(
'Eloquent' => array('Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'),
),
);