• Laravel Packages


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

    image

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

    image

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

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

    1. GeneratorSeriveProvider

     
    其全部代码如下:
    <?php namespace WayGenerators;
    
    use IlluminateSupportServiceProvider;
    use WayGeneratorsCommandsControllerGeneratorCommand;
    use WayGeneratorsCommandsModelGeneratorCommand;
    use WayGeneratorsCommandsResourceGeneratorCommand;
    use WayGeneratorsCommandsSeederGeneratorCommand;
    use WayGeneratorsCommandsPublishTemplatesCommand;
    use WayGeneratorsCommandsScaffoldGeneratorCommand;
    use WayGeneratorsCommandsViewGeneratorCommand;
    use WayGeneratorsCommandsPivotGeneratorCommand;
    
    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('WayGeneratorsGenerator');
    
                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('WayGeneratorsGenerator');
    
                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('WayGeneratorsGenerator');
    
                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('WayGeneratorsCommandsMigrationGeneratorCommand');
            });
    
            $this->commands('generate.migration');
        }
    
        /**
         * Register the seeder generator
         */
        protected function registerSeeder()
        {
            $this->app['generate.seeder'] = $this->app->share(function($app)
            {
                $generator = $this->app->make('WayGeneratorsGenerator');
    
                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('WayGeneratorsGenerator');
    
                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 WayGeneratorsCommands;
    
    use SymfonyComponentConsoleInputInputOption;
    use SymfonyComponentConsoleInputInputArgument;
    
    class ControllerGeneratorCommand extends GeneratorCommand {
    
    
    
    <?php namespace WayGeneratorsCommands;
    
    use SymfonyComponentConsoleInputInputOption;
    use SymfonyComponentConsoleInputInputArgument;
    use WayGeneratorsParsersMigrationNameParser;
    use WayGeneratorsParsersMigrationFieldsParser;
    use WayGeneratorsGenerator;
    use WayGeneratorsSchemaCreator;
    use Config;
    
    class MigrationGeneratorCommand extends GeneratorCommand {
    
    
    
    <?php namespace WayGeneratorsCommands;
    
    use SymfonyComponentConsoleInputInputOption;
    use SymfonyComponentConsoleInputInputArgument;
    
    class ModelGeneratorCommand extends GeneratorCommand {
    
    
    
    <?php namespace WayGeneratorsCommands;
    
    use IlluminateSupportFacadesFile;
    use SymfonyComponentConsoleInputInputOption;
    use SymfonyComponentConsoleInputInputArgument;
    
    class ViewGeneratorCommand extends GeneratorCommand {

    2. GeneratorCommand

    我们来看看GeneratorCommand的代码:

    <?php namespace WayGeneratorsCommands;
    
    use SymfonyComponentConsoleInputInputOption;
    use SymfonyComponentConsoleInputInputArgument;
    use IlluminateConsoleCommand;
    use WayGeneratorsFilesystemFileAlreadyExists;
    use WayGeneratorsGenerator;
    use Config;
    
    abstract class GeneratorCommand extends Command {
    
        /**
         * @var WayGeneratorsModelGenerator
         */
        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 WayGenerators;
    
    use WayGeneratorsFilesystemFilesystem;
    use WayGeneratorsCompilersTemplateCompiler;
    use WayGeneratorsUndefinedTemplate;
    
    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('WayGeneratorsGenerator');
    
                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字段。

    image

    <?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 FakerFactory 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()
  • 相关阅读:
    【转载】 jmeter 命令行模式(非GUI)运行脚本,察看结果树结果为空,解决办法
    jmeter调试元件Debug Sampler的使用
    cookie和session区别
    jmeter控制器入门笔记一
    jmeter变量的声明和使用
    jmeter正则表达式,萌新入门篇
    jmeter跨线程组session保持
    学习js都学习什么?
    使用react定义组件的两种方式
    使用jQuery.extend创建一个简单的选项卡插件
  • 原文地址:https://www.cnblogs.com/mumutouv/p/4293110.html
Copyright © 2020-2023  润新知