Big refactor

This commit is contained in:
Barry vd. Heuvel
2014-08-06 00:02:00 +02:00
parent 3151019947
commit 8193fa0763
8 changed files with 913 additions and 570 deletions
+241
View File
@@ -0,0 +1,241 @@
<?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;
class Alias
{
protected $alias;
protected $facade;
protected $extends = null;
protected $classTYpe = 'class';
protected $namespace = '__root';
protected $root = null;
protected $classes = array();
protected $methods = array();
protected $used_methods = array();
protected $valid = false;
public function __construct($alias, $facade)
{
$this->alias = $alias;
// 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();
}
/**
* 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;
}
}
}
/**
* 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;
}
/**
* 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->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);
}
}
/**
* 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)) {
$this->error("Class $this->root is not found.");
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;
}
/**
* 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->used_methods)) {
// Only add the methods to the output when the root is not the same as the facade.
// And don't add the __*() methods
if ($this->facade !== $this->root && substr($method->name, 0, 2) !== '__') {
$this->methods[] = new Method($method, $this->alias, $reflection);
}
$this->used_methods[] = $method->name;
}
}
}
}
}
// Helper class to log errors
protected function error($msg)
{
echo $msg . "\r\n";
}
}
+64 -421
View File
@@ -9,7 +9,11 @@
*/
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;
use Illuminate\Foundation\AliasLoader;
@@ -17,12 +21,14 @@ 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 GeneratorCommand extends Command {
class GeneratorCommand extends Command
{
/**
* The console command name.
@@ -38,12 +44,38 @@ class GeneratorCommand extends Command {
*/
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 $extra;
protected $onlyExtend;
protected $helpers;
protected $magic;
/**
*
* @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.
*
@@ -52,7 +84,9 @@ class GeneratorCommand extends Command {
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)');
$this->error(
'Error generating IDE Helper: first delete bootstrap/compiled.php (php artisan clear-compiled)'
);
} else {
$filename = $this->argument('filename');
@@ -60,18 +94,24 @@ class GeneratorCommand extends Command {
$this->useMemoryDriver();
}
$this->extra = \Config::get('laravel-ide-helper::extra');
$this->magic = \Config::get('laravel-ide-helper::magic');
if( $this->option('helpers') || (\Config::get('laravel-ide-helper::include_helpers') )){
$this->helpers = \Config::get('laravel-ide-helper::helper_files');
$extra = $this->config->get('laravel-ide-helper::extra');
$magic = $this->config->get('laravel-ide-helper::magic');
$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) {
if (file_exists($helper)) {
$helpers .= str_replace(array('<?php', '?>'), '', $this->files->get($helper));
}
}
} else {
$this->helpers = array();
$helpers = '';
}
$content = $this->generateDocs();
$generator = new Generator($this->view, $extra, $magic, $helpers);
$output = $generator->generate();
$written = \File::put($filename, $content);
$written = $this->files->put($filename, $output);
if ($written !== false) {
$this->info("A new helper file was written to $filename");
@@ -81,13 +121,17 @@ class GeneratorCommand extends Command {
}
}
protected function useMemoryDriver(){
protected function useMemoryDriver()
{
//Use a sqlite database in memory, to avoid connection errors on Database facades
\Config::set('database.connections.sqlite',array(
$this->config->set(
'database.connections.sqlite',
array(
'driver' => 'sqlite',
'database' => ':memory:',
));
\Config::set('database.default', 'sqlite');
)
);
$this->config->set('database.default', 'sqlite');
}
/**
@@ -98,7 +142,12 @@ class GeneratorCommand extends Command {
protected function getArguments()
{
return array(
array('filename', InputArgument::OPTIONAL, 'The path to the helper file', \Config::get('laravel-ide-helper::filename')),
array(
'filename',
InputArgument::OPTIONAL,
'The path to the helper file',
$this->config->get('laravel-ide-helper::filename')
),
);
}
@@ -116,410 +165,4 @@ class GeneratorCommand extends Command {
);
}
/**
* Generate the docs for all facades in the AliasLoader
*
* @return string
*/
protected function generateDocs(){
$aliasLoader = AliasLoader::getInstance();
$outputString = "<?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]>
*/\n\n";
$output['__root'] = "\texit('Only to be used as an helper for your IDE');\n\n";
//Get all aliases
$aliases = $aliasLoader->getAliases();
foreach($aliases as $alias => $facade){
//Check if the facade is not a Trait
if(function_exists('trait_exists') && trait_exists($facade)){
continue;
}
$facade = '\\'.ltrim($facade, '\\');
$root = $this->getRoot($facade);
if(!$root){
continue;
}
try{
if (strpos($alias, '\\')){
$nsParts = explode('\\', $alias);
$alias = array_pop($nsParts);
$ns = implode('\\', $nsParts);
} else {
$ns = '__root';
}
if (!isset($output[$ns])) $output[$ns] = '';
//Some classes extend the facade
if(interface_exists($facade)){
$output[$ns] .= "\tinterface $alias extends $facade{\n";
}elseif(class_exists($facade)){
$output[$ns] .= "\tclass $alias extends $facade{\n";
}else{
$output[$ns] .= "\tclass $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[$ns] .= $this->getMethods($root, $alias, $usedMethods, $addOutput);
$driver = $this->getDriver($alias);
if($driver){
$output[$ns] .= $this->getMethods($driver, $alias, $usedMethods);
}
//Add extra methods, from other classes (magic static calls)
if(array_key_exists($alias, $this->extra)){
$output[$ns] .= $this->getMethods($this->extra[$alias], $alias, $usedMethods);
}
//Add extra methods, from other classes (magic static calls)
if(array_key_exists($alias, $this->magic)){
$output[$ns] .= $this->addMagicMethods($this->magic[$alias], $alias, $usedMethods);
}
$output[$ns] .= "\t}\n";
}catch(\Exception $e){
$this->error("Exception: ".$e->getMessage()."\nCould not analyze $root.");
}
}
//Include the helper file, if requested
if(!empty($this->helpers)){
foreach($this->helpers as $helper){
if (file_exists($helper)){
$output['__root'] .= str_replace(array('<?php', '?>'), '', \File::get($helper));
}
}
}
foreach ($output as $ns => $body){
if ($ns == '__root'){
$ns = '';
}
$outputString .= "namespace $ns{\n";
$outputString .= $body;
$outputString .= "}\n\n";
}
return $outputString;
}
/**
* 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;
}
}
/**
* 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;
}
}
/**
* 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;
}
/**
* Get the methods for one or multiple magic methods.
*
* @param $methods
* @param $alias
* @param $usedMethods
* @param bool $addOutput
* @return string
*/
protected function addMagicMethods($methods, $alias, &$usedMethods, $addOutput = true){
$output = '';
foreach($methods 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, $usedMethods)){
if( $addOutput){
$output .= $this->parseMethod($method, $alias, $class, $magic);
}
$usedMethods[] = $method->name;
}
$usedMethods[] = $magic;
}
return $output;
}
/**
* @param \ReflectionMethod $method
* @param string $alias
* @param $class
* @param null $methodName
* @return string
*/
protected function parseMethod($method, $alias, $class, $methodName = null){
$output = '';
// Don't add the __clone() functions
if($method->name === '__clone'){
return $output;
}
$methodName = $methodName ?: $method->name;
$namespace = $method->getDeclaringClass()->getNamespaceName();
//Create a DocBlock and serializer instance
$phpdoc = new DocBlock($method, new Context($namespace));
$serializer = new DocBlockSerializer(1, "\t\t");
//Normalize the description and inherit the docs from parents/interfaces
try{
$this->normalizeDescription($phpdoc, $method);
}catch(\Exception $e){
$this->info("Cannot normalize method $alias::$methodName..");
}
//Correct the return values
$returnValue = $this->getReturn($phpdoc);
//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\t public static function ".$methodName."(";
$output .= implode($paramsWithDefault, ", ");
$output .= "){\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();
$declaringClassName = '\\'.ltrim($declaringClass->name, '\\');
$root = '\\'.ltrim($class->getName(), '\\');
if($declaringClass->name != $root){
$output .= "\t\t\t//Method inherited from $declaringClassName\n";
}
$output .= "\t\t\t$return $root::";
//Write the default parameters in the function call
$output .= $method->name."(".implode($params, ", ").");\n";
$output .= "\t\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
* @return string|null
*/
protected function getReturn($phpdoc){
//Get the return type and adjust them for beter autocomplete
$returnTags = $phpdoc->getTagsByName('return');
if($returnTags){
/** @var $tag */
$tag = reset($returnTags);
$returnValue = $tag->getType();
}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;
}
}
}
}
+62 -21
View File
@@ -25,7 +25,8 @@ use phpDocumentor\Reflection\DocBlock\Serializer as DocBlockSerializer;
*
* @author Barry vd. Heuvel <[email protected]>
*/
class ModelsCommand extends Command {
class ModelsCommand extends Command
{
/**
* The console command name.
@@ -49,7 +50,6 @@ class ModelsCommand extends Command {
protected $reset;
/**
* Execute the console command.
*
@@ -59,14 +59,20 @@ class ModelsCommand extends Command {
{
$filename = $this->option('filename');
$this->write = $this->option('write');
$this->dirs = array_merge($this->laravel['config']->get('laravel-ide-helper::model_locations'), $this->option('dir'));
$this->dirs = array_merge(
$this->laravel['config']->get('laravel-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): ")){
if ($this->confirm(
"Do you want to overwrite the existing model files? Choose no to write to $filename instead? (Yes/No): "
)
) {
$this->write = true;
}
}
@@ -113,7 +119,8 @@ class ModelsCommand extends Command {
);
}
protected function generateDocs($loadModels, $ignore = ''){
protected function generateDocs($loadModels, $ignore = '')
{
$output = "<?php
@@ -175,7 +182,9 @@ class ModelsCommand extends Command {
}
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'.");
$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;
@@ -183,7 +192,8 @@ class ModelsCommand extends Command {
}
protected function loadModels(){
protected function loadModels()
{
$models = array();
foreach ($this->dirs as $dir) {
$dir = base_path() . '/' . $dir;
@@ -201,7 +211,8 @@ class ModelsCommand extends Command {
*
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromTable($model){
protected function getPropertiesFromTable($model)
{
$table = $model->getConnection()->getTablePrefix() . $model->getTable();
$schema = $model->getConnection()->getDoctrineSchemaManager($table);
$schema->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
@@ -245,7 +256,11 @@ class ModelsCommand extends Command {
$this->setProperty($name, $type, true, true);
$this->setMethod(Str::camel("where_".$name), '\Illuminate\Database\Query\Builder|\\'.get_class($model), array('$value'));
$this->setMethod(
Str::camel("where_" . $name),
'\Illuminate\Database\Query\Builder|\\' . get_class($model),
array('$value')
);
}
}
}
@@ -253,17 +268,26 @@ class ModelsCommand extends Command {
/**
* @param \Illuminate\Database\Eloquent\Model $model
*/
protected function getPropertiesFromMethods($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'){
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'){
} 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)) {
@@ -288,14 +312,22 @@ class ModelsCommand extends Command {
$file->seek($reflection->getStartLine() - 1);
$code = '';
while ($file->key() < $reflection->getEndLine())
{
$code .= $file->current(); $file->next();
while ($file->key() < $reflection->getEndLine()) {
$code .= $file->current();
$file->next();
}
$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));
@@ -304,7 +336,12 @@ class ModelsCommand extends Command {
$returnModel = "\\" . ltrim(trim($arguments[0], " \"'"), "\\");
if ($relation === "belongsToMany" or $relation === 'hasMany' or $relation === 'morphMany' or $relation === 'morphToMany') {
//Collection or array of models (because Collection is Arrayable)
$this->setProperty($method, '\Illuminate\Database\Eloquent\Collection|'.$returnModel.'[]', true, null);
$this->setProperty(
$method,
'\Illuminate\Database\Eloquent\Collection|' . $returnModel . '[]',
true,
null
);
} else {
//Single model is returned
$this->setProperty($method, $returnModel, true, null);
@@ -323,7 +360,8 @@ class ModelsCommand extends Command {
* @param bool|null $read
* @param bool|null $write
*/
protected function setProperty($name, $type = null, $read = null, $write = null){
protected function setProperty($name, $type = null, $read = null, $write = null)
{
if (!isset($this->properties[$name])) {
$this->properties[$name] = array();
$this->properties[$name]['type'] = 'mixed';
@@ -341,7 +379,8 @@ class ModelsCommand extends Command {
}
}
protected function setMethod($name, $type = '', $arguments=array()){
protected function setMethod($name, $type = '', $arguments = array())
{
if (!isset($this->methods[$name])) {
$this->methods[$name] = array();
$this->methods[$name]['type'] = $type;
@@ -353,7 +392,8 @@ class ModelsCommand extends Command {
* @param string $class
* @return string
*/
protected function createPhpDocs($class){
protected function createPhpDocs($class)
{
$reflection = new \ReflectionClass($class);
$namespace = $reflection->getNamespaceName();
@@ -439,7 +479,8 @@ class ModelsCommand extends Command {
* @param $method
* @return array
*/
public function getParameters($method){
public function getParameters($method)
{
//Loop through the default values for paremeters, and make the correct output string
$params = array();
$paramsWithDefault = array();
+130
View File
@@ -0,0 +1,130 @@
<?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\Foundation\AliasLoader;
use Illuminate\Config\Repository as ConfigRepository;
class Generator
{
/** @var \Illuminate\View\Factory */
protected $view;
protected $extra;
protected $magic;
protected $helpers;
/**
* @param \Illuminate\View\Factory $view
* @param array $extra
* @param array $magic
* @param string $helpers
*/
public function __construct( /* Illuminate\View\Factory */
$view,
$extra = array(),
$magic = array(),
$helpers = ''
) {
$this->view = $view;
$this->extra = $extra;
$this->magic = $magic;
$this->helpers = $helpers;
}
/**
* Generate the helper file contents;
*
* @return string;
*/
public function generate()
{
return $this->view->make('laravel-ide-helper::ide-helper')
->with('namespaces', $this->getNamespaces())
->with('helpers', $this->helpers)
->render();
}
/**
* 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) {
$alias = new Alias($name, $facade);
if ($alias->isValid()) {
$driver = $this->getDriver($name);
if ($driver) {
$alias->addClass($driver);
}
//Add extra methods, from other classes (magic static calls)
if (array_key_exists($name, $this->extra)) {
$alias->addClass($this->extra[$name]);
}
//Add extra methods, from other classes (magic static calls)
if (array_key_exists($name, $this->magic)) {
$alias->addClass($this->magic[$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;
}
}
}
+15 -9
View File
@@ -12,9 +12,11 @@ namespace Barryvdh\LaravelIdeHelper;
use Illuminate\Support\ServiceProvider;
use Barryvdh\LaravelIdeHelper\Console\GeneratorCommand;
use Barryvdh\LaravelIdeHelper\Console\Generator2Command;
Use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
class IdeHelperServiceProvider extends ServiceProvider {
class IdeHelperServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
@@ -30,7 +32,7 @@ class IdeHelperServiceProvider extends ServiceProvider {
*/
public function boot()
{
$this->app['config']->package('barryvdh/laravel-ide-helper', __DIR__ . '/config');
$this->package('barryvdh/laravel-ide-helper', 'laravel-ide-helper', __DIR__);
}
/**
@@ -40,15 +42,19 @@ class IdeHelperServiceProvider extends ServiceProvider {
*/
public function register()
{
$this->app['command.ide-helper.generate'] = $this->app->share(function()
{
return new GeneratorCommand;
});
$this->app['command.ide-helper.models'] = $this->app->share(function()
{
$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 () {
return new ModelsCommand();
});
}
);
$this->commands('command.ide-helper.generate', 'command.ide-helper.models');
}
+246
View File
@@ -0,0 +1,246 @@
<?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 phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Serializer as DocBlockSerializer;
class Method
{
protected $output = '';
protected $name;
protected $namespace;
protected $phpdoc;
protected $params = array();
protected $params_with_default = array();
public function __construct($method, $alias, $class, $methodName = null)
{
$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->normalizeDescription($method);
} catch (\Exception $e) {
$this->info("Cannot normalize method $alias::$methodName..");
}
//Get the parameters, including formatted default values
$this->getParameters($method);
//Make the method static
$this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc));
//Correct the return values
$returnValue = $this->getReturn();
//Only return when not a constructor and not void.
$this->return = ($returnValue && $returnValue !== "void" && $method->name !== "__construct");
//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;
}
/**
* Should the function return a value?
*
* @return bool
*/
public function shouldReturn()
{
return $this->return;
}
/**
* 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(', ', $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(', ', $this->params_with_default);
}
/**
* Get the description and get the inherited docs.
*
* @param $method
*/
protected function normalizeDescription($method)
{
//Get the short + long description from the DocBlock
$description = $this->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);
$this->phpdoc->setText($description);
//Add the tags that are inherited
$inheritTags = $inheritdoc->getTags();
if ($inheritTags) {
foreach ($inheritTags as $tag) {
$tag->setDocBlock();
$this->phpdoc->appendTag($tag);
}
}
}
}
/**
* Make some changes to the return types, if needed.
*
* @return string|null
*/
protected function getReturn()
{
//Get the return type and adjust them for beter autocomplete
$returnTags = $this->phpdoc->getTagsByName('return');
if ($returnTags) {
/** @var $tag */
$tag = reset($returnTags);
$returnValue = $tag->getType();
} 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;
}
$this->params = $params;
$this->params_with_default = $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;
}
}
}
}
Executable → Regular
View File
+36
View File
@@ -0,0 +1,36 @@
<?= '<?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]>
*/
<?php foreach($namespaces as $namespace => $aliases): ?>
namespace <?= $namespace == '__root' ? '' : $namespace ?>{
<?= $namespace == '__root' ? $helpers : '' ?>
<?php foreach($aliases as $alias): ?>
<?= $alias->getClassType() ?> <?= $alias->getAlias() ?> <?= $alias->getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{
<?php foreach($alias->getMethods() as $method): ?>
<?= trim($method->getDocComment()) ?>
public static function <?= $method->getName() ?>(<?= $method->getParamsWithDefault() ?>){
//Method inherited from <?= $method->getDeclaringClass() ?>
<?= $method->shouldReturn() ? 'return ': '' ?><?= $method->getRoot() ?>::<?= $method->getName() ?>(<?= $method->getParams() ?>);
}
<?php endforeach; ?>
}
<?php endforeach; ?>
}
<?php endforeach; ?>