Laravel大型項目系列教程(一)
一、課程概述
1.課程介紹
本教程將使用Laravel完成一個多用戶的博客系統,大概會包含如下內容:
- 路由管理。
- 用戶管理,如用戶注冊、修改信息、鎖定用戶等。
- 文章管理,如發表文章、修改文章等。
- 標簽管理,文章會有一到多個標簽。
- 數據庫管理,如遷移、填充數據等。
- Web表單驗證。
- Blade模版引擎。
- 分頁處理。
- 安全處理。
- 單元測試。
- 部署到應用服務器Apache。
盡量保證每節教程完整並能運行,會在教程的最后附上這節教程的代碼下載地址。
Tip:教程中必要的知識點都會有一個超鏈接
二、環境要求
- PHP 5.4+
- MySQL 5.1+
- Composer([中國鏡像](http://pkg.phpcomposer.com/))
三、Let's go!
1.新建一個Laravel項目
使用如下命令創建一個名為blog的Laravel項目:
$ composer create-project laravel/laravel blog --prefer-dist
創建完成之后進入到blog目錄,修改app/config/app.php
中的timezone
為RPC
、locale
為zh
,然后在blog目錄下啟動它自帶的開發服務器:
$ php artisan serve Laravel development server started on http://localhost:8000
打開瀏覽器輸入localhost:8000
,如果頁面如下圖就說明項目搭建完成了:
2.安裝插件
在composer.json
中增加:
"require-dev": { "way/generators": "~2.0" },
運行composer update
安裝,完成后在app/config/app.php
的providers
中增加:
'Way\Generators\GeneratorsServiceProvider'
運行php artisan
是不是多了generate
選項,它可以快速地幫我們創建想要的組件。
3.建立數據庫
把app/config/database.php
中connections
下的mysql
改成你自己的配置:
'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'blog', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ),
需要在MySQL中先創建一個名為blog的數據庫
配置完成之后,創建users表的數據庫遷移文件:
$ php artisan migrate:make create_users_table --create=users
我們會發現在app\database\migrations
下多了一個*_create_users_table.php
文件,在這個文件中修改:
Schema::create('users', function(Blueprint $table) { $table->increments('id'); $table->string('email'); $table->string('password'); $table->string('nickname'); $table->boolean('is_admin')->default(0); $table->boolean('block')->default(0); $table->timestamps(); });
之后進行數據庫遷移:
$ php artisan migrate
你會驚訝地發現在數據庫中多了兩張表users
和migrations
,users
表就是我們定義的表,migrations
表記錄了遷移的信息。
4.創建User模型
數據庫遷移完成之后我們將使用Eloquent ORM,這是Laravel讓人着迷的重要原因之一。我們會發現在app\models
下已經有一個User.php
文件了,對其修改:
use Illuminate\Auth\UserInterface; use Illuminate\Auth\UserTrait; class User extends Eloquent implements UserInterface { use UserTrait; protected $table = 'users'; protected $hidden = array('password', 'remember_token'); }
5.填充數據
有了User模型后,我們就可以向數據庫填充數據了,在app/database/seeds
下創建一個名為UsersSeeder.php
的文件,增加如下:
class UsersSeeder extends Seeder { public function run() { User::create([ 'email' => 'admin@shiyanlou.com', 'password' => Hash::make(''), 'nickname' => 'admin', 'is_admin' => 1, ]); } }
然后在DatabaseSeeder.php
中增加:
$this->call('UserTableSeeder');
之后就真正地向數據庫填充數據:
$ php artisan db:seed
你可以查看數據庫,會發現users表中多了一條記錄。
詳情可以查看Laravel中數據庫的遷移和填充
6.創建視圖模版
我們將使用Laravel中的Blade模版引擎,使用下面命令創建三個視圖:
php artisan generate:view _layouts.default php artisan generate:view _layouts.nav php artisan generate:view _layouts.footer php artisan generate:view index
之后你可以在app/views
下發現多了一個index.blade.php
和一個_layouts
文件夾,在_layouts
文件夾下有三個文件default.blade.php
、footer.blade.php
和nav.blade.php
。我們將使用AmazeUI框架來做為前端框架,修改default.blade.php
:
<!DOCTYPE html> <html> <head lang="zh"> <meta charset="UTF-8"/> <title>ShiYanLou Blog</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="format-detection" content="telephone=no"/> <meta name="renderer" content="webkit"/> <meta http-equiv="Cache-Control" content="no-siteapp"/> <link rel="alternate icon" type="image/x-icon" href="{{ URL::asset('i/favicon.ico') }}"/> <link rel="stylesheet" href="//cdn.amazeui.org/amazeui/2.1.0/css/amazeui.min.css"/> {{ HTML::style('css/custom.css') }} </head> <body> <header class="am-topbar am-topbar-fixed-top"> <div class="am-container"> <h1 class="am-topbar-brand"> <a href="/">ShiYanLou Blog</a> </h1> @include('_layouts.nav') </div> </header> @yield('main') @include('_layouts.footer') <script src="//cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script> <script src="//cdn.amazeui.org/amazeui/2.1.0/js/amazeui.min.js"></script> </body> </html>
URL::asset('i/favicon.ico')
會生成http://localhost:8000/i/favicon.ico
,HTML::style('css/custom.css')
會生成<link media="all" type="text/css" rel="stylesheet" href="http://localhost:8000/css/custom.css">
,其中的i
和css
文件夾是放在public
目錄下的,public
目錄是項目的資源文件夾。@include('_layouts.nav')
會包含app/views/_layouts/nav.blade.php
文件,@yield('main')
是用於模版繼承的。
修改nav.blade.php
:
<button class="am-topbar-btn am-topbar-toggle am-btn am-btn-sm am-btn-secondary am-show-sm-only" data-am-collapse="{target: '#collapse-head'}"><span class="am-sr-only">nav switch</span> <span class="am-icon-bars"></span></button> <div class="am-collapse am-topbar-collapse" id="collapse-head"> <div class="am-topbar-right"> <a href="#" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a> </div> </div>
修改footer.blade.php
:
<footer class="footer">
<p>© 2015 By <a href="http://www.shiyanlou.com" target="_blank">www.shiyanlou.com</a></p>
</footer>
修改index.blade.php
:
@extends('_layouts.default') @section('main') <div class="am-g am-g-fixed blog-g-fixed"> <div class="am-u-sm-12"> <h1>Welcome to ShiYanLou!</h1> </div> </div> @stop
@extends('_layouts.default')
會繼承app/views/_layouts/default.blade.php
文件,@yield('main')
對應@section('main')
並填充為其中的內容。
在public
目錄下新建兩個文件夾i
和css
,在i
文件夾里放置一個名為favicon.ico
的圖標,在css
文件夾下新建一個名為custom.css
的文件,修改如下:
.footer p { color: #7f8c8d; margin: 0; padding: 15px 0; text-align: center; background: #2d3e50; } .topbar-link-btn { color: #fff !important; }
7.修改路由訪問首頁
視圖已經有了,這時候需要把路由跟視圖進行關聯,修改app/routes.php
如下:
Route::get('/', function() { return View::make('index'); });
不出意外,這時候訪問localhost:8000
會出現下圖這樣:
終於見到了親手編寫的第一個頁面,是不是有點小激動啊?
8.創建登錄視圖
在nav.blade.php
中修改登錄超鏈接的地址:
<a href="{{ URL::to('login') }}" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a>
URL::to('login')
會生成http://localhost:8000/login
這個地址。
創建login.blade.php
:
$ php artisan generate:view login
修改login.blade.php
:
@extends('_layouts.default') @section('main') <div class="am-g am-g-fixed"> <div class="am-u-lg-6 am-u-md-8"> <br/> @if (Session::has('message')) <div class="am-alert am-alert-danger" data-am-alert> <p>{{ Session::get('message') }}</p> </div> @endif @if ($errors->has()) <div class="am-alert am-alert-danger" data-am-alert> <p>{{ $errors->first() }}</p> </div> @endif {{ Form::open(array('url' => 'login', 'class' => 'am-form')) }} {{ Form::label('email', 'E-mail:') }} {{ Form::email('email', Input::old('email')) }} <br/> {{ Form::label('password', 'Password:') }} {{ Form::password('password') }} <br/> <label for="remember_me"> <input id="remember_me" name="remember_me" type="checkbox" value="1"> Remember Me </label> <br/> <div class="am-cf"> {{ Form::submit('Login', array('class' => 'am-btn am-btn-primary am-btn-sm am-fl')) }} </div> {{ Form::close() }} <br/> </div> </div> @stop
在routes.php
中增加:
Route::get('login', function() { return View::make('login'); });
這時候訪問localhost:8000/login
或者點擊導航條的Login
按鈕會出現下圖這樣:
9.實現登錄
創建用戶登錄后主頁:
$ php artisan generate:view home
修改home.blade.php
:
@extends('_layouts.default') @section('main') <div class="am-g am-g-fixed blog-g-fixed"> <div class="am-u-sm-12"> <h1>Hello {{{ Auth::user()->nickname }}}</h1> </div> </div> @stop
上面的{{{ }}}
可以對字符串做轉義處理,一定程度上避免XSS攻擊。
修改nav.blade.php
:
<div class="am-collapse am-topbar-collapse" id="collapse-head"> @if (Auth::check()) <ul class="am-nav am-nav-pills am-topbar-nav am-topbar-right"> <li class="am-dropdown" data-am-dropdown> <a class="am-dropdown-toggle" data-am-dropdown-toggle href="javascript:;"> <span class="am-icon-users"></span> {{{ Auth::user()->nickname }}} <span class="am-icon-caret-down"></span> </a> <ul class="am-dropdown-content"> <li><a href="{{ URL::to('logout') }}"><span class="am-icon-power-off"></span> Exit</a></li> </ul> </li> </ul> @else <div class="am-topbar-right"> <a href="{{ URL::to('login') }}" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a> </div> @endif </div>
在Routes.php
中增加:
Route::post('login', array('before' => 'csrf', function() { $rules = array( 'email' => 'required|email', 'password' => 'required|min:6', 'remember_me' => 'boolean', ); $validator = Validator::make(Input::all(), $rules); if ($validator->passes()) { if (Auth::attempt(array( 'email' => Input::get('email'), 'password' => Input::get('password'), 'block' => 0), (boolean) Input::get('remember_me'))) { return Redirect::intended('home'); } else { return Redirect::to('login')->withInput()->with('message', 'E-mail or password error'); } } else { return Redirect::to('login')->withInput()->withErrors($validator); } })); Route::get('home', array('before' => 'auth', function() { return View::make('home'); }));
下面就可以嘗試用戶登錄了,如果輸入信息有誤,會出現錯誤信息如:
登錄成功后會出現下圖這樣:
這里我們使用了Laravel自帶的身份驗證Auth,你也可以使用更加強大的Sentry,Web表單驗證用了Validator,View和Redirect詳細可以查看視圖和響應文檔,還使用了路由過濾器,csrf
過濾器可以使我們輕松地防御csrf
攻擊。
10.退出登錄
在routes.php
中增加:
Route::get('logout', array('before' => 'auth', function() { Auth::logout(); return Redirect::to('/'); }));
現在你就可以實現退出功能了,點擊Exit
:
退出后會跳轉到主頁。
11.小結
至此簡單的用戶登錄功能就完成了,你除了要完成上述的例子外,還要完成記住我
的功能哦!你可以通過下面途徑來完成:
代碼下載:
$ git clone https://github.com/shiyanlou/laravel-blog-1.git