【Laravel實戰】Laravel Collective 套件

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

分享這篇文章:

訂閱電子報,索取 Laravel 學習手冊

價值超過 3000 元,包含常用 Laravel 語法與指令!

Laravel 百萬年薪特訓營

從最基礎的 PHP 語法開始,包含所有你該知道的網頁基礎知識,連同 Laravel 從零開始一直到實戰,最後還將告訴你如何找好工作,讓你及早擁有百萬年薪