Laravel 实现自定义生成文件命令

laravel实现自定义生成文件命令


前言

现在的项目中有使用Entiy文件,每次新增一张表的时候都要创建对应的Entiy文件,同时还要设置变量,非常麻烦。所以想着能不能创建一个像make:controller那样的命令生成Entity文件。

laravel里的 php artisan make:model这样的创建文件命令,都是继承自Illuminate\Console\GeneratorCommand.而实现这样的命令的原理其实很简单:

先写好一个范本文件,然后定义关键字,最后在command里将关键字替换成我们想要的内容.

模版文件(stub)

make:command来看:他的模版是model.stub,位于vendor\laravel\framework\src\Illuminate\Foundation\Console\stubs\model.stub.

<?php

namespace DummyNamespace;

use Illuminate\Database\Eloquent\Model;

class DummyClass extends Model
{
    //
}

model.stub来看,当我们利用php artisan make:model创建模型时,只是替换了命名空间关键字DummyNamespace和类名关键字DummyClass.

GeneratorCommand

make:model命令对应的类是ModelMakeCommand,位于model.stub的父级目录下。内容有点多,就不贴了,有兴趣可以去看下。直接看它的父类Illuminate\Console\GeneratorCommand.

// 核心代码 
public function handle()
{
    // 拼接命名空间
    $name = $this->qualifyClass($this->getNameInput());

    // 获取文件存储位置
    $path = $this->getPath($name);

    // 判断文件是否存在,存在则抛出错误
    if ((! $this->hasOption('force') || ! $this->option('force')) && $this->alreadyExists($this->getNameInput())) {
        $this->error($this->type.' already exists!');

        return false;
    }

    // 生成文件
    $this->makeDirectory($path);

    // 替换模版中的关键字,如:命令空间和类名
    $this->files->put($path, $this->buildClass($name));

    $this->info($this->type.' created successfully.');
}

// 编辑模版内容
protected function buildClass($name)
{
    // 获取模版文件内容
    $stub = $this->files->get($this->getStub()); 

    return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);
}

// 替换命名空间 DummyRootNamespace
protected function replaceNamespace(&$stub, $name)
{
    // 拼接命名空间
    $stub = str_replace(
        ['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'],
        [$this->getNamespace($name), $this->rootNamespace(), config('auth.providers.users.model')],
        $stub
    );

    return $this;
}

// 替换类名 DummyClass
protected function replaceClass($stub, $name)
{ 
    $class = str_replace($this->getNamespace($name).'\\', '', $name);

    return str_replace('DummyClass', $class, $stub);
}

通过源码可以看出,创建文件就是替换模版中的关键字就行了。在这个基础上我们可以实现一些命令来生成我们想要的文件。


实现 create:entity 命令

1. 创建模版
<?php

namespace DummyNamespace;

class DummyClass extends Entity
{
// 自定义需要替换的内容关键字
AAA
}

2. 实现command

class CreateEntity extends GeneratorCommand
{
    protected $signature = 'create:entity {name}';

    protected $description = '自动生成Model Entity 实例';

    // 数据库类型对照
    public static $dictionary = [
        'string' => ['char', 'text'],
        'int' => ['int','numeric'],
        'float' => ['double','float','decimal']
    ];

    protected $type = 'entity';

    /**
     * 设置模板地址
     * @return string
     */
    protected function getStub()
    {
        return __DIR__.'/stubs/Entity.stub';
    }

    /**
     * 设置命名空间,以及文件路径
     * @param string $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace.'\Repositories\Entitys'; //偷懒、直接写死
    }

    /**
     * 设置类名和自定义替换内容
     * @param string $stub
     * @param string $name
     * @return string
     */
    protected function replaceClass($stub, $name)
    {

        $stub = $this->replaceCustomizeSetting($stub); //替换自定义内容

        return parent::replaceClass($stub, $name);
    }

    /**
     * 替换自定义内容
     * @param $stub
     * @return mixed
     */
    protected function replaceCustomizeSetting($stub){

        //将输入的类名处理成表名
        $name =  $this->getNameInput();
        $name = rtrim($name,'E');
        $tableName = strtolower(trim(preg_replace("/[A-Z]/", "_\\0",$name), "_")); //驼峰变成小写加_

        $info = collect(\DB::select("desc rxt_".$tableName.";"))->toArray(); //获取表字段和类型列表
        $list = [];
        foreach ($info as $key => $value){ //转成二维数组
            $arr = collect($info[$key])->toArray();
            if($arr['Field'] == 'deleted_at') continue;
            array_push($list, $arr);
        }
        $fieldExample = "    /**  \r\n    * @var type isNull \r\n    */ \r\n    public \$fieldName;\r\n";
        $result = null;
        foreach ($list as $item){
            $result = $result.$fieldExample;
            foreach (static::$dictionary as $key => $value){
                foreach ($value as $a => $b){
                    if(strstr($item['Type'], $b)){
                        $result = str_replace('type', $key, $result);
                    }
                }
            }
            $isNull = $item['Null'] == 'YES' ? '|null' : '';
            $result = str_replace('isNull', $isNull, $result);
            $result = str_replace('fieldName', $item['Field'], $result);

        }

        return str_replace('AAA', $result, $stub);
    }

}
本作品采用《CC 协议》,转载必须注明作者和本文链接
Egfly
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!