免費視頻教程地址https://laravist.com/series/laravel-5-basic
在開始之前,我們把界面先美化一點點先:
首先到https://github.com/JellyBool/blog-css-js得到靜態文件,然后分別修改下面三個文件:
1. app.blade.php 2. articles/index.blade.php 3. articles/show.blade.php
下面的視圖代碼的修改部分,如果你偷懶,你可以使用ctrl+c
大法。
在app.blade.php
中:將原來@yield('content')
的代碼替換成下面的代碼:
<body> <div class="container"> <section class="content"> <div class="pad group"> @yield('content') </div> </section> </div> </body>
就是在外面多加了個div和一個section。
再引入這兩個css文件:
<link rel='stylesheet' href="/css/bootstrap.min.css" type='text/css' media='all'/> <link rel='stylesheet' href="/css/all.css" type='text/css' media='all'/>
一個是bootstrap,一個是自定義的。
在articles/index.blade.php
文件中,我們將每個$article
放在<article>
標簽中:
@foreach($articles as $article)
<article class="format-image group"> <h2 class="post-title pad"> <a href="/articles/{{ $article->id }}"> {{ $article->title }}</a> </h2> <div class="post-inner"> <div class="post-deco"> <div class="hex hex-small"> <div class="hex-inner"><i class="fa"></i></div> <div class="corner-1"></div> <div class="corner-2"></div> </div> </div> <div class="post-content pad"> <div class="entry custome"> {{ $article->intro }} </div> <a class="more-link-custom" href="/articles/{{ $article->id }}"><span><i>更多</i></span></a> </div> </div> </article> @endforeach
然后最后就是修改articles/show.blade.php
視圖文件了:
@section('content')
<article class="format-image group"> <h2 class="post-title pad"> <a href="/articles/{{ $article->id }}" rel="bookmark"> {{ $article->title }}</a> </h2> <div class="post-inner"> <div class="post-content pad"> <div class="entry custome"> {{ $article->content }} </div> </div> </div> </article> @endsection
最后看看效果:
教程的最后,基本上就可以完成一個跟本人的blog一樣的小產品。
OK,稍微美化完過后,我們就可以進入我們的主題了:在Laravel中使用Forms表單。
前奏
既然我們需要創建一篇文章,我們首先還是需要將這個創建文章的頁面展示出來吧,就像SF的文章撰寫頁面一樣:http://segmentfault.com/write
所以我們需要將上一篇的內容走一遍:
注冊路由,在routes.php
中增加:
Route::get('article/create','ArticleController@create');
我們指定article/create
來加載ArticleController
的create()
方法,然后我們在ArticleController
創建之:
public function create() { return view('articles.create'); }
這個create()方法直接加載我們的create.blade.php
,所以我們創建這個視圖文件,來到之前的views/articles/這個文件夾中,新建create.blade.php
,寫上這些測試內容:
@extends('app') @section('content') <h1>撰寫新文章</h1> @endsection
瀏覽器訪問試試http://blog.dev/article/create:
一切正確加載之后,我們就開始着手我們的Forms使用了,因為創建文章的時候就是需要表單的提交,我們才可以將內容接收到,或者說幾乎每一個web應用都離不開表單,哪怕是一個注冊,登錄頁面,也都是需要表單的存在,只要你需要收集用戶的信息或者希望有一些UGC,也離不開表單。所以我們開始使用Laravel的Forms表單吧。
使用illuminate/html
這里我們使用一個官方的Package:https://github.com/illuminate/html
我們通過composer來安裝之:
composer require illuminate/html
靜待一會,安裝成功之后,我們們怎么告訴Laravel,這個Package已經安裝了?或者說我們怎么將這個Package跟Laravel的整個體系結合起來呢?
通過提供Service Provider和指定Facade!這樣就可以很完美地與Laravel結合了。
為什么直接叫Service Provider和Facade?因為我知道怎么翻譯這兩個才貼切,意會一下
在這里順便多說一點:在PHP的很多composer的package中,都會有各個框架的不同版本,比如說HtmlPurifier這個過濾html和預防xss的package,就有這個Laravel的版本: https://github.com/mewebstudio/Purifier ,或多或少,一些很好的package都會有Laravel的版本。
配置
那么說回Service Provider和Facade,剛開始可能對Service Provider的概念可能很迷惑,不過你現在完全不必要擔心,盡管打開config/app.php
這個文件看一看:
'providers' => [ Illuminate\Foundation\Providers\ArtisanServiceProvider::class, Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, //... ]
你會看到providers
這個數組里面會有一堆Laravel預置的Service Provider,比如我們經常使用到得Auth,Controller等,都可以在這里找到。如果你再往下拉,你還會看到一個這樣的aliases
數組:
'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, //... ]
aliases其實就是快捷方式了,一旦在這里指定了快捷方式,我們就可以在Laravel中全局使用,比如我在代碼中使用Auth
,其實背后我就是在用Illuminate\Support\Facades\Auth::class
,然后再深入,我們其實是在用providers
中的Illuminate\Auth\AuthServiceProvider::class
這個。
趁上面寫這些的時候illuminate/html
已經下載好了:
那么,按照上面方式,我們來配置一下我們的illuminate/html
,在config/app.php
中的providers添加我們的Service Provider:
Illuminate\Html\HtmlServiceProvider::class,
配置完大概長這樣:
OK,Service Provider添加好了之后,我們來添加我們的Facade,也就是在aliases
這個數值后面添加:
'Form' => Illuminate\Html\FormFacade::class,
配置完之后看看圖片長這樣:
使用Forms
這兩個配置好了之后,我們就可以在在我們的create.blade.php
這個視圖中使用它了:
@section('content') <h1>撰寫新文章</h1> {!! Form::open() !!} {!! Form::close() !!} @endsection
我們加入了兩行{!! Form::open() !!}
和{!! Form::close() !!}
,至於{!!
類似的符號,請類比如blade的{{
,不用太糾結這個。我們再來訪問http://blog.dev/article/create試試:
咋一看,貌似沒有什么變化,但是你要查看頁面源碼或者使用開發者工具檢查元素的時候,就可以發現這個form元素已經創建出來了。
不難發現,Laravel的Form還默認為我們生成一個hidden的表單(name="_token"),這個是Laravel默認對表單提交的一點安全支持。在表單提交的時候,Laravel會自動檢查這個_token
是否與保存在session中的_token
一致,如果不一致,那就直接跳轉回遠頁面,不允許我們提交數據。
既然Form可以正常使用了,我們就可以創建我們需要的表單了:
{!! Form::open() !!}
<div class="form-group"> {!! Form::label('title','標題:') !!} {!! Form::text('title',null,['class'=>'form-control']) !!} </div> <div class="form-group"> {!! Form::label('content','正文:') !!} {!! Form::textarea('content',null,['class'=>'form-control']) !!} </div> <div class="form-group"> {!! Form::submit('發表文章',['class'=>'btn btn-success form-control']) !!} </div> {!! Form::close() !!}
我們在{!! Form::open() !!}
加入一點東西,先來看看我們的效果:
下面詳細解釋一下:
{!! Form::text('title',null,['class'=>'form-control']) !!}
拿這個來開刀吧:
-
Form::text
表示<input type='text' />
,還要一堆比如<input type='password' />
等你可以參照着寫。 -
'title'
表示name='title'
-
null
表示value=''
'class'=>'form-control'
表示class='form-control'
,這里可以指定id
,placeholder
等一系列你想指定的屬性
然而在Form::open()
沒有指定提交路徑的情況之下,默認是提交到本頁面,這樣對於我們的清晰分工是不太好的,因為這個頁面就是用來加載視圖的,而對於我們表單提交的內容,我們希望用另外的方法來處理,所以我們來寫一寫吧。
首先在Form::open()
指定表單提交的url,直接在加入url:
{!! Form::open(['url'=>'article/store']) !!}
我們指定表單post提交到article/store
這個地址,然后在routes.php
注冊這個路由地址:
Route::post('article/store','ArticleController@store');
這里注意我們使用了Route::post
而不是Route::get
,這是用來接收post的路由。然后順利成章,在ArticleController
中創建store()
方法:
public function store() { $input = Request::all(); return $input; }
在這個方法中,我們引入Laravel自帶的Request
並使用Request::all()
,來獲取所有的用戶提交的過來的內容(這里指的是:_token
,name
很content
),如果你想獲取具體某一個表單輸入的內容,可以使用Request::get()
,比如Request::get('title')
,然后直接return來看看用戶到底輸入了什么內容,我們來試試:
實現創建新文章
OK,成功拿到用戶的提交的內容之后,我們需要將這些保存到數據庫,怎么實現呢?在第四篇中,我們提到的Eloquent
的create()
方法現在就可以派上用場了,於是我們可以寫成這樣:
Article::create($input);
Laravel會自動過濾_token
這個提交內容。
但是創建完一篇文章之后,我們並不是想return $input
,而是想重新跳轉到某個頁面中,比如我們的首頁,因為發表完文章,我們需要看到它是否成功出線在文章列表中,所以我們最后寫一下:
public function store() { $input = Request::all(); Article::create($input); return redirect('/'); }
我們直接使用Laravel的redirect()
函數進行跳轉,跳轉到首頁。這個時候,短短的三行代碼就可以將我們的邏輯實現了,那么我們來試試:
貌似成功了?但是我們覺得這個排序有點問題,最新創建的文章當然是在最上面的了,所以我們到ArticleController
的index()
方法中稍微修改一下:
public function index() { $articles = Article::latest()->get(); return view('articles.index',compact('articles')); }
將原來的all()
換成了latest()->get()
,刷新,
我們發現,最新的文章intro
竟然空白,我們到數據庫看看:
我們發現,剛剛創建的文章的intro
為空值,而published_at
為0000-00-00 00:00:00
,這不是我們想要的,為什么會這樣呢?因為我們在提交過來的時候,並沒有這兩個數據啊,為了解決這個問題,首先我們可以很暴力得將這兩個數據在使用Article::create($input)
之前配置好,比如:
public function store() { $input = Request::all(); //下面增加兩行,順便看看Request::get的使用 $input['intro'] = mb_substr(Request::get('content'),0,64); $input['published_at'] = Carbon::now(); Article::create($input); return redirect('/'); }
intro字段就直接取content字段的頭64個,然后published_at就默認為創建的時間。目前開起來代碼有點暴力,但是不失為一種解決方案,我們后續會使代碼much cleaner。我們再來試試:
bang,成功了,我們在看看數據庫:
到這里,我們創建一篇文章的基本流程就完成了,但是這里還有一個問題,如果你嘗試在文章創建的頁面什么都不填,直接提交數據,你看看會發生什么,如果不確定,你可以看看你的數據庫,到底發生了什么。