本文基於Laravel
框架作的一個URL生成和存儲demo,主要目的是學習使用Laravel
框架。內容基於英文書籍《Packt.Laravel.Application.Development.Blueprints》
第一章節,彷佛沒有中文版。書籍基於Laravel4
的,學習時使用Laravel5.2
框架開發。
php
該demo主要涉及以下幾個知識點:css
建立數據庫並遷移數據表html
建立表單,學習Laravel
的blade
模板引擎java
建立名爲Link的模型Model
mysql
保存數據進入數據庫laravel
從數據庫中得到URL連接並重定向sql
表遷移(Migrations
)其實就是數據庫(Database
)的版本控制,容許團隊修改數據庫架構,並保存當前數據庫最新架構信息,爲了建立並遷移建立的URL數據庫,須要作幾個步驟:數據庫
(1)
、首先建立一個數據庫並定義該數據庫與Laravel
的鏈接信息,Laravel
框架爲數據庫鏈接提供了配置文件:/config/database.php
,Laravel
支持SQlite、MySQL、PostgreSQL、SQLSRV
數據庫,本教程使用MySQL
數據庫。json
(2)
、建立一個名爲urls
的數據庫,終端登入mysql服務器或者使用phpMyAdmin敲入SQL語句:CREATE DATABASE urls
。可使用PHPStorm
這個IDE的database
模塊遠程建立urls
數據庫。數組
(3)
、在成功建立數據庫urls後,開始配置數據庫名稱和用戶名密碼,在/config/database.php
裏配置host,database,username,password
,因爲配置文件使用env()函數先讀取.env文件裏的值,因此能夠直接在.env文件裏配置。.env文件能夠從.env.example文件複製得來,如修改.env文件中值:DB_HOST=localhost,DB_DATABASE=urls,DB_USERNAME=root,DB_PASSWORD=laravel
;也能夠修改/config/database.php
文件爲:'host'=>'localhost','database'=> 'urls','username'=>'root','password' =>'laravel'
。數據庫用戶名爲安裝MySQL時配置的。
(4)
、使用Laravel
的Artisan CLI
工具命令建立migrations遷移文件,能夠在終端進入項目根目錄輸入php artisan
命令查看Artisan命令列表。如今建立一個名爲links的遷移文件:php artisan make:migration create_links_table --create=links
,會在/database/migrations/
文件夾下新建一個date+create_links_table.php
文件,該文件源碼主要包含兩個很是重要的方法:up()/down()
。當執行數據表遷移命令php artisan migrate
時執行的是up()
方法;當執行回滾上一次遷移命令php artisan migrate:rollback
時執行的是down()
方法,該命令具備破壞性會刪除links數據表。曾經遇到一個場景:須要給數據表test增長一個字段age但又要保留test表裏數據,能夠再建立一個遷移文件php artisan make:migration create_links_table --table=links
,生成的遷移文件中up()
方法裏引用了Schema::table()
方法而不是Schema::create()
方法,再添加$table->string('age')->default(0);
語句,刪除原來的'id'和timestamps郵戳語句,再執行php artisan migrate
遷移命令。
(5)
、在建立的遷移文件內增長兩個字段:$table->text('url');$table->string('hash',400);
,自動生成的$table->timestamps();
語句是給數據表添加郵戳,會自動增長'created_at'/'updated_at'
兩個字段,默認時間是UTC與北京時間相差8小時,能夠在config/app.php
文件中修改'timezone'
值爲'Asia/Shanghai'
就行。再執行遷移命令php artisan migrate
,若是數據庫配置沒有錯誤就會在urls數據庫裏生成links表和migrations表,migrations表記錄的是遷移記錄可不用管。
註明:能夠安裝phpstorm
這個IDE,使用它的database模塊查看數據庫,說實話我的用的感受還挺順手的,固然也能夠安裝navicat premium
軟件查看。
(1)
、在resources/views/
文件夾下建立一個urls
文件夾,在urls
文件夾下建立一個form.blade.php
文件文件名須要有blade字符串,laravel會自動識別這個文件爲blade模板文件。form模板代碼爲:
<html lang="en"> <head> <title>URL Shortener</title> <link rel="stylesheet" href="{{asset('css/urls/style.css')}}"> </head> <body> <div id="container"> <h2>短連接生成器</h2> {{Form::open(array('url'=>'/url','method'=>'post'))}} {{Form::text('link', '請輸入您的網址!')}} {{--{{Form::text('link',Input::old('link'), array('placeholder'=>'請輸入您的網址!'))}}--}} {{Form::close()}} </div> </body> </html>
註明
:個人Laravel代碼會報錯沒有Input這個類,很奇怪,那就把這一句註銷掉吧。若是你知道咋解決,請在評論留言給我,謝謝
。樣式style.css文件能夠用asset()函數在public文件夾下找到路徑,在這裏就是public/css/urls/style.css
。固然,也能夠不用這個Form類,直接寫<form></form>表單html代碼也行。這裏的url表示提交表單時的路由,方法爲post。在這裏使用laravelcollective/html這個組件,順便了解下怎麼在laravel中安裝組件。
這裏書中使用了laravel4.*
自帶的Form類,但laravel5.*
已經移除了,能夠經過composer
Composer官網安裝。能夠進入官網https://laravelcollective.com/docs/5.1/html
找安裝和配置方式,也能夠去packagist.org
中找https://packagist.org/packages/laravelcollective/html
,這裏推薦一個很是好用的網站packagist
,PHP中全部組件components均可以在這裏找到並經過composer安裝。《Modern PHP》(能夠去pan.java1234.com
搜到英文版的)這本書中倡導PHP軟件開發應該使用組件components方式來作,利用別人的輪子會加速開發效率,組件components可裝可卸,組件式代碼比麪條式代碼讀起來更舒服!!!
經過composer安裝也很簡單,就是在項目根目錄下的composer.json
文件'require'數組中添加"laravelcollective/html": "5.2.*",
,再composer update
就行,安裝完laravelcollective/html後在config/app.php
文件中配置這個組件的服務serviceprovider,在'providers'數組中加上Collective\Html\HtmlServiceProvider::class,
,在'aliases'數組中加上'Form' => Collective\Html\FormFacade::class,'Html' => Collective\Html\HtmlFacade::class,
,就能夠用這個組件輪子了,實際上不少組件也都是這麼安裝配置的。
樣式style.css代碼爲:
div#container{padding-top:100px;text-align:center;width:75%;margin:auto;border-radius:4px} div#container h2{font-family:Arial,sans-serif;font-size:28px;color:#555} div#container h3{font-family:Arial,sans-serif;font-size:28px} div#container h3.error{color:#a00} div#container h3.success{color:#0a0} div#container input{display:block;width:90%;float:left;font-size:24px;border-radius:5px} div#error,div#success{border-radius:3px;display:block;width:90%;padding:10px} div#error{background:#ff8080;border:1px solid red} div#success{background:#80ff80;border:1px solid #0f0}
balde模板頁面寫完,而後在routes.php路由文件中寫個路由:
Route::get('/url', function(){ return view('urls.form');//urls爲建立的文件夾 });
這裏路由第二個參數爲匿名函數,直接返回視圖,固然能夠建個控制器php artisan make:controller UrlController
,在控制器裏寫個getUrl()方法返回視圖,那路由就要這麼寫了:Route::get('url', 'UrlController@getUrl')
。
最後輸入URL:http://yourhost/url
,則blade模板頁面如圖所示:
Laravel提供了一個很是好用的ORM(Object Relationship Mapping)爲Eloquent ORM,其實就是Model層,來管理數據庫中的數據表且一一對應關係。Eloquent比較好用在於它提供了不少Feature功能模塊,這些模塊提供了許多面向對象的方法便於使用,這樣就不用寫SQL語句了,且代碼看起來也很舒服。。不過有時也推薦使用它的Query Builder查詢構造器,實際上就是SQL語句封裝的類,性能會比較高一些,我的遇到過一個場景:使用Eloquent ORM性能有點慢,致使PHP執行過長報503 Time Out,改爲Query Builder後性能高不少腳本執行很快搞定,固然各有利弊,畢竟Eloquent很強大很好用。
在項目根目錄執行Artisan命令php artisan make:model Link
後,生成app/Link.php
文件,這個model經過配置用來管理MySQL中的links數據表,在Link這個model裏寫上配置:
class Link extends Model { // protected $table = 'links'; protected $fillable = ['url', 'hash']; }
$table變量配置成MySQL中links數據表的名稱,$fillable用來配置數據表字段(column)被批量建立和更新的,由於後文在保存數據進入表裏時使用Link::create([])方法來進行批量賦值的。能夠查看Model這個class源碼裏有$table和$fillable字段,這個Model類提供了許多好用的方法,有時間能夠瞅瞅。若是不須要laravel自動建立的時間能夠寫上public $timestamps = false;
再執行遷移命令,links數據表裏就沒有'created_at'/'updated_at'
字段了。這裏注意下:若是不寫$table變量,laravel會自動根據model名字複數來找數據表,如這個model名字是link,那就找links表。
寫好視圖表單後,再就是寫表單的提交路由及其控制器邏輯,在控制器中引用建立好的Link這個Model往links數據表裏存數據。原文書中是直接在路由中匿名函數裏寫數據存儲邏輯,這裏我的仍是先建立一個控制器php artisan make:controller UrlController
,在控制器裏寫數據存儲邏輯比較好。實際上,控制器也就是路由層route、視圖層view與模型model層的黏合劑而已,通常寫laravel代碼流程也僅此而已:如今路由裏寫好路由,再創建好model(包括建立好migrations和model,寫好數據庫鏈接配置、model配置、執行migrations表遷移),再在控制器controller裏寫好業務邏輯,返回response如blade視圖view或直接一個"hello world"字符串吧,最後要是返回view那就在resources/views
裏寫個view就行。laravel框架使用也僅此而已,沒有那麼複雜,對於咱們這樣的剛剛入門,瞭解這個流程就能夠玩一玩了!!!
(1)
、驗證輸入
在提交表單時都要驗證輸入數據是否符合規定,省得讓髒數據進入數據表裏,laravel提供了Validation模塊來作表單驗證而且能夠在視圖中顯示驗證錯誤信息,具體想了解下的能夠看我這篇文章:Laravel學習筆記之Validator。
在驗證表單時首先須要寫驗證規則$rules,本demo僅有一個輸入且輸入要符合URL格式,那就要考慮兩個問題:怎麼獲得表單的輸入$input和怎麼寫符合URL的$rules驗證規則。首先使用驗證方法Validator::make([], [])
,這個方法的第一個參數是取得的表單輸入$input,第二個參數是驗證規則$rules。demo中只有一個輸入可使用Input::all()
取得或者Input::get('link')
,其中link爲這個輸入的name,對應表單視圖的{{Form::text('link', '請輸入您的網址!')}}
這個link
,$rules驗證規則這麼寫:
$rules = array( 'link' => 'required|url' );
這裏'required'是輸入不能爲空,是laravel自帶的驗證規則,'url'也是laravel自帶的URL驗證規則,就是格式得符合URL格式,'|'表示且的意思。
好,如今就按照流程寫代碼:
首先:
Route::post('url', 'UrlController@postUrl');
而後在UrlController中寫上:
public function postUrl(){ $rules = array( 'link' => 'required|url' ); //$validation = Validator::make(Input::all(),$rules); $validation = Validator::make(Input::get('link'),$rules); }
這裏這個存儲變量$validation存儲了不少驗證信息,頗有用,如驗證經過($validation->passes()
)和驗證失敗($validation->fails()
),這兩個函數返回Boolean結果,還有$validation->messages()
函數返回驗證失敗後驗證信息。
若是驗證失敗,就返回URL表單提交頁面,而且帶上flash data,flash data是被刷到session中,能夠在模板視圖view中經過Session::get('XXX')
獲得,下面會看到代碼。那怎樣把flash data數據刷到session中:laravel提供了with()
或withVariableName()
方法,若是直接返回view時,$VariableName直接在模板視圖中做爲變量使用,若是是重定向view時,須要經過Session::get('VariableName')
方法獲取變量值。
比較:
public function getUrl(){ $title = 'Url Generator'; return view('urls.form')->with('titletitle', $title);//blade模板中直接使用$titletitle變量就行,如<title>{{$titletitle}}</title> } public function postUrl(){ $title = 'Url Generator'; return Redirect::to('/url')->with('titletitle', $title);//這裏重定向頁面,在blade模板視圖中獲得$titletitle變量能夠這麼作,Session::get('titletitle'),檢查有無變量這麼作Session::has('titletitle') }
而後在postUrl()方法中寫上驗證失敗的話重定向URL表單提交頁面:
if($validation->fails()) { return Redirect::to('/url') ->withInput() ->withErrors($validation); }
這裏$errors變量在blade視圖模板中能夠直接引用就不用Session::get()了,這是由於laravel會自動把這個變量和視圖模板綁定,這$errors是個特殊的變量,在form.blade.php視圖中添加上驗證錯誤信息代碼。withInput()
函數會在返回表單時在input裏填上剛剛輸入的舊數據。
(2)
、將驗證信息傳到模板視圖中
@if(Session::has('errors')) <h3 class="error">{{$errors->first('link')}}</h3> @endif
first()
函數返回link表單的第一個驗證錯誤信息。固然也能夠遍歷驗證信息並顯示出來:
@if(Session::has('errors')) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $error) <li>{{$error}}</li> @endforeach </ul> </div> @endif
代碼的else
部分主要處理當驗證經過後,主要實現如下邏輯:
檢查link連接是否已經在數據表裏
若是link連接已經在數據表裏,返回該短鏈接
若是link連接不在數據表裏,那就爲該連接建立一個hash字段
根據提供數據在數據表裏插入一個記錄record
返回該連接給用戶(1).使用Query Builder的where()方法,並傳入Input::get('link')參數驗證數據表裏是否已經有該連接,並鏈式使用first()方法取出第一個結果:
$link = Link::where('url','=',Input::get('link'))->first();
(2).若是數據表裏有該連接,重定向到表單頁面並帶上數據表的hash字段:
if($link) { return Redirect::to('/url')->withInput()->with('link',$link->hash); }
能夠經過$link->columnName取得數據表裏的字段值。這裏with('name','value')等同於駝峯方法withName('value')方法,上文也說明了。在form.blade視圖中也加上消息:
@if(Session::has('link')) <h3 class="success"> {{Html::link(Session::get('link'),'Click here for your shortened URL')}}//Html類是laravelcollective/html這個模塊裏的類,或者直接寫個`a`超連接標籤也行 </h3> @endif
(3).連接不在數據表裏,爲該連接建立一個hash字段,原文使用$newHash = Str::random(6)
建立一個包含數字字母的字符長度爲6的字符串,再去表裏驗證該$newHash是惟一的,這樣比較麻煩,能夠直接使用Hash::make($param)
就行:
else{ $newHash = Hash::make(Input::get('link'));//根據輸入的link作hash哈希就行或者別的更簡短的輸入值 }
(4).向link數據表裏插入一個新的記錄record:
else{ $newHash = Hash::make(Input::get('link'));//根據輸入的link作hash哈希就行或者別的更簡短的輸入值 Link::create([ 'url' => Input::get('link'), 'hash' => $newHash ]); }
使用Link模型的create()方法建立一條record,或者:
$link = new Link(); $link->url = Input::get('link'); $link->hash = $newHash; $link->save();
以前研究過一個小點:使用create方式是須要在Link模型類中寫上$fillable指定批量賦值字段,不然報錯,而這個save方式不須要這麼作。
(5).再重定向到表單提交頁面
return Redirect::to('/url') ->withInput() ->with('link', $newHash);
這裏帶上$newHash變量是爲了後面捕獲這個變量後,根據這個變量從數據表裏查找對應的url值。
最後根據生成的URL獲取其hash部分,根據hash值從links數據表取出對應的URL爲了重定向,這裏英文原文也是在路由中寫邏輯,這裏也在路由裏寫邏輯:
Route::get('/url/{hash}', function($hash){ $link = Link::where('hash',$hash)->first(); if($link){ return Redirect::to($link->url); }else{ return Redirect::to('/url')->with('message', 'Invalid Link'); } })->where('hash', '[0-9a-zA-Z+]');
{hash}
是一個路由參數,做爲匿名函數的參數,而且正則限制其是由數字字母組合where('hash', '[0-9a-zA-Z+]')
,若是links數據表裏有數據就跳轉到這個連接去,沒有則返回message給blade模板視圖,因此form.blade模板視圖須要添加顯示:
@if(Session::has('message')) <h3 class="error">{{Session::get('message')}}</h3> @endif