【Laravel實戰】Laravel Collective 套件

本篇文章示範如何利用 Laravel Collective 套件來快速建置表單與裏頭的輸入項
Step 1.下載套件
composer require laravelcollective/html:"5.8.0"
//針對5.8版本
composer require laravelcollective/html
//針對8.x版本
Step 2.註冊provider與alias(Laravel 5.4以上非必須)
加入provider,請編輯config/app.php
在providers陣列加入以下程式碼:
Collective\\Html\\HtmlServiceProvider::class,
在aliases陣列加入以下程式碼:
'Form' => Collective\\Html\\FormFacade::class,
'Html' => Collective\\Html\\HtmlFacade::class
表單Blade撰寫範例
//resources/views/items/create.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>
新增商品
</title>
</head>
<body>
{!! Form::open(['action'=>'ItemController@store','method'=>'POST','files'=>true]) !!}
{!! Form::label('title', '標題', ['class' => 'myclass']) !!}
{!! Form::text('title', null) !!}<br><br>
{!! Form::label('size', '規格', ['class' => 'myclass']) !!}
{!! Form::textarea('size', 'L Size', ['cols' =>50 , 'rows'=>10]) !!}<br><br>
{!! Form::label('isRecommend', '是否為推薦商品', []) !!}
{!! Form::checkbox('isRecommend', 1, true) !!}<br><br>
{!! Form::label('colors[]', '紅色', []) !!}
{!! Form::checkbox('colors[]', 'red', false) !!}
{!! Form::label('colors[]', '黃色', []) !!}
{!! Form::checkbox('colors[]', 'yellow', false) !!}
{!! Form::label('colors[]', '綠色', []) !!}
{!! Form::checkbox('colors[]', 'green', false) !!}<br><br>
{!! Form::label('enabled', '是否上架', []) !!}
上架{!! Form::radio('enabled', 1, true, []) !!}
下架{!! Form::radio('enabled', 0, false, []) !!}<br><br>
{!! Form::label('price', '價格', []) !!}
{!! Form::number('price', 0, ['min'=>0 , 'max'=>10000]) !!}<br><br>
{!! Form::label('mode:', '模式', []) !!}
經典下拉
{!! Form::select('mode', ['recommend'=>'編輯精選','season'=>'當季商品','cp'=>'超值商品'],null, ['placeholder' => '請選擇商品模式']) !!}
分群下拉
{!! Form::select('mode', ['時節'=>['summer' => '夏日熱銷','winter'=>'冬節獻禮'],'價格'=>['cp'=>'超值商品','boss'=>'老闆跳樓']],null, []) !!}
選項由後台提供
{!! Form::select('mode', $cgies,null, []) !!}
{!! Form::label('month', '月份', []) !!}
月份下拉
{!! Form::selectMonth('month', null, []) !!}<br><br>
{!! Form::label('number', '數字', []) !!}
區間數字下拉
{!! Form::selectRange('number', 1, 10, 5, []) !!}<br><br>
{!! Form::label('pwd', '密碼', []) !!}
{!! Form::password('pwd', []) !!}<br><br>
{!! Form::label('email', 'Email', []) !!}
{{ Form::email('email',null,[]) }}<br><br>
{!! Form::label('pic', '圖片', []) !!}
{!! Form::file('pic', []) !!}<br><br>
{!! Form::label('date', '日期', []) !!}
{!! Form::date('date',null, []) !!}<br><br>
{!! Form::submit('儲存', []) !!}
{!! Form::reset('重置', []) !!}
{!! Form::close() !!}
</body>
</html>
Controller撰寫範例
//app/Http/Controllers/ItemController.php
public function create()
{
//取用表格的某兩個欄位,作為選項的來源
$cgies = \\App\\Models\\Cgy::pluck('title','id');
return view('items.create',compact('cgies'));
}
public function store(Request $request)
{
//dd($request->all());
//驗證表單是否正確
//新增資料
$item = Item::create($request->all());
//轉址出去
return redirect('/items');
}
public function edit($id)
{
//從cgies表格取出title和id這兩欄的資料,做成鍵值對陣列
$cgies = Cgy::pluck('title','id');
$item = Item::findOrFail($id);
return view('items.edit',compact('item','cgies'));
}
public function update(Request $request, $id)
{
$item = Item::find($id);
//驗證表單是否正確
//更新資料
$item = Item::updateOrCreate(['id'=>$id] ,$request->except(['_method','_token','id']));
//轉址出去
return redirect('/items');
}
路由撰寫範例
//routes/web.php
Route::resource('items','ItemController');
Form套件輸入項函式
開啟表單
{!! Form::open(['action'=>'App\\Http\\Controllers\\ItemController@store','method'=>'POST','files'=>true]) !!}
內建屬性:
- url 表單送出的網站路徑,ex:items
- route 表單送出的路由名稱,ex:items.store
- action 表單送出的控制器與方法,ex:ItemController@store
- method 表單請求動詞,預設為POST
- files 是否包含傳送檔案的輸入項
關閉表單
{!! Form::close() !!}
//輸入項標籤
{!! Form::label(欄位名稱, 顯示文字, 額外屬性陣列) !!}
//單行文字輸入項
{!! Form::text(欄位名稱, 預設內容) !!}
//多行文字輸入項
{!! Form::textarea(欄位名稱, 預設內容, 額外屬性陣列) !!}
//隱藏輸入項
{!! Form::hidden(欄位名稱, 內容) !!}
//額外屬性陣列範例
['class'=>'myclass','cols'=>50,'rows'=>10]
//checkbox輸入項
{!! Form::checkbox(欄位名稱, 值, 預設是否選取, 額外屬性陣列) !!}
//radio輸入項
{!! Form::radio(欄位名稱, 值, 預設是否選取, 額外屬性陣列) !!}
//數字輸入項
{!! Form::number(欄位名稱, 預設值, ['min'=>最小值 , 'max'=>最大值]) !!}
//下拉輸入項
{!! Form::select(欄位名稱, 選項陣列,預設值, ['placeholder' => 提示文字]) !!}
//密碼輸入項
{!! Form::password(欄位名稱, 額外屬性陣列) !!}
//Email輸入項
{!! Form::email(欄位名稱,預設值,額外屬性陣列) !!}
//檔案輸入項,記得表單頭要加入files=>true
{!! Form::file(欄位名稱, 額外屬性陣列) !!}
日期輸入項
{!! Form::date(欄位名稱, 預設值, 額外屬性陣列) !!}
//提交按鈕
{!! Form::submit(按鈕提示文字, []) !!}
//重置按鈕
{!! Form::reset(按鈕提示文字, []) !!}
PS:輸入項的值如為多選,需在欄位名稱後面加上[]
優化表單視圖
將可重複使用的輸入項內容移到一個新的視圖 items/_form.blade.php
//resources/views/items/_form.blade.php
{!! Form::label('title', '標題', ['class' => 'myclass']) !!}
{!! Form::text('title', null) !!}<br><br>
{!! Form::label('size', '規格', ['class' => 'myclass']) !!}
{!! Form::textarea('size', 'L Size', ['cols' =>50 , 'rows'=>10]) !!}<br><br>
{!! Form::label('enabled', '是否上架', []) !!}
上架{!! Form::radio('enabled', 1, true, []) !!}
下架{!! Form::radio('enabled', 0, false, []) !!}<br><br>
{!! Form::label('price', '價格', []) !!}
{!! Form::number('price', 0, ['min'=>0 , 'max'=>10000]) !!}<br><br>
{!! Form::label('pic', '圖片網址', []) !!}
{!! Form::text('pic','<https://lorempixel.com/640/480/?13909>',[]) !!}<br><br>
{!! Form::label('sell_at', '銷售日期', []) !!}
{!! Form::date('sell_at',\\Carbon\\Carbon::now(), []) !!}<br><br>
{!! Form::label('cgy_id', '商品分類', []) !!}
{!! Form::select('cgy_id', $cgies,null, ['placeholder' => '請選擇商品分類']) !!}<br><br>
{!! Form::label('mode', '商品模式', []) !!}
{!! Form::select('mode', ['recommend'=>'編輯精選','season'=>'當季商品','cp'=>'超值商品'],null, ['placeholder' => '請選擇商品模式']) !!}
@if (isset($item))
{!! Form::hidden('id', $item->id) !!}
@endif
改寫create.blade.php
將新增的_form.blade.php給include進來
//resources/views/items/create.blade.php
以上略
{!! Form::open(['action'=>'App\\Http\\Controllers\\ItemController@store','method'=>'post','files'=>true]) !!}
@include('items._form')
{!! Form::close() !!}
以下略
新增edit.blade.php
改用Form::model(), 需傳入要變更的資料物件,並需指定方法為patch。同時也把新增的_form.blade.php給include進來
//resources/views/items/edit.blade.php
以上略
{!! Form::model($item ,['url'=>'items/'.$item->id,'method'=>'patch','files'=>true]) !!}
@include('items._form')
{!! Form::close() !!}
以下略
如何組織 View的 Blade檔
建議針對各Model建立專屬的資料夾,再將關聯的Blade檔案存放在裡面,一般分為:
- _form.blade.php 將表單結構抽取存於此檔
- create.blade.php 負責顯示建立新資源頁面
- edit.blade.php 負責顯示編輯舊資源頁面
- index.blade.php 負責顯示多筆資料頁面
- show.blade.php 負責顯示單筆資料頁面
_form.blade.php 編寫重點
如果表單預定採用非GET的請求方式,記得要加入CSRF Token,否則會發生錯誤,如下示範:
<input type="hidden" name="_token" value="{{ csrf_token() }}">
此檔案將被create和edit這兩支Blade給include,可直接得到它們的變數,不需要傳入。
create.blade.php 編寫重點
表單內容搬移到_form.blade.php,以便於維護
Form主要的內容如下例:
{{ Form::open(['action'=>'App\\Http\\Controllers\\CgyController@store','role'=>'form']) }} //action設定對應的方法
@include('cgies._form',['submitBtnText'=>'建立']) //如果要傳參數到include視圖,可用第二參數作為陣列傳入
{{ Form::close() }}
edit.blade.php 編寫重點
表單內容搬移到_form.blade.php,以便於維護
Form主要的內容如下例:
//為將資料直接帶入對應輸入項,改用model(),第一參數為資料model的物件,變更資料的預設方法為patch或put,因此要加上method屬性
{{ Form::model($cgy,['method'=>'patch','url'=>'backend/cgy'.$cgy->id,'role'=>'form']) }} //action設定對應的方法
@include('cgies._form',['submitBtnText'=>'修改']) //如果要傳參數到include視圖,可用第二參數作為陣列傳入
{{ Form::close() }}
該如何讓超連結的GET請求能觸發 POST或DELETE等其他動詞
概念是為其建立一個form表單,然後透過JS來取消超連結的預設行為,並改為送出表單,如下例:
//此為刪除超連結,不須放在表單內,要換掉元素的ID
<a onclick="event.preventDefault();document.getElementById('del-form').submit();">刪除分類</a>
//指定刪除某資料的表單
{!! Form::open(['url' =>'cgies/' . $cgy->id , 'method' => 'DELETE', 'style'=>'display:none;' , 'id' => 'del-form']) !!}
{!! Form::close() !!}
上傳圖片檔案範例
\\\\app\\Http\\Controllers\\ProductController.php
public function store(){
//$data = $request->all(); //取得所有前台傳入的資料
$data = $request->except('_token'); //取得所有前台傳入的資料
$data['options'] = implode(',',$data['options']);
if ($request->hasFile('pic')) {
$file = $request->file('pic'); //獲取UploadFile例項
if ( $file->isValid()) { //判斷檔案是否有效
//$filename = $file->getClientOriginalName(); //檔案原名稱
$extension = $file->getClientOriginalExtension(); //副檔名
$filename = time() . "." . $extension; //重新命名
$data['pic'] = $filename;
$file->move( storage_path('app\\public\\images') , $filename); //移動至指定目錄
}
}
Product::create($data);
}