说明:本文主要讲述Laravel的Artisan命令来实现自定义模板,就如经常输入的php artisan make:controller ShopController就会自动生成一个ShopController.php模板文件一样,通过命令生成模板也会提高开发效率。同时,作者会将开发过程中的一些截图和代码黏上去,提高阅读效率。

备注:个人平时在写Repository代码时会这样写,如先写上ShopRepositoryInterface并定义好接口方法如all()、create()、update()、delete()、findBy()等等,然后再写上接口对应的实现ShopRepository并注入对应的Model即Shop。别的PostRepository、TagRepository也会是这么写(当然,对于很多重用的Repository方法可以集体拿到AbstractRepository抽象类里供子类继承,实现代码复用)。那能不能直接命令行生成模板文件呢,就不用自己一个个的写了,就像输入php artisan make:controller PostController给我一个Controller模板来。

关于使用Repository模式来封装下Model逻辑,不让Controller里塞满了很多Model逻辑,这样做是有很多好处的,最主要的就是好测试和代码架构清晰,也符合SOLID原则。如果使用PHPUnit来做测试就知道了为啥说好测试了。SegmentFault上也有相关的文章描述。作者也打算最近新开一篇文章聊一聊这个,PHPUnit也打算过段时间聊一聊。

个人研究了下Artisan命令行,是可以的。经过开发后,结果是输入自定义指令php artisan make:repository PostRepository --model=Post(这个option可要可不要),就会帮我生成一个PostRepositoryInterface和对应的接口实现PostRepository。

模板文件Stub

由于个人需要生成一个RepositoryInterface和对应接口实现Repository,那就需要两个模板文件了。在resources/stubs新建两个模板文件,以下是个人经常需要的两个模板文件(你可以自定义):

/**

* @param array $columns

* @return \Illuminate\Database\Eloquent\Collection|static[]

*/

public function all($columns = array('*'))

{

return $this->$model_var_name->all($columns);

}

/**

* @param int $perPage

* @param array $columns

* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator

*/

public function paginate($perPage = 15, $columns = array('*'))

{

return $this->$model_var_name->paginate($perPage, $columns);

}

/**

* Create a new $model_var_name

* @param array $data

* @return \$model_namespace

*/

public function create(array $data)

{

return $this->$model_var_name->create($data);

}

/**

* Update a $model_var_name

* @param array $data

* @param $id

* @return \$model_namespace

*/

public function update($data = [], $id)

{

return $this->$model_var_name->whereId($id)->update($data);

}

/**

* Store a $model_var_name

* @param array $data

* @return \$model_namespace

*/

public function store($data = [])

{

$this->$model_var_name->id = $data['id'];

//...

$this->$model_var_name->save();

}

/**

* Delete a $model_var_name

* @param array $data

* @param $id

* @return \$model_namespace

*/

public function delete($data = [], $id)

{

$this->$model_var_name->whereId($id)->delete();

}

/**

* @param $id

* @param array $columns

* @return array|\Illuminate\Database\Eloquent\Collection|static[]

*/

public function find($id, $columns = array('*'))

{

$$model_name = $this->$model_var_name->whereId($id)->get($columns);

return $$model_name;

}

/**

* @param $field

* @param $value

* @param array $columns

* @return \Illuminate\Database\Eloquent\Collection|static[]

*/

public function findBy($field, $value, $columns = array('*'))

{

$$model_name = $this->$model_var_name->where($field, '=', $value)->get($columns);

return $$model_name;

}

}

模板文件里包括参数,这些参数将会根据命令行中输入的参数和选项被相应替换:

['$repository_namespace', '$model_namespace', '$repository_interface_namespace', '$repository_interface', '$class_name', '$model_name', '$model_var_name']

Artisan命令生成Repository模板文件

生成Artisan命令并注册

Laravel提供了Artisan命令自定义,输入指令:

php artisan make:console MakeRepositoryCommand

然后改下签名和描述:

// app/Console/Commands/MakeRepositoryCommand

/**

* The name and signature of the console command.

*

* @var string

*/

protected $signature = 'make:repository {repository} {--model=}';

/**

* The console command description.

*

* @var string

*/

protected $description = 'Make a repository and interface';

这里{repository}是必填参数并指明(选填参数加个?,就和路由参数一样),将会被$this->argument('repository')方法捕捉到,{--model=}是选项,可填可不填,将会被$this->option('model')方法捕捉到。填上这个命令的描述,最后在Console的Kernel里注册下命令:

// app/Console/Kernel

protected $commands = [

// Commands\Inspire::class,

// Commands\RedisSubscribe::class,

// Commands\RedisPublish::class,

// Commands\MakeTestRepositoryCommand::class,

Commands\MakeRepositoryCommand::class,

];

然后输入php artisan命令后就能看到这个make:repository命令了。

自动化生成RepositoryInterface和Repository文件

在MakeRepositoryCommand.php命令执行文件里写上模板自动生成逻辑,代码也不长,有些逻辑也有注释,可看:

use Config;

use Illuminate\Console\Command;

use Illuminate\Filesystem\Filesystem;

use Illuminate\Support\Composer;

class MakeRepositoryCommand extends Command

{

/**

* The name and signature of the console command.

*

* @var string

*/

protected $signature = 'make:repository {repository} {--model=}';

/**

* The console command description.

*

* @var string

*/

protected $description = 'Make a repository and interface';

/**

* @var

*/

protected $repository;

/**

* @var

*/

protected $model;

/**

* Create a new command instance.

*

* @param Filesystem $filesystem

* @param Composer $composer

*/

public function __construct(Filesystem $filesystem, Composer $composer)

{

parent::__construct();

$this->files = $filesystem;

$this->composer = $composer;

}

/**

* Execute the console command.

*

* @return mixed

*/

public function handle()

{

//获取repository和model两个参数值

$argument = $this->argument('repository');

$option = $this->option('model');

//自动生成RepositoryInterface和Repository文件

$this->writeRepositoryAndInterface($argument, $option);

//重新生成autoload.php文件

$this->composer->dumpAutoloads();

}

private function writeRepositoryAndInterface($repository, $model)

{

if($this->createRepository($repository, $model)){

//若生成成功,则输出信息

$this->info('Success to make a '.ucfirst($repository).' Repository and a '.ucfirst($repository).'Interface Interface');

}

}

private function createRepository($repository, $model)

{

// getter/setter 赋予成员变量值

$this->setRepository($repository);

$this->setModel($model);

// 创建文件存放路径, RepositoryInterface放在app/Repositories,Repository个人一般放在app/Repositories/Eloquent里

$this->createDirectory();

// 生成两个文件

return $this->createClass();

}

private function createDirectory()

{

$directory = $this->getDirectory();

//检查路径是否存在,不存在创建一个,并赋予775权限

if(! $this->files->isDirectory($directory)){

return $this->files->makeDirectory($directory, 0755, true);

}

}

private function getDirectory()

{

return Config::get('repository.directory_eloquent_path');

}

private function createClass()

{

//渲染模板文件,替换模板文件中变量值

$templates = $this->templateStub();

$class = null;

foreach ($templates as $key => $template) {

//根据不同路径,渲染对应的模板文件

$class = $this->files->put($this->getPath($key), $template);

}

return $class;

}

private function getPath($class)

{

// 两个模板文件,对应的两个路径

$path = null;

switch($class){

case 'Eloquent':

$path = $this->getDirectory().DIRECTORY_SEPARATOR.$this->getRepositoryName().'.php';

break;

case 'Interface':

$path = $this->getInterfaceDirectory().DIRECTORY_SEPARATOR.$this->getInterfaceName().'.php';

break;

}

return $path;

}

private function getInterfaceDirectory()

{

return Config::get('repository.directory_path');

}

private function getRepositoryName()

{

// 根据输入的repository变量参数,是否需要加上'Repository'

$repositoryName = $this->getRepository();

if((strlen($repositoryName) < strlen('Repository')) || strrpos($repositoryName, 'Repository', -11)){

$repositoryName .= 'Repository';

}

return $repositoryName;

}

private function getInterfaceName()

{

return $this->getRepositoryName().'Interface';

}

/**

* @return mixed

*/

public function getRepository()

{

return $this->repository;

}

/**

* @param mixed $repository

*/

public function setRepository($repository)

{

$this->repository = $repository;

}

/**

* @return mixed

*/

public function getModel()

{

return $this->model;

}

/**

* @param mixed $model

*/

public function setModel($model)

{

$this->model = $model;

}

private function templateStub()

{

// 获取两个模板文件

$stubs = $this->getStub();

// 获取需要替换的模板文件中变量

$templateData = $this->getTemplateData();

$renderStubs = [];

foreach ($stubs as $key => $stub) {

// 进行模板渲染

$renderStubs[$key] = $this->getRenderStub($templateData, $stub);

}

return $renderStubs;

}

private function getStub()

{

$stubs = [

'Eloquent' => $this->files->get(resource_path('stubs/Repository').DIRECTORY_SEPARATOR.'Eloquent'.DIRECTORY_SEPARATOR.'repository.stub'),

'Interface' => $this->files->get(resource_path('stubs/Repository').DIRECTORY_SEPARATOR.'repository_interface.stub'),

];

return $stubs;

}

private function getTemplateData()

{

$repositoryNamespace = Config::get('repository.repository_namespace');

$modelNamespace = 'App\\'.$this->getModelName();

$repositoryInterfaceNamespace = Config::get('repository.repository_interface_namespace');

$repositoryInterface = $this->getInterfaceName();

$className = $this->getRepositoryName();

$modelName = $this->getModelName();

$templateVar = [

'repository_namespace' => $repositoryNamespace,

'model_namespace' => $modelNamespace,

'repository_interface_namespace' => $repositoryInterfaceNamespace,

'repository_interface' => $repositoryInterface,

'class_name' => $className,

'model_name' => $modelName,

'model_var_name' => strtolower($modelName),

];

return $templateVar;

}

private function getRenderStub($templateData, $stub)

{

foreach ($templateData as $search => $replace) {

$stub = str_replace('$'.$search, $replace, $stub);

}

return $stub;

}

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);

}

}

这里把一些常量值放在config/repository.php配置文件里了:

/**

* Created by PhpStorm.

* User: liuxiang

* Date: 16/6/22

* Time: 17:06

*/

return [

'directory_path' => 'App'.DIRECTORY_SEPARATOR.'Repositories',

'directory_eloquent_path' => 'App'.DIRECTORY_SEPARATOR.'Repositories'.DIRECTORY_SEPARATOR.'Eloquent',

'repository_namespace' => 'App\Repositories\Eloquent',

'repository_interface_namespace' => 'App\Repositories',

];

运行一下看可不可以吧,这里截个图:

It is working!!!

是可以生成RepositoryInterface和对应的接口实现文件,这里一个是加了--model选项一个没加的,没加的话这里第一个指令就默认Model的名称是Shop。

生成的文件内容不截图了,看下新生成的ShopRepository.php文件,的确是我想要的模板文件:

/**

* Created by PhpStorm.

* User: liuxiang

*/

namespace App\Repositories\Eloquent;

use App\Shop;

use App\Repositories\ShopRepositoryInterface;

class ShopRepository implements ShopRepositoryInterface

{

/**

* @var \App\Shop

*/

public $shop;

public function __construct(Shop $shop)

{

$this->shop = $shop;

}

/**

* @param array $columns

* @return \Illuminate\Database\Eloquent\Collection|static[]

*/

public function all($columns = array('*'))

{

return $this->shop->all($columns);

}

/**

* @param int $perPage

* @param array $columns

* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator

*/

public function paginate($perPage = 15, $columns = array('*'))

{

return $this->shop->paginate($perPage, $columns);

}

/**

* Create a new shop

* @param array $data

* @return \App\Shop

*/

public function create(array $data)

{

return $this->shop->create($data);

}

/**

* Update a shop

* @param array $data

* @param $id

* @return \App\Shop

*/

public function update($data = [], $id)

{

return $this->shop->whereId($id)->update($data);

}

/**

* Store a shop

* @param array $data

* @return \App\Shop

*/

public function store($data = [])

{

$this->shop->id = $data['id'];

//...

$this->shop->save();

}

/**

* Delete a shop

* @param array $data

* @param $id

* @return \App\Shop

*/

public function delete($data = [], $id)

{

$this->shop->whereId($id)->delete();

}

/**

* @param $id

* @param array $columns

* @return array|\Illuminate\Database\Eloquent\Collection|static[]

*/

public function find($id, $columns = array('*'))

{

$Shop = $this->shop->whereId($id)->get($columns);

return $Shop;

}

/**

* @param $field

* @param $value

* @param array $columns

* @return \Illuminate\Database\Eloquent\Collection|static[]

*/

public function findBy($field, $value, $columns = array('*'))

{

$Shop = $this->shop->where($field, '=', $value)->get($columns);

return $Shop;

}

}

总结:本文主要用Laravel的Artisan命令来自动生成个人需要的模板,减少平时开发中重复劳动。就像Laravel自带了很多模板生成命令,用起来会节省很多时间。这是作者在平时开发中遇到的问题,通过利用Laravel Artisan命令解决了,所以Laravel还是挺好玩的。有兴趣的可以把代码扒下来玩一玩,并根据你自己想要的模板做修改。这两天想就Repository模式封装Model逻辑的方法和好处聊一聊,到时见。希望对大家的学习有所帮助,也希望大家多多支持脚本之家

php自动生成模板文件,Laravel学习笔记之Artisan命令生成自定义模板的方法相关推荐

  1. 学习笔记:jmeter-CLI命令生成jtl文件及html文件

    背景:jmeter学习中,CLI:无界面模式 负载测试使用CLI模式,而非GUI模式(GUI模式仅用于创建测试计划和调试脚本) 原因:性能测试多用户并发,消耗资源较高:GUI图像界面本身占用资源,导致 ...

  2. jxls读取模板导出Excel学习笔记

    jxls读取模板导出Excel学习笔记 ​ jxls是一个简单的.轻量级的excel导出库,使用特定的标记在excel模板文件中来定义输出格式和布局.除此以外,java中成熟的excel导出工具有po ...

  3. VBA学习笔记(9)--生成点拨(1)

    VBA学习笔记(9)--生成点拨(1) 说明(2017.3.26): 1. 还没写完,写到新建文件夹了,下一步新建word,重命名,查找点拨,把点拨复制进去,因为要给点拨编号,应该会很麻烦 1 Pub ...

  4. Vue学习笔记: Vue + Element-ui搭建后台管理系统模板

    Vue学习笔记: Vue + Element-ui搭建后台管理系统模板 技术:Vue + Element-ui 功能:后台管理系统基础模板,路由配置,加载页面进度条,请求响应拦截器的封装等 页面预览: ...

  5. Laravel学习笔记汇总——Collection方法详解

    ## Laravel学习笔记汇总--Collection方法详解 本文参考:https:// laravel.com/docs/8.x/collections // 返回整个底层的数组 collect ...

  6. 从滚动条到画布的几个代码文件——Python学习笔记之十七

    从滚动条到画布的几个代码文件--Python学习笔记之十七 这一章的继续学习,比在前的照片涉及代码要轻松一些,代码打完后的预期结果总能实现.特别让人欣慰的一点,文本上的文字理解好像上了一个台阶,不用多 ...

  7. 设置默认settings文件_Django 学习笔记系列 之 settings.py 设定

    我们在上⼀节中已经创建了⼀个新的功能应⽤,名为newapp_01. 在这一节中,我们要对整个django项目的settings.py文件进行设定.这里settings.py 的主要功能是管理djang ...

  8. Angular快速学习笔记(3) -- 组件与模板

    1. 显示数据 在 Angular 中最典型的数据显示方式,就是把 HTML 模板中的控件绑定到 Angular 组件的属性. 使用插值表达式显示组件属性 要显示组件的属性,最简单的方式就是通过插值表 ...

  9. linux添加自己的库,Linux学习笔记——例叙makefile 增加自定义共享库

    Linux学习笔记--例说makefile 增加自定义共享库 0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己 ...

  10. ROS 学习笔记(三):自定义服务数据srv+server+client 示例运行

    ROS 学习笔记(三):自定义服务数据srv+Server+Client 示例运行 一.自定义服务数据: 1.向功能包添加自定义服务文件(AddTwoInts.srv) cd ~/catkin_ws/ ...

最新文章

  1. 基于 Android NDK 的学习之旅-----JNI 数据类型
  2. 能用python做信号处理吗_Python中的信号处理
  3. SpringBoot实现的学生选课管理系统
  4. 网络安全实验室CTF—注入关 writeup
  5. GUI图形用户界面设计
  6. 使用计算机软件,计算机使用软件
  7. 体验服务器windows系统,经典重温:Windows 95操作系统体验
  8. 安卓执法仪录像之进程间共享内存
  9. c语言人机互动编程,单片机人机交互系统的C语言编程简介.ppt
  10. Linux 往事:一个不会像 GNU 那样大而专业的 OS 是如何成为主流的?
  11. springboot(九)--统一异常处理(500)、错误页处理(404)
  12. 飞屋环游记中英文对白
  13. 微型计算机控制技术 西安交大,西安交通大学18年9月课程考试《计算机控制技术》作业考核试题满分...
  14. 模拟看门狗如何实现?
  15. 小程序创业,有哪些行业方向可以选?
  16. 【PSO】熟悉PSO算法
  17. 解Error:(3, 32) java: 无法访问org.springframework.boot.SpringApplication 错误的类文件: /D:/Program/maven-repos
  18. 【论文简述】UCS-Net:Deep Stereo using Adaptive Thin Volume Representation with Uncertainty Awareness(CVPR)
  19. IBM WebBIOS配置
  20. 年薪50w+的软件测试工程师是怎么炼成的?

热门文章

  1. 2017年 外牌转沪牌 攻略 (沪南路车管所)
  2. 计算机音乐制作旋律教学,旋律创作的基本规律 管窥小学音乐旋律创作教学
  3. 实现Excel下拉自动填补对应内容到后面单元格
  4. URLConnection 传入参数
  5. Python tolist()用法
  6. Air780E模块PPP应用开发指南
  7. vscode如何配置java环境_VSCode 配置Java环境
  8. 由对称性知定点一定在x轴上_圆锥曲线解答题的经典答案:由椭圆的对称性知,定点在x轴上?...
  9. 简述力法计算弹性固定无铰拱的原理_隧道结构力学计算
  10. 电路图中电阻分类字母速记说明图文