配置即一切
一切皆於需求,后台從0開始搭建,但是寫了一兩個頁面后發現太多的是對單表的增刪改查操作,於是就想到了,能不能做一個快速搭建的后台。想到一句話,配置即一切。如果一個CURD后台能只進行配置就自動生成,該是多么美妙的事情,那么就開始搭建這么個結構。
首先配置文件應該怎么設計
起初想到將配置文件放到config目錄下,但是想想還是放棄了這個想法,那樣子可能會導致有一個“萬能”文件,又臭又長。那么,其次,這個功能只針對單表,所以,是不是可以將配置文件放置在Model中,后來也覺得這個想法不大好,這個配置文件是承擔頁面展示的功能的,如果放在Model中就算是入侵了Model層了。所以最后決定放在了Controller中。
最后的效果大概是什么樣子的?
后台大概會有幾個頁面:
列表頁:

列表頁中有查詢操作,編輯,刪除按鈕,新建按鈕。
新建頁面:

編輯頁面:

好了,對應這幾個頁面,我們可以設置配置項了。
基本想法是搭建一個FormController,所有以后需要配置生成后台的controller就繼承這個FormController就好了。在FormController中定義屬性:
class FormController extends BaseController { // 對應的模型 protected $model; // 所有的字段 protected $fields_all; // 列表頁顯示的字段 protected $fields_show; // 編輯頁面顯示的字段 protected $fields_edit; // 創建頁面顯示的字段 protected $fields_create; }
定義了Model,來表示這個Controller是對那個Model進行單表操作的。
定義了fields_all屬性,來將所有的字段來進行一個說明和定義。這個定義和說明就包括字段顯示名字,字段是否要進行搜索,字段類型是什么。
對於列表頁,不是所有屬性都顯示出來,所以定義一個$fields_show,這個數組存放的是$fields_all中的一些字段,用來顯示的字段。
對於編輯頁面,要顯示的字段就放在$field_edit中
對於創建頁面,要顯示的字段就放在$field_create中
好了,現在繼承FormController的類就只需要這么配置就好;
<?php // 賬號管理系統 class BadminController extends FormController { public function __construct() { $this->model = '\Badmin'; $this->fields_all = [ 'id' => [ 'show' => '序號', ], 'nickname' => [ 'show' => '昵稱', 'search' => "nickname like CONCAT('%', ?, '%')" ], 'username' => [ 'show' => '用戶名', ], 'email' => [ 'show' => '郵箱', ], 'password' => [ 'show' => '密碼', ], 'created_at' => [ 'show' => '創建時間', ], 'updated_at' => [ 'show' => '更新時間', ], ]; $this->fields_show = ['id' ,'nickname', 'username', 'email', 'created_at']; $this->fields_edit = ['nickname', 'username']; $this->fields_create = ['nickname', 'username', 'email', 'password']; parent::__construct(); } }
在構造函數中定義model,$fields_all, $fields_show, $fields_edit, $fields_create。
對於fields_all,key為數據庫對應的字段名,value為一個數組,show是顯示名,如果你在列表頁希望這個字段能進行搜索,就設置下search屬性。
路由
下面是路由,laravel中路由基本有三種:
Route::get('order/{id}',['as'=>'order.detail','uses'=>'OrderController@show']); Route::controller('preview', 'PreviewController'); Route::resource('badmin', 'BadminController');
第三種已經完全定義好了增刪改查操作,看起來能省我不少的事情,好吧,我就使用這個resource來做了。
所以在route.php中我只需要定義這么一條就ok了
// 管理員賬號管理 Route::resource('badmin', 'BadminController');
Controller
下面寫FromController中的resource方法
按照laravel的resource定義的,需要填充的方法有:

我習慣在構造函數中把一些諸如Input,全局定義的東西都share到模版中,代碼如下:
public function __construct() { // TODO:做一些基礎的判斷,如果沒有的話就拋出異常 $route = Route::currentRouteAction(); list($this->controller, $action) = explode('@', $route); View::share('controller', $this->controller); $fields_show = array(); foreach ($this->fields_show as $field) { $fields_show[$field] = $this->fields_all[$field]; } View::share('fields_show', $fields_show); $fields_edit = array(); foreach ($this->fields_edit as $field) { $fields_edit[$field] = $this->fields_all[$field]; } View::share('fields_edit', $fields_edit); $fields_create = array(); foreach ($this->fields_create as $field) { $fields_create[$field] = $this->fields_all[$field]; } View::share('fields_create', $fields_create); View::share('input', Input::all()); }
這里把controller放到外面是為了在view中可以使用諸如:
action($controller . '@destroy', $model->id),
的路徑定義
index函數:
public function index() { $model = new $this->model; $builder = $model->orderBy('id', 'desc'); $input = Input::all(); foreach ($input as $field => $value) { if (empty($value)) { continue; } if (!isset($this->fields_all[$field])) { continue; } $search = $this->fields_all[$field]; $builder->whereRaw($search['search'], [$value]); } $models = $builder->paginate(20); return View::make('form.index', [ 'models' => $models, ]); }
$builder在laravel中真是太TMD好用了,對於這里的搜索,我使用whereRaw進行prepare查詢。這里還有一個點,之前在fields_all設計的時候,我定義的直接是一個 'search' => "nickname like CONCAT('%', ?, '%')" 這里定義搜索字段的時候其實有很多種設計方法,比如定義為
‘search’ => [ 'type' => 'like', 'value' => '%?%' ]
但是考慮到使用這個FromController的都是程序員,所以這里的search直接使用預處理的語句,然后在index中直接使用whereRaw,這樣使得配置文件的易讀性增加了。
下面是
create函數:
public function create() { return View::make('form.create', []); }
store函數:
public function store() { $model = new $this->model; $model->fill(Input::all()); $model->save(); return Redirect::to(action($this->controller . '@index')); }
這里的model的fill是不是很簡單,爽到爆。當然model中還是需要定義fillable字段
edit,update,destory函數
如法炮制就好
public function edit($id) { $model = new $this->model; $model = $model->find($id); return View::make('form.edit', compact('model')); } public function update($id) { $model = new $this->model; $model = $model->find($id); $model->fill(Input::all()); $model->save(); return Redirect::to(action($this->controller . '@index')); } public function destroy($id) { $model = new $this->model; $model->destroy($id); return Redirect::to(action($this->controller . '@index')); }
View
下面就是view的編寫。

view大概就只要三個頁面,列表頁面,編輯頁面,創建頁面
列表頁面注意事項:
1 使用laravel自帶分頁,注意記得帶上本頁的輸入參數,這個時候,構造函數中share的Input就很有用了
{{$models->appends($input)->links()}}
2 可以使用laravel自帶的from操作,比如刪除操作由於需要調用HTTP的DELETE 方法,可以這么寫
{{ Form::open(array( 'id' => "delete_{$model->id}", 'url' => action($controller . '@destroy', $model->id), 'class' => 'dropdown-toggle')) }} {{ Form::hidden('_method', 'DELETE') }} {{ Form::close() }}
其實自己寫DELETE也行,就是在From表單中多傳遞一個_method隱藏域
3 搜索直接使用一個form就可以搞定了
<form class="form-inline" role="form" action="{{action($controller . '@index')}}"> @foreach ($fields_show as $field => $field_info) @if (isset($field_info['search'])) <div class="form-group"> <label class="col-sm-3 control-label">{{$field_info['show']}}</label> <div class="col-md-3"> <input name="{{$field}}" type="input" class="form-control" placeholder="" value="@if (isset($input[$field])){{$input[$field]}}@endif"> </div> </div> @endif @endforeach <input type="submit" class="btn btn-success" value="查詢" /> </form>
編輯頁面和創建頁面
簡單到只需要一個form就能搞定了
<form class="form-horizontal" role="form" action="{{action($controller . "@update", $model->id)}}" method='POST'> <input type="hidden" name="_method" value="PUT"> @foreach ($fields_edit as $field => $field_info) <div class="form-group"> <label class="col-sm-2 control-label">{{$field_info['show']}}</label> <div class="col-sm-10"> <input name="{{$field}}" type="text" class="form-control" placeholder="" value="{{$model->$field}}"> </div> </div> <div class="line line-dashed line-lg pull-in"></div> @endforeach <div class="col-sm-4 col-sm-offset-2"> <button type="submit" class="btn btn-primary">提交</button> </div> </form>
記得resource中更新的操作是要使用PUT方式,刪除的操作要使用DELETE方式。
至於view的模版,我這里使用的是一款叫notebook的模版,它是基於bootstrap的,你也可以使用其他更好看的模版來寫。
好了,至此這么個快速搭建CURD的結構就完成了。現在可以在運營人員給需求的時候,很牛逼地說,等我一分鍾,我就給你一個世界~~
后記
其實回想下,這整個結構不算復雜。配置即一切的思想能解決很多問題。但是依賴配置的路子最怕的是幾個事情:
1 配置文件過於復雜。(如果你的配置文件過於復雜,已經超過了敲代碼本身需要了解的東西,那么這個配置項的學習成本就太太太高了)
2 配置字段語意不清。(配置的字段名字和意思不對,字段名和變量名一樣重要!)
當然這個就是個初步,改進的幾個點還有
1 所有字段都使用input標簽,需要在配置中加入其它標簽類型
2 是不是考慮view中所有的東西都使用laravel自帶的form對應字段?