<s id="vqbdy"></s>

      <object id="vqbdy"></object>
      <strong id="vqbdy"><rp id="vqbdy"></rp></strong>

      Laravel - 為 WEB 藝術家創造的 PHP 框架。

      PHP THAT DOESN'T HURT. CODE HAPPY & ENJOY THE FRESH AIR.

      Laravel logo

      2016 版 Laravel 系列入門教程(四)

      本教程示例代碼見:https://github.com/johnlui/Learn-Laravel-5

      在任何地方卡住,最快的辦法就是去看示例代碼。

      本篇文章中,我將跟大家一起實現 Article 的新增、編輯和刪除功能,仔細解讀每一段代碼,相信本篇文章看完,你就能夠 get Laravel 使用之道。

      RESTful 資源控制器

      資源控制器是 Laravel 內部的一種功能強大的約定,它約定了一系列對某一種資源進行“增刪改查”操作的路由配置,讓我們不再需要對每一項需要管理的資源都寫 N 行重復形式的路由。中文文檔見:http://www.ap4lp.com/laravel/docs/5.1/controllers/#restful-resource-controllers

      我們只需要寫一行簡單的路由:

      Route::resource('photo', 'PhotoController');
      

      就可以得到下面 7 條路由配置:

      左邊是 HTTP 方法,中間是 URL 路徑,右邊是 控制器中對應的函數,只要某個請求符合這七行中某一行的要求,那么這條請求就會觸發最后一列的方法。這是 Laravel 對于 RESTful 的規范,它不僅僅幫我們省去了幾行路由配置代碼,更是如何合理規劃 URL 的指路明燈,相信你會從中學到很多。

      下面我們正式開始一項一項地實現 Article 的新增、編輯、刪除功能:

      開始行動

      配置資源路由

      將當前路由配置中的 Route::get('article', 'ArticleController@index'); 改成 Route::resource('article', 'ArticleController');,哦了。

      新增 Article

      新增一篇文章需要兩個動作:第一步,獲取“新增Article”的頁面;第二步,提交數據到后端,插入一篇文章到數據庫。

      獲取“新增Article”的頁面

      第二行路由可以滿足我們的需求:

      那下一步就明了了,在 ArticleController 中新增 create 方法,放回一個可以輸入文章的頁面:

      ArticleController 中:

      public function create()
      {
          return view('admin/article/create');
      }
      

      新增視圖文件 learnlaravel5/resources/views/admin/article/create.blade.php

      @extends('layouts.app')
      
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-10 col-md-offset-1">
                  <div class="panel panel-default">
                      <div class="panel-heading">新增一篇文章</div>
                      <div class="panel-body">
      
                          @if (count($errors) > 0)
                              <div class="alert alert-danger">
                                  <strong>新增失敗</strong> 輸入不符合要求<br><br>
                                  {!! implode('<br>', $errors->all()) !!}
                              </div>
                          @endif
      
                          <form action="{{ url('admin/article') }}" method="POST">
                              {!! csrf_field() !!}
                              <input type="text" name="title" class="form-control" required="required" placeholder="請輸入標題">
                              <br>
                              <textarea name="body" rows="10" class="form-control" required="required" placeholder="請輸入內容"></textarea>
                              <br>
                              <button class="btn btn-lg btn-info">新增文章</button>
                          </form>
      
                      </div>
                  </div>
              </div>
          </div>
      </div>
      @endsection
      

      點擊文章管理頁面最上面的“新增”按鈕,你將得到以下頁面:

      視圖調用

      上文中我使用 return view('admin/article/create'); 返回了視圖文件。

      view() 方法是 Laravel 中一個全局的方法,用于調用視圖文件,他接受一個字符串參數,并會按照這個參數去調取對應的路由,這很容易理解。實際上 'admin/article/create''admin.article.create' 是等價的,而且看起來后者更加優雅,不過本寶寶十分推薦前者。代碼優雅是好事兒,不過本質上代碼是寫給人看的,一切提高代碼理解成本的行為都是錯誤的。

      提交數據到后端

      “新增Article”的頁面已經展示出來,下一步就是提交數據到后端了,理解提交數據,要從表單開始。

      表單

      視圖文件中有一個表單:

      <form action="{{ url('admin/article') }}" method="POST">
          {!! csrf_field() !!}
          <input type="text" name="title" class="form-control" required="required" placeholder="請輸入標題">
          <br>
          <textarea name="body" rows="10" class="form-control" required="required" placeholder="請輸入內容"></textarea>
          <br>
          <button class="btn btn-lg btn-info">新增文章</button>
      </form>
      

      這是一個非常普通的 form 表單,只有兩點需要我們費點心思去理解。

      第一,表單的 action。form 是 HTML 規范,在點擊了表單中的提交按鈕后,瀏覽器會使用 method 方法將某些數據組裝好發送給 action,這里我們動態生成了一個 URL 作為 action,并且指定了表單提交需要使用 POST 方法。

      第二,csrf_field。這是 Laravel 中內置的防止應對 CSRF 攻擊的防范措施,任何 POST PUT PATCH 請求都會被檢測是否提交了 CSRF 字段。

      {!! csrf_field() !!}
      

      實際上會生成一個隱藏的 input:

      <input type="hidden" name="_token" value="GYZ8OHDAbZICMcEvcTiS82qlZs2XrELklpEl159S">
      

      這一行也可以這么寫:

      <input type="hidden" name="_token" value="{{ csrf_token() }}">
      

      如果你的系統有很多的 Ajax,而你又不想降低安全性,這里的 csrf_token() 函數將會給你巨大的幫助。

      后端接收數據

      我們在頁面中填入了一些數據,點擊了提交按鈕,這條請求會被分配到那里呢?

      第三行解答了我們的問題。好了,新建 store 方法:

      public function store(Request $request)
      {
          $this->validate($request, [
              'title' => 'required|unique:articles|max:255',
              'body' => 'required',
          ]);
      
          $article = new Article;
          $article->title = $request->get('title');
          $article->body = $request->get('body');
          $article->user_id = $request->user()->id;
      
          if ($article->save()) {
              return redirect('admin/article');
          } else {
              return redirect()->back()->withInput()->withErrors('保存失敗!');
          }
      }
      

      檢驗成果

      填入數據:

      點擊按鈕,頁面跳轉到“文章管理”頁,將此頁面拉到最底部:

      恭喜你,文章新增成功!

      詳細注釋

      下面我已注釋的形式細細解析每一段代碼的作用:

      public function store(Request $request) // Laravel 的依賴注入系統會自動初始化我們需要的 Request 類
      {
          // 數據驗證
          $this->validate($request, [
              'title' => 'required|unique:articles|max:255', // 必填、在 articles 表中唯一、最大長度 255
              'body' => 'required', // 必填
          ]);
      
          // 通過 Article Model 插入一條數據進 articles 表
          $article = new Article; // 初始化 Article 對象
          $article->title = $request->get('title'); // 將 POST 提交過了的 title 字段的值賦給 article 的 title 屬性
          $article->body = $request->get('body'); // 同上
          $article->user_id = $request->user()->id; // 獲取當前 Auth 系統中注冊的用戶,并將其 id 賦給 article 的 user_id 屬性
      
          // 將數據保存到數據庫,通過判斷保存結果,控制頁面進行不同跳轉
          if ($article->save()) {
              return redirect('admin/article'); // 保存成功,跳轉到 文章管理 頁
          } else {
              // 保存失敗,跳回來路頁面,保留用戶的輸入,并給出提示
              return redirect()->back()->withInput()->withErrors('保存失敗!');
          }
      }
      

      編輯 Article

      這兩行路由配置可以滿足我們的需求:

      上面一行:展示“編輯某一篇文章”的頁面;下面一行:上傳數據更新這篇文章。

      這個就當做第二個小作業留給你們,嘗試自己去構建吧~這里面還有個小坑,參考我的代碼就可以迅速地解決呦~

      刪除 Article

      刪除某個資源跟新增、編輯相比最大的不同就是運行方式的不同:刪除按鈕看起來是一個獨立的按鈕,其實它是一個完整的表單,只不過只有這一個按鈕暴露在頁面上:

      <form action="{{ url('admin/article/'.$article->id) }}" method="POST" style="display: inline;">
          {{ method_field('DELETE') }}
          {{ csrf_field() }}
          <button type="submit" class="btn btn-danger">刪除</button>
      </form>
      

      大家可能注意到了這句代碼 {{ method_field('DELETE') }},這是什么意思呢?這是 Laravel 特有的請求處理系統的特殊約定。雖然 DELETE 方法在 RFC2616 中是可以攜帶 body 的(甚至 GET 方法都是可以攜帶的),但是由于歷史的原因,不少 web server 軟件都將 DELETE 方法和 GET 方法視作不可攜帶 body 的方法,有些 web server 軟件會丟棄 body,有些干脆直接認為請求不合法拒絕接收。所以在這里,Laravel 的請求處理系統要求所有非 GET 和 POST 的請求全部通過 POST 請求來執行,再將真正的方法使用 _method 表單字段攜帶給后端代碼。上面小作業中的小坑便是這個,PUT/PATCH 請求也要通過 POST 來執行。

      另外,這里還有一些小問題:PUT/PATCH 請求通過 POST 方法執行僅限于 form 提交,對 Ajax 請求目前來看是無效的,看來我要去給 Laravel 提交一個 patch 了。

      在控制器中增加刪除文章對應的是 destroy 方法:

      public function destroy($id)
      {
          Article::find($id)->delete();
          return redirect()->back()->withInput()->withErrors('刪除成功!');
      }
      

      點擊刪除按鈕,檢驗效果:

      恭喜你,文章新增、編輯、刪除功能構建成功!


      原文:https://github.com/johnlui/Learn-Laravel-5/issues/7


      關于作者 JohnLui
      PHP 框架 TinyLara 作者。
      国模吧私拍