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[]*/publicfunctionall($columns=array('*')){return$this->$model_var_name->all($columns);}/*** @param int $perPage* @param array $columns* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator*/publicfunctionpaginate($perPage= 15,$columns=array('*')){return$this->$model_var_name->paginate($perPage,$columns);}/*** Create a new $model_var_name* @param array $data* @return \$model_namespace*/publicfunctioncreate(array$data){return$this->$model_var_name->create($data);}/*** Update a $model_var_name* @param array $data* @param $id* @return \$model_namespace*/publicfunctionupdate($data= [],$id){return$this->$model_var_name->whereId($id)->update($data);}/*** Store a $model_var_name* @param array $data* @return \$model_namespace*/publicfunctionstore($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*/publicfunctiondelete($data= [],$id){$this->$model_var_name->whereId($id)->delete();}/*** @param $id* @param array $columns* @return array|\Illuminate\Database\Eloquent\Collection|static[]*/publicfunctionfind($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[]*/publicfunctionfindBy($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/Kernelprotected$commands= [// Commands\Inspire::class,// Commands\RedisSubscribe::class,// Commands\RedisPublish::class,// Commands\MakeTestRepositoryCommand::class,Commands\MakeRepositoryCommand::class,];
然后輸入php artisan命令后就能看到這個make:repository命令了。

自動化生成RepositoryInterface和Repository文件
在MakeRepositoryCommand.php命令執行文件里寫上模板自動生成邏輯,代碼也不長,有些邏輯也有注釋,可看:
useConfig;useIlluminate\Console\Command;useIlluminate\Filesystem\Filesystem;useIlluminate\Support\Composer;classMakeRepositoryCommandextendsCommand{/*** 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*/publicfunction__construct(Filesystem$filesystem, Composer$composer){parent::__construct();$this->files =$filesystem;$this->composer =$composer;}/*** Execute the console command.** @return mixed*/publicfunctionhandle(){//獲取repository和model兩個參數值$argument=$this->argument('repository');$option=$this->option('model');//自動生成RepositoryInterface和Repository文件$this->writeRepositoryAndInterface($argument,$option);//重新生成autoload.php文件$this->composer->dumpAutoloads();}privatefunctionwriteRepositoryAndInterface($repository,$model){if($this->createRepository($repository,$model)){//若生成成功,則輸出信息$this->info('Success to make a '.ucfirst($repository).' Repository and a '.ucfirst($repository).'Interface Interface');}}privatefunctioncreateRepository($repository,$model){// getter/setter 賦予成員變量值$this->setRepository($repository);$this->setModel($model);// 創建文件存放路徑, RepositoryInterface放在app/Repositories,Repository個人一般放在app/Repositories/Eloquent里$this->createDirectory();// 生成兩個文件return$this->createClass();}privatefunctioncreateDirectory(){$directory=$this->getDirectory();//檢查路徑是否存在,不存在創建一個,并賦予775權限if(!$this->files->isDirectory($directory)){return$this->files->makeDirectory($directory, 0755, true);}}privatefunctiongetDirectory(){returnConfig::get('repository.directory_eloquent_path');}privatefunctioncreateClass(){//渲染模板文件,替換模板文件中變量值$templates=$this->templateStub();$class= null;foreach($templatesas$key=>$template) {//根據不同路徑,渲染對應的模板文件$class=$this->files->put($this->getPath($key),$template);}return$class;}privatefunctiongetPath($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;}privatefunctiongetInterfaceDirectory(){returnConfig::get('repository.directory_path');}privatefunctiongetRepositoryName(){// 根據輸入的repository變量參數,是否需要加上'Repository'$repositoryName=$this->getRepository();if((strlen($repositoryName) <strlen('Repository')) ||strrpos($repositoryName,'Repository', -11)){$repositoryName.='Repository';}return$repositoryName;}privatefunctiongetInterfaceName(){return$this->getRepositoryName().'Interface';}/*** @return mixed*/publicfunctiongetRepository(){return$this->repository;}/*** @param mixed $repository*/publicfunctionsetRepository($repository){$this->repository =$repository;}/*** @return mixed*/publicfunctiongetModel(){return$this->model;}/*** @param mixed $model*/publicfunctionsetModel($model){$this->model =$model;}privatefunctiontemplateStub(){// 獲取兩個模板文件$stubs=$this->getStub();// 獲取需要替換的模板文件中變量$templateData=$this->getTemplateData();$renderStubs= [];foreach($stubsas$key=>$stub) {// 進行模板渲染$renderStubs[$key] =$this->getRenderStub($templateData,$stub);}return$renderStubs;}privatefunctiongetStub(){$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;}privatefunctiongetTemplateData(){$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;}privatefunctiongetRenderStub($templateData,$stub){foreach($templateDataas$search=>$replace) {$stub=str_replace('$'.$search,$replace,$stub);}return$stub;}privatefunctiongetModelName(){$modelName=$this->getModel();if(isset($modelName) && !empty($modelName)){$modelName= ucfirst($modelName);}else{// 若option選項沒寫,則根據repository來生成Model Name$modelName=$this->getModelFromRepository();}return$modelName;}privatefunctiongetModelFromRepository(){$repository=strtolower($this->getRepository());$repository=str_replace('repository','',$repository);returnucfirst($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*/namespaceApp\Repositories\Eloquent;useApp\Shop;useApp\Repositories\ShopRepositoryInterface;classShopRepositoryimplementsShopRepositoryInterface{/*** @var \App\Shop*/public$shop;publicfunction__construct(Shop$shop){$this->shop =$shop;}/*** @param array $columns* @return \Illuminate\Database\Eloquent\Collection|static[]*/publicfunctionall($columns=array('*')){return$this->shop->all($columns);}/*** @param int $perPage* @param array $columns* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator*/publicfunctionpaginate($perPage= 15,$columns=array('*')){return$this->shop->paginate($perPage,$columns);}/*** Create a new shop* @param array $data* @return \App\Shop*/publicfunctioncreate(array$data){return$this->shop->create($data);}/*** Update a shop* @param array $data* @param $id* @return \App\Shop*/publicfunctionupdate($data= [],$id){return$this->shop->whereId($id)->update($data);}/*** Store a shop* @param array $data* @return \App\Shop*/publicfunctionstore($data= []){$this->shop->id =$data['id'];//...$this->shop->save();}/*** Delete a shop* @param array $data* @param $id* @return \App\Shop*/publicfunctiondelete($data= [],$id){$this->shop->whereId($id)->delete();}/*** @param $id* @param array $columns* @return array|\Illuminate\Database\Eloquent\Collection|static[]*/publicfunctionfind($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[]*/publicfunctionfindBy($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配置調整等,特別適合新手朋友們體驗建站,搭建一個屬于個人的博客。...

