前言
現在的項目中有使用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);
}
}