Laravel身為最優雅的PHP框架,很多學習PHP的小伙伴造就對Laravel垂涎欲滴。今天就來實現你的願望,讓我們一起從零開始,利用Laravel實現Web應用最常見的注冊和登錄功能!所有的課程源碼已放在Github上:laravel-start. Race Start !
首先我們來明確一下我們這個課程需要的東西:
Laravel 4.2
Bootstrap 3.3
Laravel就是我們關心的核心部分,Bootstrap用來快速設置一些前端的CSS樣式。
1.安裝Laravel
簡單說明之後我們來進入下一步,安裝Laravel,在這我們是通過Composer來安裝,打開命令行終端,執行:
復制代碼 代碼如下:
cd Sites
Sites就是web應用的根目錄,你可以根據需要換成你自己的根目錄,然後再執行:
復制代碼 代碼如下:
composer create-project laravel/laravel laravel
laravel就是你的應用目錄名,你可以取一個你喜歡的名字。執行上面的命令之後,等一段時間(畢竟在國內,網速是個大坑),安裝完以後你會得到這一堆目錄:
我們主要操作models和 controllers和 views這三個目錄:這就是MVC的構成啊!
2.安裝Bootstrap
然後再命令行執行:
復制代碼 代碼如下:
cd laravel/public/packages
這裡的laravel與上面的應用目錄對應,如果你在安裝的時候用了其他的名字,請對應換上。來到packages這個目錄後安裝Bootstrap,直接在命令行執行:
復制代碼 代碼如下:
bower install bootstrap
這個比較快,然後等這個下載完之後你就會得到最新的穩定版Bootstrap。在目錄packages目錄下的 bower_components/bootstrap/dist/這裡就包含了Bootstrap的css,js,fonts這三個我們在開發過程中經常用到的樣式文件,js和字體文件。成功後你將看到這個:
注:這裡使用的bower這個工具,它負責管理一些前端的包。
到這裡,我們的前期工作已經准備好了。不過在進入下一步之前,我們得先確保我們的laravel/app/storage目錄有相應的寫入權限,所以回到laravel目錄,如果你在安裝完bower之後沒動過命令行,可以直接通過:
復制代碼 代碼如下:
cd ../../
回到laravel目錄,然後在執行:
復制代碼 代碼如下:
chmod -R 755 app/storage
這一步搞定之後我們就可以進入真正的開發階段了。
3.配置數據庫並建表:
在開始配置之前,我們要為我們的laravel應用創建一個數據庫,我將它命名為laravel-start,
然後在編輯器中打開app/config/database.php文件,對相應的數據庫配置項填入,如:
復制代碼 代碼如下:
'default' => 'mysql',
// 數據庫連接
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => 'laravel-start',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
連接完數據庫之後,還得創建一個Users表,你可以直接在數據庫中創建Users表,也可以利用Laravel的artisan來創建,這裡我們使用Laravel的artisan來建表,順道了解一點點關於Laravel migrate的知識。執行下面語句:
php artisan migrate:make create-users-table
以上命令會創建一個migrate文件(文件位於app/database/migrations目錄下),這個文件的名字就是create-users-table,然後我們可以通過編輯剛剛生成的migrate文件來創建Users表。
復制代碼 代碼如下:
public function up() {
Schema::create('users', function($table){
$table->increments('id');
$table->string('username', 20);
$table->string('email', 100)->unique();
$table->string('password', 64);
$table->string('remember_token',62)->default('default');
$table->timestamps();
});
}
上面的方法使用了laravel的Schema Builder類,上面這段代碼使用up()方法的創建一個users表,這個表裡有5個字段:id自增 ,username長度20以內 ,email長度100以內並且是唯一的 ,password長度64以內 ,remember_token是為了在登錄的時候更方便實用,Laravel會自動將token值填充進來,但在最開始你必須設一個默認值,timestamp當前的時間戳。在這我們需要注意的一點是:最好在down()加上下面的代碼,以防某天我們需要刪除Users這個表。
復制代碼 代碼如下:
public function down()
{
Schema::drop('users');
}
上面的都做好以後,執行一下下面這一句神奇的命令:
復制代碼 代碼如下:
php artisan migrate
有圖有真相:
終於,我們的前奏搞完了,可以正式來魯Laravel了。
4.啟動服務來試試
直接在laravel目錄執行:
復制代碼 代碼如下:
php artisan serve
打開浏覽器,輸入localhost:8000,回車,Bingo!
OK,先給自己三十秒的掌聲時間,如果你順利地走到了這一步的話。恭喜你,你已經進入Laravel的大門,更多驚喜我們再一一道來.....
5.創建公用視圖
好了,我們現在開始了,首先在app/views/文件夾下創建一個layouts文件夾,再再這個文件夾下新建一個php文件,命名為main.blade.php,在這個文件裡寫上下面這些代碼:
復制代碼 代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>發現Laravel 4之美</title>
</head>
<body>
</body>
</html>
PS:layouts文件夾通常用來存放視圖文件的功用部分,比如一些網頁的頭部<header>和尾部<footer>,這裡就是存放了頭部<header>部分
感覺main.blade.php的名字很奇怪?不用擔心,Laravel的視圖文件命名遵循filename.blade.php的規則,因為Laravel是用Blade這個模板引擎解析的,你不用深究,就照著上面的名字規則來命名視圖文件就OK
為視圖文件添加CSS樣式:
復制代碼 代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>發現Laravel 4之美</title>
{{HTML::style('packages/bower_components/bootstrap/dist/css/bootstrap.min.css') }}
{{ HTML::style('css/main.css')}}
</head>
<body>
</body>
</html>
沒錯,就是在原來的main.blade.php的基礎上添加兩行代碼;然後我們來創建我們的main.css,這個主要是用來放我們自己定義的樣式。在public文件夾下創建css文件夾,在css文件夾創建main.css文件,大功告成。
添加導航欄。在main.blade.php文件的<body>標簽中加上以下代碼:
復制代碼 代碼如下:
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand hidden-sm" href="/">Laravel新手上路</a>
</div>
<ul class="nav navbar-nav navbar-right hidden-sm">
<li>{{ HTML::link('users/register', '注冊') }}</li>
<li>{{ HTML::link('users/login', '登陸') }}</li>
</ul>
</div>
</div>
</body>
上面只是引用了一些簡單的Bootstrap的class,也沒什麼難的,不用傷心。
到這裡基本的功用部分就結束了,但是我們的追求從不會這麼low,所以為了更好地與用戶交互,我們希望在用戶進行某個操作之後給出一些反饋,比如注冊成功的時候說:少年,你已成功注冊本站,恭喜恭喜。等,於是乎,我們再為main.blade.php添加一點點代碼:
復制代碼 代碼如下:
<div class="container">
@if(Session::has('message'))
<p class="alert">{{ Session::get('message') }}</p>
@endif
</div>
為了現實這些反饋信息給用戶,我們得使用Session::get('message')方法,當然,我們得首先從邏輯上判斷一下這個message是否存在,所以這裡用了一個簡單的if判斷。
在blade引擎的視圖中if 的使用格式是
復制代碼 代碼如下:
@if(conditions)
#code...
@endif
到這裡就結束了麼?NO,如果到這裡就結束的話,其他的視圖文件是怎麼插入main.blade.php的<body></body>之間的呢?所以,不要忘了還有一個重要的事:{{ $content }},於是乎,上面的代碼就變成了這樣:
復制代碼 代碼如下:
<div class="container">
@if(Session::has('message'))
<p class="alert">{{ Session::get('message') }}</p>
@endif
{{ $content }}
</div>
{{ $content }}在這裡就是表示其他的視圖文件內容,你可以在理解上將其他的視圖當作一個字符串來理解,只不過這個字符串很長,而且恰好包含了HTML標簽而已。下面你將體會到這種想法。
創建完我們的公用視圖main.blade.php後,我們先來為main.css添加我們的CSS樣式:
復制代碼 代碼如下:
body {
padding-top: 60px;
}
.form-signup, .form-signin {
margin: 0 auto;
}
因為我們在main.blade.php文件中使用了<div class="navbar navbar-inverse navbar-fixed-top">,Bootstrap的navbar高為40px,所以我將body樣式設為padding-top: 60px;避免下面的注冊表單被navbar覆蓋。
終於要進入正題
我擦,前面搞這麼久才進入正題?對的,我說的是從這裡開始我們就開始進入Laravel的Controller世界了,別高潮那麼快,更好的事情還在後頭。
6.創建UsersController
來到app/controllers文件夾,並在這裡創建UsersController.php文件並加入下面的代碼:
復制代碼 代碼如下:
<?php
class UsersController extends BaseController {
}
?>
然後告訴我們的UsersController我們要使用main.blade.php作為我們的layouts,所以:
復制代碼 代碼如下:
<?php
class UsersController extends BaseController {
protected $layout = "layouts.main";
}
?>
這裡使用了路徑別名,你不用layouts/main.blade.php,你只需要layouts.main,Laravel會自動幫你找到layouts下相應的文件。
7.實現注冊
接著為我們的UsersController添加用戶注冊時訪問到的方法:
復制代碼 代碼如下:
public function getRegister() {
$this->layout->content = View::make('users.register');
}
這裡我們將content制定為users/register.blade.php文件(我們等下會創建這個文件),如果你夠細心的話,你可能就注意到了:這裡的content就是上面我們在main.blade.php寫的{{ $content }},也就是說等下渲染視圖的時候,我們的users/register.blade.php文件會替換掉main.blade.php的{{ $content }}進行顯示。現在,清晰了沒?還不清晰?隨時聯系我....如果你不嫌我長得丑的話。
自然而然的,我們現在要做的就是創建users/register.blade.php這個文件了,來到views文件夾 ,創建一個新的文件夾users/,再在裡面新建register.blade.php,寫上下面這些內容:
復制代碼 代碼如下:
{{ Form::open(array('url'=>'users/create', 'class'=>'form-signup')) }}
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">歡迎注冊</h3>
</div>
<div class="panel-body">
{{ Form::open(array('url'=>'users/create', 'class'=>'form-signup')) }}
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
<fieldset>
<div class="form-group">
{{ Form::text('username', null, array('class'=>'form-control', 'placeholder'=>'用戶名')) }}
</div>
<div class="form-group">
{{ Form::text('email', null, array('class'=>'form-control', 'placeholder'=>'郵箱')) }}
</div>
<div class="form-group">
{{ Form::text('password', array('class'=>'form-control', 'placeholder'=>'密碼')) }}
</div>
<div class="form-group">
{{ Form::text('password_confirmation', array('class'=>'form-control', 'placeholder'=>'確認密碼')) }}
</div>
{{ Form::submit('馬上注冊',array('class'=>'btn btn-large btn-success btn-block')) }}
</fieldset>
{{ Form::close() }}
</div>
</div>
</div>
</div>
</div>
這裡我們使用了Laravel的Form類來創建我們的注冊表單,首先調用open()方法,表示創建表單的開始,並且我們也為其通過數組的形式傳人一些參數,url表示表到提交的地址,class就是表示CSS樣式的類。接下來我們使用了:
復制代碼 代碼如下:
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
@foreach循環將每個表單的錯誤信息輸出。因為我們在讓用戶注冊的時候總是要驗證一下用戶輸入的數據是否滿足我們設定的規則,比如郵箱這一欄我們規定它必須為正確的郵箱形式,而如果用戶沒有輸入正確的郵箱格式,我們就會返回錯誤信息給用戶看。That's it.
再下來需要說明的就是幾個Form輸入框的創建方式了:
復制代碼 代碼如下:
{{ Form::text() }} //創建type=text 輸入框
{{ Form::password() }}//創建type=password 輸入框
{{ Form::submit() }}//創建type=submit 輸入框
各個輸入框的值我們都設為null,因為我們用placeholder來更好的替代了,第三個參數是你可以通過一個數組來傳人相應的HTML選項來實現我們的布局,比如上面的array('class'=>'form-control', 'placeholder'=>'確認密碼')等。
最後別忘我們要用{{ Form::close() }}來結束表單。
到這裡我們就把注冊頁面搞定了,緊接下來就是正確地設置好我們的路由以使我們能正確訪問到我們的getRegister()方法。於是,帶著神聖的使命感,我們打開app/routes.php這個文件,首先可以將裡面的:
復制代碼 代碼如下:
Route::get('/', function()
{
return View::make('hello');
});
這幾行代碼干掉(你可以注視掉或者直接刪了,建議是注釋),然後再添上下面這一行代碼;
Route::controller('users', 'UsersController');
注意到第一個參數users沒,這個告訴就是說我們在訪問UsersController的方法的時候我們遵循下面這個格式:
/users/actionName
比如我們想訪問UsersController的getRegister(),我們可以在浏覽器地址欄輸入的格式是:
/users/register
於是,打開你的浏覽器,在地址欄輸入:
http://localhost:8000/users/register
見證奇跡吧。是不是很爽!哈哈哈。
如果現在你在這個注冊表單添上相應的注冊信息,然後點擊注冊的話,你會得到一個意外的錯誤:NotFoundHttpException!那是因為我們還沒有為注冊表單寫提交地址:users/create。所以我們自然要來到UsersController中,為其添上postCreate():
復制代碼 代碼如下:
public function postCreate() {
}
這樣我們就把地址users/create正確地搞定了,只是我們還沒有為其添加相應的條件判斷語句,因為我們首先要在這裡說明一點就是:getRegister()和postCreate()的不同,沒錯前面的get或post就是代表http的提交方式,我們在注冊表單中使用的是post方法,所以這裡要使用postCreate()。
說明上面的細節之後,我們還要做一件非常重要的事:表單驗證。即是先在用戶提交表單的時候驗證其輸入數據的合法性,以便於我們在數據庫中能存儲正確的數據,這裡就聯系到前面的:
復制代碼 代碼如下:
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
這裡的$error就是我們在用戶輸入數據不合法的時候返回給用戶的錯誤提示信息。所以,我們現在app/models/User.php中添加我們的表單驗證規則(我一般將驗證規則放在模型modal中):
復制代碼 代碼如下:
public static $rules = array(
'username'=>'required|alpha|min:2',
'email'=>'required|email|unique:users',
'password'=>'required|alpha_num|between:6,12|confirmed',
'password_confirmation'=>'required|alpha_num|between:6,12'
);
說明一下上面的一些規則表示什麼意思:
required:必填的,不能為空
alpha:字母
email:郵件格式
unique:users:唯一,參考users表的設置
alpha_num:字母或數字
between:長度位於哪兩個數字之間
confirmed:需要確認的
在我們有了驗證規則,我們再來完善我們的postCreate(),即為其添加一些條件判斷使用戶在注冊時可以保存用戶的注冊信息和進一步引導用戶到登陸頁面:
我們來一步一步地理清思路:首先判斷用戶提交的數據是否通過了驗證
復制代碼 代碼如下:
public function postCreate() {
$validator = Validator::make(Input::all(), User::$rules);
if ($validator->passes()) {
// 驗證通過就存儲用戶數據
} else {
// 驗證沒通過就顯示錯誤提示信息
}
}
}
上面我們通過Input::all()來獲取表單傳過來的值,又調用User::$rules來獲得驗證規則,最後通過把這兩個以參數的形式傳入Validator::make()實現驗證,下面的判斷語句就很清晰了,驗證通過後干嘛,沒通過又該干嘛。思路清晰就OK。
接著我們再來完善我們的postCreate()代碼:
復制代碼 代碼如下:
if ($validator->passes()) {
$user = new User;//實例化User對象
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->save();
return Redirect::to('users/login')->with('message', '歡迎注冊,好好玩耍!');
} else {
// 驗證沒通過就顯示錯誤提示信息
}
上面的我們通過Input::get('fieldName')來獲得相應的表單輸入框的值,這裡需要注意的是我們對密碼進行了加密,因為我們都是棒棒的工程師,不會像之前的CSDN一樣保存明文密碼的,所以在密碼這一欄我們使用Hash::make()來加密傳入的密碼。然後我們通過$user->save()來將我們的數據保存到數據庫中。數據保存之後,我們用Redirect::to()將頁面跳轉到users/login,並通過width將注冊成功的信息返回給用戶。
Redirect::to()的參數規則是:controller/action。前面是控制起,後面就是具體的方法名。
上面是驗證通過的情況,現在我們看看驗證沒有通過的情況:
復制代碼 代碼如下:
if ($validator->passes()) {
$user = new User;//實例化User對象
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->save();
return Redirect::to('users/login')->with('message', '歡迎注冊,好好玩耍!');
} else {
return Redirect::to('users/register')->with('message', '請您正確填寫下列數據')->withErrors($validator)->withInput();
}
這裡如果用戶沒有通過驗證,我讓其重定向到注冊頁,並通過withErrors($validator)將錯誤信息傳到注冊頁面,通過withInput()將沒有輸錯的數據也傳給注冊頁面(正確來說是傳給register方法,不過你可以根據上面那樣理解,個人覺得也還OK),這樣一來,我們就有了錯誤信息和一些正確的表單信息(不用用戶多次輸入),以提高整個過程的用戶體驗。
再進一步,我們在開發的時候永遠不要忘記一件很重要的事:安全。那麼在這裡我們需要POST提交表單,我們就要保證它不會被CSRF攻擊,解決這個問題我們需要在UsersController裡添加下面的代碼:
復制代碼 代碼如下:
public function __construct() {
$this->beforeFilter('csrf', array('on'=>'post'));
}
構造方法請放在其他方法前面。
8.實現登錄
接下來的一步就是創建login的視圖文件了,我們依舊來到我們最熟悉的views/users/下,新建文件名為login.blade.php的文件,在裡面放上以下的代碼:
復制代碼 代碼如下:
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">歡迎登錄</h3>
</div>
<div class="panel-body">
{{ Form::open(array('url'=>'users/signin', 'class'=>'form-signin')) }}
<fieldset>
<div class="form-group">
{{ Form::text('email', null, array('class'=>'form-control', 'placeholder'=>'郵箱')) }}
</div>
<div class="form-group">
{{ Form::password('password', array('class'=>'form-control', 'placeholder'=>'密碼')) }}
</div>
{{ Form::submit('馬上登錄',array('class'=>'btn btn-large btn-success btn-block')) }}
</fieldset>
{{ Form::close() }}
<hr/>
</div>
</div>
</div>
</div>
</div>
這裡的一些要點跟register.blade.php一樣,你不明白的話可以看看前面的。然後我們需要在UsersController裡面定義getLogin()方法:
復制代碼 代碼如下:
public function getLogin() {
$this->layout->content = View::make('users.login');
}
這裡也是指定了content的模版為users/login.blade.php,道理跟前面一樣。
這時候我們就可以注冊新用戶了,如果你的浏覽器還保留在http://localhost:8000/users/register你可以試著輸入你的用戶名,郵箱,密碼來注冊一個,當然你也可以故意輸錯,看看會有什麼信息返回給你。enjoy!
正常情況下,你注冊完之後就吼跳到登錄界面(已經寫好了),但是我們在登錄的時候也需要驗證,如果你仔細看上面的login.blade.php的話,你會發現我們在這裡將用戶的登錄表單提交地址設置為
'url'=>'users/signin',所以接下來的一步就是為UsersController補充postSignin()方法:
復制代碼 代碼如下:
public function postSignin() {
if (Auth::attempt(array('email'=>Input::get('email'), 'password'=>Input::get('password')))) {
return Redirect::to('users/dashboard')->with('message', '歡迎登錄');
} else {
return Redirect::to('users/login')->with('message', '用戶名或密碼錯誤')->withInput();
}
}
這裡我們使用Auth類來驗證用戶輸入的信息是否和數據庫的信息一致,如果驗證通過,那麼我們就將用戶重定向到users/dashboard,如果沒通過,就重新跳回登錄頁,情況跟注冊時候幾乎一模一樣,我相信你看得懂。
既然是重定向到users/dashboard那麼我們就來寫寫getDashboard()方法,到這裡可能不用我說你都知道應該在UsersController添加下面的代碼:
復制代碼 代碼如下:
public function getDashboard() {
$this->layout->content = View::make('users.dashboard');
}
這裡再多說一句,這個Dashboard的頁面一般是在登錄後才能看到的,為了限制一些沒登錄的人到處亂逛,我們只需要在UsersController中的構造函數加一行代碼,變成這樣的:
復制代碼 代碼如下:
public function __construct() {
$this->beforeFilter('csrf', array('on'=>'post'));
$this->beforeFilter('auth', array('only'=>array('getDashboard')));
}
現在邏輯是不是很清晰,我們接下來的一步自然是創建dashboard.blade.php文件了,這個從getDashboard()看出我們依然是將這個視圖文件存在views/users/目錄下,我們就簡單地在dashboard.blade.php寫上幾行入門級的HTML:
復制代碼 代碼如下:
<div class="welcome">
<center>
<a href="http://www.jellybool.com" target="_blank">
<img src="https://wt-prj.oss.aliyuncs.com/766e22da1e8c467a8af35d90c9185409/7680dd9d-c0e4-42ea-86b8-ddd63d07faa6.png" >
</a>
</center>
<center><h1>歡迎來到管理面板!</h1></center>
</div>
寫到這裡我們還不能登錄,因為在Laravel中auth過濾(filter)會默認將沒登錄的用戶重定向到/login,但我們需要的是重定向到users/login,所以我們需要自定義我們的filter規則,打開app/filter.php,在代碼的開始加上下面的代碼:
復制代碼 代碼如下:
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::guest('users/login');
});
到這裡就大功告成了,如果你之前注冊了一個用戶,請用你的郵箱和密碼到
http://localhost:8000/users/login
嘗試登錄一下,你會發現:Bingo!!!登錄進去了!
9.實現退出
但是細心的你發現了沒,我們還有一個需要完善的地方.....沒錯!就是我們的導航,我們已經登錄進去了,它還是顯示登錄和注冊,不科學啊!所以回到最初我們的main.blade.php在鏈接部分我們將它改為:
復制代碼 代碼如下:
<ul class="nav navbar-nav navbar-right hidden-sm">
@if(!Auth::check())
<li>{{ HTML::link('users/register', '注冊') }}</li>
<li>{{ HTML::link('users/login', '登陸') }}</li>
@else
<li>{{ HTML::link('users/logout', '退出') }}</li>
@endif
</ul>
沒錯,我們為導航這裡加入了條件判斷語句,如果用戶沒有通過Auth::check(),也就是沒有登錄的話,我們顯示登錄和注冊,如果登錄了就顯示退出,
既然有了users/logout這個鏈接,那麼我們就會想到在UsersController寫這個getLogout()方法,而且這個方法是負責清理用戶的登錄信息的,所以:
復制代碼 代碼如下:
public function getLogout() {
if(Auth::check())
{
Auth::logout();
}
return Redirect::to('users/login')->with('message','你現在已經退出登錄了!');
}
這裡我們Auth::logout()將用戶的登錄信息(主要就是session信息)清除掉,然後再將用戶重定向到登錄界面。
10.最後的最後
這個小教程寫到這裡就基本結束了,希望各位玩的愉快。最後多說一句:編程是我們最容易學習的超能力,永遠要相信自己可以改變世界!