Laravel学习笔记之Artisan命令生成自定义模板的方法
本文主要讲述Laravel的Artisan命令来实现自定义模板,就如经常输入的php artisan make:controller ShopController就会自动生成一个ShopController.php模板文件一样,通过命令生...
本文主要讲述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配置文件里了:
<?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文件,的确是我想要的模板文件:
总结:本文主要用Laravel的Artisan命令来自动生成个人需要的模板,减少平时开发中重复劳动。就像Laravel自带了很多模板生成命令,用起来会节省很多时间。这是作者在平时开发中遇到的问题,通过利用Laravel Artisan命令解决了,所以Laravel还是挺好玩的。有兴趣的可以把代码扒下来玩一玩,并根据你自己想要的模板做修改。这两天想就Repository模式封装Model逻辑的方法和好处聊一聊,到时见。希望对大家的学习有所帮助
<?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
;
}
}
-
PHP判断电子邮件是否正确的简单方法介绍
本篇内容里小编给大家整理了一篇关于php判断电子邮件是否正确方法,需要的朋友们参考下。PHP判断电子邮件是否正确即是否有效,是我们PHP面试过程中常见考题之一。我们可以使用P...
-
当laravel获取不到session的三种解决办法
说到PHP估计有些朋友还有些熟悉,但是对于PHP下的laravel就表示不知道了。有些人因为需要使用到laravel时,却发现过程中出现了问题,那就是session无法获取了,鼓捣了半天也不...
-
在PHP中进行curl开启操作的具体教程
相信大家对于PHP都并不陌生了,毕竟PHP吸收了C语言、Java里的许多优点,作为一款脚本语言还是收到很多程序员朋友的喜爱的。PHP里的curl函数库还是非常实用的,今天小编就给大...
-
PHP中间件ICE,ICE的安装配置,ICE常见编译和运行(异常)错误
ICE(Internet Communications Engine)是Zeroc提供的一款高性能的中间件。使用ICE能使得php(或c++,java,python)与java,c++,.net,python等进行交互。基于ICE可以实现电信级的...
-
win7下手动配置apache+php+mysql记
本来想学学php,于是就想搭建web服务器和sql环境,结果浪费掉了不少时间。大致的总结下,也算是长个记性。使用的安装包分别是httpd-2.2.22-win32-x86-no_ssl.msi,php-5.2.5-Win32.zip和mysql-installer-communit...
-
OneinStack一键PHP/JAVA/HHVM安装及VPS手动安装LNMP
说起LNMP,多数人应该知道lnmp.org站长开发的LNMP一键安装包,该脚本虚拟主机管理、FTP用户管理、Nginx、MySQL/MariaDB、PHP的升级、常用缓存组件的安装、重置MySQLroot密...
-
PHP遭弃用!Wordpress.com开源并转用Javascript
据外媒消息称,Wordpress母公司Automattic将完全重写Wordpress.com网站代码,并将此项计划命名为“Calypso”,代码开源并被托管于Github平台。此外,最新的wordpress.com放...
-
分享6款国内、外开源PHP轻论坛CMS程序
随着移动互联网对于传统互联网的冲击,用户群更加注重信息的及时性和有效性的简便分享和获取,传统的社区模式经过多年的积累沉淀很深,尤其对于新兴的社区用户群和站长来说...
-
【php爬虫】百万级别知乎用户数据爬取与分析
本程序是抓取知乎的用户数据,要能访问用户个人页面,需要用户登录后的才能访问。当我们在浏览器的页面中点击一个用户头像链接进入用户个人中心页面的时候,之所以能够看到...
-
FreeHostia免费PHP空间中文面板250MB空间6GB流量
FreeHostia这类空间提供中文主机控制面板,有域名绑定、MysqL管理、在线文件管理器、PHP配置调整等,特别适合新手朋友们体验建站,搭建一个属于个人的博客。...