最近用 lumen 写服务端api ,因为我在 model 和 controller 之间加了一个抽象层(repository),所以需要频繁新建不同的 repository,能不能自己定义个
php artisan make:repository
命令来帮助我自行创建呢?
需求
自动在 App\Repository
下新建新的 XxxRepository.php
文件,同时可以实现以下功能
- 可以指定
use
的 model - 自动创建
index()
,getOne()
等方法
最后的指令应该是形如php artisan make:repository XxxRepository --model=Xxx
查看laravel 的实现方式
在namespace Illuminate\Foundation\Console\ModelMakeCommand
,这里有现成的MakeModel
例子:
$name
属性指定了 command 名称getStub()
方法返回 文件模板 的绝对路径getDefaultNamespace()
返回默认命令空间getOptions()
获取参数fire()
方法执行指令逻辑
新建command
lumen 没有make command
,于是手动在app\repository\Commands
下新建文件MakeRepository.php
:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class MakeRepository extends Command {
protected $signature = 'make:repository {repository}';
protected $description = 'make a new repository.';
public function __construct()
{
parent::__construct();
}
public function handle()
{
echo "make a new repository!\n";
}
}
并在App\Console\Kernel
中注册,修改$commands
protected $commands = [
\App\Console\Commands\MakeRepository::class,
];
新建stub
在app/Console/Commands
下新建stubs文件夹,并在它里面新建repository.stub
代码
<?php
namespace App\Repositorys;
use App\Models\$model_name;
class $class_name extends Repository{
public static function getAll(){
}
}
修改MakeRepository
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Composer;
class MakeRepository extends Command {
/**
* The name and signature of the console command.
*
* @var string
*/
// protected $signature = 'make:repository';
protected $signature = 'make:repository {repository} {--model=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'make a new repository.';
/**
* @param mixed */
protected $type = 'Repository';
public function __construct(Filesystem $filesystem, Composer $composer) {
parent::__construct();
$this->files = $filesystem;
$this->composer = $composer;
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle(){
$argument = $this->argument('repository');
$option = $this->option('model');
//自动生成RepositoryInterface和Repository文件
$this->writeRepository($argument, $option);
//重新生成autoload.php文件
$this->composer->dumpAutoloads();
}
private function writeRepository($repository, $model){
if($this->createRepository($repository, $model)){
//若生成成功,则输出信息
$this->info('Success to make a '.ucfirst($repository).' Repository');
}
}
private function createRepository($repository, $model) {
// getter/setter 赋予成员变量值
$this->setRepository($repository);
$this->setModel($model);
// 创建文件存放路径, Repository放在app/Repositorys里
$this->createDirectory();
// 生成两个文件
return $this->createClass();
}
private function createClass() {
//渲染模板文件,替换模板文件中变量值
$template = $this->templateStub();
return $this->files->put($this->getPath(), $template);
}
private function getPath() {
// 两个模板文件,对应的两个路径
$path = $this->getDirectory().DIRECTORY_SEPARATOR.$this->getRepositoryName().'.php';
return $path;
}
private function getRepositoryName() {
// 根据输入的repository变量参数,是否需要加上'Repository'
$repositoryName = $this->getRepository();
if((strlen($repositoryName) <= strlen('Repository')) || strrpos($repositoryName, 'Repository', -11)){
$repositoryName .= 'Repository';
}
return $repositoryName;
}
public function setRepository($repository) {
$this->repository = $repository;
}
public function getRepository() {
return $this->repository;
}
public function setModel($model) {
$this->model = $model;
}
private function templateStub() {
// 获取模板文件
$stub = $this->getStub();
// 获取需要替换的模板文件中变量
$templateData = $this->getTemplateData();
return $this->getRenderStub($templateData, $stub);
}
private function getTemplateData(){
return [
'class_name' => $this->getRepositoryName(),
'model_name' => $this->getModelName(),
];
}
private function getModelName() {
$modelName = $this->getModel();
if(isset($modelName) && !empty($modelName)){
$modelName = ucfirst($modelName);
}else{
// 若option选项没写,则根据repository来生成Model Name
$modelName = $this->getModelFromRepository();
}
return $modelName;
}
private function getModelFromRepository() {
$repository = strtolower($this->getRepository());
$repository = str_replace('repository', '', $repository);
return ucfirst($repository);
}
private function getRenderStub($templateData, $stub) {
foreach ($templateData as $search => $replace) {
$stub = str_replace('$'.$search, $replace, $stub);
}
return $stub;
}
private function createDirectory() {
$directory = $this->getDirectory();
//检查路径是否存在,不存在创建一个,并赋予775权限
if(! $this->files->isDirectory($directory)){
return $this->files->makeDirectory($directory, 0755, true);
}
}
private function getDirectory() {
return dirname(dirname(__DIR__)).'/Repositorys';
}
/**
* @return mixed
*/
public function getModel(){
return $this->model;
}
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub() {
return $this->files->get(__DIR__.'/stubs/repository.stub');
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace;
}
}
测试
$ php artisan make:repository TestRepository --model=TestModel