码迷,mamicode.com
首页 > 其他好文 > 详细

Laravel Packages

时间:2015-02-15 17:48:43      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

Laravel的包存放在vendor目录下面。

技术分享

例如way,可以是一个供应商代号,其目录下面有一个generators目录。

技术分享

在src目录下面有Way/Generators目录,里面存放真正的代码文件。提供一个GeneratorServiceProvider.php文件,实现了多个派生自

Illuminate\Console\Command类的命令。其中包括:
generate:view
generate:model
generate:controller
generate:migration
generate:seeder
generate:pivot
generate:resource
generate:scaffold
generate:publisher

1. GeneratorSeriveProvider

 
其全部代码如下:
<?php namespace Way\Generators;

use Illuminate\Support\ServiceProvider;
use Way\Generators\Commands\ControllerGeneratorCommand;
use Way\Generators\Commands\ModelGeneratorCommand;
use Way\Generators\Commands\ResourceGeneratorCommand;
use Way\Generators\Commands\SeederGeneratorCommand;
use Way\Generators\Commands\PublishTemplatesCommand;
use Way\Generators\Commands\ScaffoldGeneratorCommand;
use Way\Generators\Commands\ViewGeneratorCommand;
use Way\Generators\Commands\PivotGeneratorCommand;

class GeneratorsServiceProvider extends ServiceProvider {

    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;


    /**
     * Booting
     */
    public function boot()
    {
        $this->package(‘way/generators‘);
    }

    /**
     * Register the commands
     *
     * @return void
     */
    public function register()
    {
        foreach([
            ‘Model‘,
            ‘View‘,
            ‘Controller‘,
            ‘Migration‘,
            ‘Seeder‘,
            ‘Pivot‘,
            ‘Resource‘,
            ‘Scaffold‘,
            ‘Publisher‘] as $command)
        {
            $this->{"register$command"}();
        }
    }

    /**
     * Register the model generator
     */
    protected function registerModel()
    {
        $this->app[‘generate.model‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new ModelGeneratorCommand($generator);
        });

        $this->commands(‘generate.model‘);
    }

    /**
     * Register the view generator
     */
    protected function registerView()
    {
        $this->app[‘generate.view‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new ViewGeneratorCommand($generator);
        });

        $this->commands(‘generate.view‘);
    }

    /**
     * Register the controller generator
     */
    protected function registerController()
    {
        $this->app[‘generate.controller‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new ControllerGeneratorCommand($generator);
        });

        $this->commands(‘generate.controller‘);
    }

    /**
     * Register the migration generator
     */
    protected function registerMigration()
    {
        $this->app[‘generate.migration‘] = $this->app->share(function($app)
        {
            return $this->app->make(‘Way\Generators\Commands\MigrationGeneratorCommand‘);
        });

        $this->commands(‘generate.migration‘);
    }

    /**
     * Register the seeder generator
     */
    protected function registerSeeder()
    {
        $this->app[‘generate.seeder‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new SeederGeneratorCommand($generator);
        });

        $this->commands(‘generate.seeder‘);
    }

    /**
     * Register the pivot generator
     */
    protected function registerPivot()
    {
        $this->app[‘generate.pivot‘] = $this->app->share(function($app)
        {
            return new PivotGeneratorCommand;
        });

        $this->commands(‘generate.pivot‘);
    }

    /**
     * Register the resource generator
     */
    protected function registerResource()
    {
        $this->app[‘generate.resource‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new ResourceGeneratorCommand($generator);
        });

        $this->commands(‘generate.resource‘);
    }

    /**
     * register command for publish templates
     */
    public function registerpublisher()
    {
        $this->app[‘generate.publish-templates‘] = $this->app->share(function($app)
        {
            return new publishtemplatescommand;
        });

        $this->commands(‘generate.publish-templates‘);
    }

    /**
     * register scaffold command
     */
    public function registerScaffold()
    {
        $this->app[‘generate.scaffold‘] = $this->app->share(function($app)
        {
            return new ScaffoldGeneratorCommand;
        });

        $this->commands(‘generate.scaffold‘);
    }



    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array();
    }

}
其中$this->commands(‘generate.scaffold‘)命令调用了ServiceProvider的commands.
public function commands($commands)
    {
        $commands = is_array($commands) ? $commands : func_get_args();

        // To register the commands with Artisan, we will grab each of the arguments
        // passed into the method and listen for Artisan "start" event which will
        // give us the Artisan console instance which we will give commands to.
        $events = $this->app[‘events‘];

        $events->listen(‘artisan.start‘, function($artisan) use ($commands)
        {
            $artisan->resolveCommands($commands);
        });
    }

其中每一个命令都是派生自GeneratorCommand类。

<?php namespace Way\Generators\Commands;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class ControllerGeneratorCommand extends GeneratorCommand {



<?php namespace Way\Generators\Commands;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Way\Generators\Parsers\MigrationNameParser;
use Way\Generators\Parsers\MigrationFieldsParser;
use Way\Generators\Generator;
use Way\Generators\SchemaCreator;
use Config;

class MigrationGeneratorCommand extends GeneratorCommand {



<?php namespace Way\Generators\Commands;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class ModelGeneratorCommand extends GeneratorCommand {



<?php namespace Way\Generators\Commands;

use Illuminate\Support\Facades\File;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class ViewGeneratorCommand extends GeneratorCommand {

2. GeneratorCommand

我们来看看GeneratorCommand的代码:

<?php namespace Way\Generators\Commands;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Console\Command;
use Way\Generators\Filesystem\FileAlreadyExists;
use Way\Generators\Generator;
use Config;

abstract class GeneratorCommand extends Command {

    /**
     * @var \Way\Generators\ModelGenerator
     */
    protected $generator;

    /**
     * @param Generator $generator
     */
    public function __construct(Generator $generator)
    {
        $this->generator = $generator;

        parent::__construct();
    }

    /**
     * Fetch the template data
     *
     * @return array
     */
    protected abstract function getTemplateData();

    /**
     * The path where the file will be created
     *
     * @return mixed
     */
    protected abstract function getFileGenerationPath();

    /**
     * Get the path to the generator template
     *
     * @return mixed
     */
    protected abstract function getTemplatePath();

    /**
     * Compile and generate the file
     */
    public function fire()
    {
        $filePathToGenerate = $this->getFileGenerationPath();

        try
        {
            $this->generator->make(
                $this->getTemplatePath(),
                $this->getTemplateData(),
                $filePathToGenerate
            );

            $this->info("Created: {$filePathToGenerate}");
        }

        catch (FileAlreadyExists $e)
        {
            $this->error("The file, {$filePathToGenerate}, already exists! I don‘t want to overwrite it.");
        }
    }

    /**
     * Get a directory path either through a
     * command option, or from the configuration
     *
     * @param $option
     * @param $configName
     * @return string
     */
    protected function getPathByOptionOrConfig($option, $configName)
    {
        if ($path = $this->option($option))
        {
            return $path;
        }

        return Config::get("generators::config.{$configName}");
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return [
            [‘path‘, null, InputOption::VALUE_REQUIRED, ‘Where should the file be created?‘],
            [‘templatePath‘, null, InputOption::VALUE_REQUIRED, ‘The location of the template for this generator‘]
        ];
    }

}

该类有三个虚函数

getTemplateData
getFileGenerationPath   //创建的文件存放路径
getTemplatePath    //模板文件的路径
 
并且最终调用了Generator类的make函数来生成相应的内容。

3. Generator

其全部代码如下:

<?php namespace Way\Generators;

use Way\Generators\Filesystem\Filesystem;
use Way\Generators\Compilers\TemplateCompiler;
use Way\Generators\UndefinedTemplate;

class Generator {

    /**
     * @var Filesystem
     */
    protected $file;

    /**
     * @param Filesystem $file
     */
    public function __construct(Filesystem $file)
    {
        $this->file = $file;
    }

    /**
     * Run the generator
     *
     * @param $templatePath
     * @param $templateData
     * @param $filePathToGenerate
     */
    public function make($templatePath, $templateData, $filePathToGenerate)
    {
        // We first need to compile the template,
        // according to the data that we provide.
        $template = $this->compile($templatePath, $templateData, new TemplateCompiler);

        // Now that we have the compiled template,
        // we can actually generate the file.
        $this->file->make($filePathToGenerate, $template);
    }

    /**
     * Compile the file
     *
     * @param $templatePath
     * @param array $data
     * @param TemplateCompiler $compiler
     * @throws UndefinedTemplate
     * @return mixed
     */
    public function compile($templatePath, array $data, TemplateCompiler $compiler)
    {
        return $compiler->compile($this->file->get($templatePath), $data);
    }

}

4. generator:view 是如何执行的?

4.1 ServiceProvider Register

/**
     * Register the view generator
     */
    protected function registerView()
    {
        $this->app[‘generate.view‘] = $this->app->share(function($app)
        {
            $generator = $this->app->make(‘Way\Generators\Generator‘);

            return new ViewGeneratorCommand($generator);
        });

        $this->commands(‘generate.view‘);
    }

$this->app->make是从container中取出单一实例化的对象。

4.2 ViewGeneratorCommand fire

4.2.1 getFileGenerationPath

/**
     * Create directory tree for views,
     * and fire generator
     */
    public function fire()
    {
        $directoryPath = dirname($this->getFileGenerationPath());

        if ( ! File::exists($directoryPath))
        {
            File::makeDirectory($directoryPath, 0777, true);
        }

        parent::fire();
    }
/**
     * The path where the file will be created
     *
     * @return mixed
     */
    protected function getFileGenerationPath()
    {
        $path = $this->getPathByOptionOrConfig(‘path‘, ‘view_target_path‘);
        $viewName = str_replace(‘.‘, ‘/‘, $this->argument(‘viewName‘));

        return sprintf(‘%s/%s.blade.php‘, $path, $viewName);
    }
protected function getPathByOptionOrConfig($option, $configName)
    {
        if ($path = $this->option($option))
        {
            return $path;
        }

        return Config::get("generators::config.{$configName}");
    }

为什么我们输入php artisan generate:view xxxx.yyyy的时候,新建的文件yyyy.php会出现在app/views/xxxx下面?

就是因为下面这段代码:

$viewName = str_replace(‘.‘, ‘/‘, $this->argument(‘viewName‘));

首先判断path参数是否指定,如果没有指定的话,那么就从默认的Config里面去取generators::config.view_target_path字段。

技术分享

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Where the templates for the generators are stored...
    |--------------------------------------------------------------------------
    |
    */
    ‘model_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/model.txt‘,

    ‘scaffold_model_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/scaffolding/model.txt‘,

    ‘controller_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/controller.txt‘,

    ‘scaffold_controller_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/scaffolding/controller.txt‘,

    ‘migration_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/migration.txt‘,

    ‘seed_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/seed.txt‘,

    ‘view_template_path‘ => ‘vendor/way/generators/src/Way/Generators/templates/view.txt‘,


    /*
    |--------------------------------------------------------------------------
    | Where the generated files will be saved...
    |--------------------------------------------------------------------------
    |
    */
    ‘model_target_path‘   => app_path(‘models‘),

    ‘controller_target_path‘   => app_path(‘controllers‘),

    ‘migration_target_path‘   => app_path(‘database/migrations‘),

    ‘seed_target_path‘   => app_path(‘database/seeds‘),

    ‘view_target_path‘   => app_path(‘views‘)

];

4.2.2 getTemplatePath

protected function getTemplatePath()
    {
        return $this->getPathByOptionOrConfig(‘templatePath‘, ‘view_template_path‘);
    }

从template文件中读取相应的数据,并进行替换,然后再通过filesystem的make函数将数据写入到文件里面就OK.

<?php

// Composer: "fzaninotto/faker": "v1.3.0"
use Faker\Factory as Faker;

class $CLASS$ extends Seeder {

    public function run()
    {
        $faker = Faker::create();

        foreach(range(1, 10) as $index)
        {
            $MODEL$::create([

            ]);
        }
    }

}
/**
     * Fetch the template data
     *
     * @return array
     */
    protected function getTemplateData()
    {
        $tableName = $this->getTableName();

        return [
            ‘CLASS‘ => "{$tableName}TableSeeder",
            ‘MODEL‘ => str_singular($tableName)
        ];
    }
class Filesystem {

    /**
     * Make a file
     *
     * @param $file
     * @param $content
     * @throws FileAlreadyExists
     * @return int
     */
    public function make($file, $content)
    {
        if ( $this->exists($file))
        {
            throw new FileAlreadyExists;
        }

        return file_put_contents($file, $content);
    }

5. 流程图

ViewGeneratorCommand::fire()
GeneratorCommand::fire()
ViewGeneratorCommand::getFileGenerationPath()
ViewGeneratorCommand::getTemplatePath
ViewGeneratorCommand::getTemplateData
Generator::make()
TemplateCompiler::compile()
FileSystem::make()

Laravel Packages

标签:

原文地址:http://www.cnblogs.com/mumutouv/p/4293110.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!