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