1. 視圖分離與嵌套
在 learnlaravel 文件夾下運行命令:
php artisan generate:view admin._layouts.default
這時候generator插件幫我們創建了app/views/admin/_layouts/default.blade.php 文件,將內容修改為:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Laravel 4</title>
@include('admin._partials.assets')
</head>
<body>
<div class="container">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="{{ URL::route('admin.pages.index') }}">Learn Laravel 4</a>
@include('admin._partials.navigation')
</div>
</div>
</div>
<hr>
@yield('main')
</div>
</body>
</html>
這就是視圖文件,MVC中的V。視圖需要仔細講一下。
views文件夾為視圖文件夾,視圖文件夾可以嵌套,就像我上面一樣創建了admin/_layout嵌套文件夾,在裡面創建了一個叫default.blade.php的文件,那麼以後我們在Laravel內任何地方要用到這個視圖的時候,他就叫admin._layouts.default。
我們看到,上面代碼的第七行是“@include('admin._partials.assets')”,根據上面我們剛剛了解的知識,這表示載入了另外一個文件。blade是Laravel的模板引擎,此處的 @include 表示直接把那個文件的所有代碼帶入進來放到這裡,變成當前視圖的一部分。
注意看第25行“@yield('main')”,這表示什麼呢?這個有點復雜,我們稍後再講。
2. 權限驗證
Laravel支持標准HTTP認證,但是在此處我們需要構建blog系統,所以我們將編寫完善的管理員登陸系統,從頁面登錄。
用命令行創建app/views/admin/auth/login.blade.php文件,代碼如下:
@extends('admin._layouts.default')
@section('main')
<div id="login" class="login">
{{ Form::open() }}
@if ($errors->has('login'))
<div class="alert alert-error">{{ $errors->first('login', ':message') }}</div>
@endif
<div class="control-group">
{{ Form::label('email', 'Email') }}
<div class="controls">
{{ Form::text('email') }}
</div>
</div>
<div class="control-group">
{{ Form::label('password', 'Password') }}
<div class="controls">
{{ Form::password('password') }}
</div>
</div>
<div class="form-actions">
{{ Form::submit('Login', array('class' => 'btn btn-inverse btn-login')) }}
</div>
{{ Form::close() }}
</div>
@stop
大家應該注意到了前兩行:
@extends('admin._layouts.default')@section('main')
這代表什麼?實際上,以後我們會了解到,在controller中調用view的時候,調用的只是這個login.blade.php文件,第一行表示,此視圖是admin._layouts.default的子視圖,這時blade引擎會把這個視圖也載入進來,怎麼組裝呢?這時候下面那個@section('main')就該出場了,被它包裹的代碼將會直接放到admin._layouts.default中的@yield('main')中。section和yield可以任意搭配,只要兩個視圖之間有調用關系,他們就可以這樣用,非常靈活。
寫到這裡大家可能有個疑問,為什麼示例代碼裡空行那麼多?這一點就是個人經驗了。blade引擎的所有標簽都會在視圖編譯時用正則處理,引擎本身有一個問題,算不上bug,就是換行符會被處理掉,導致前後行和這一行都緊緊地擠在一起,在前端浏覽器中“查看源代碼”時,比較不清晰,前後加上空行可以解決這個問題。當然這可能是一個自動的“壓縮”特性,不再深入討論。
增加控制器文件app/controllers/admin/AuthController.php,這時候有人就說了,這我知道,哈哈,運行
“php artisan generate:controller admin.AuthController”
這個想法是對的,但你運行一下試試?會直接在app/controllers目錄下創建一個“admin.AuthController.php”文件,有人又說,那我用“admin/AuthController”總行了吧,你試一下?也不行。所以我們要先在app/controllers 下手動創建 admin 文件夾,這時候,再命令行輸入:
php artisan generate:controller admin/AuthController
這樣就可以了。接下來改寫AuthController.php 的內容為:
<?php
namespace App\Controllers\Admin;
use Auth, BaseController, Form, Input, Redirect, Sentry, View;
class AuthController extends BaseController {
/**
* 顯示登錄頁面
* @return View
*/
public function getLogin()
{
return View::make('admin.auth.login');
}
/**
* POST 登錄驗證
* @return Redirect
*/
public function postLogin()
{
$credentials = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
try
{
$user = Sentry::authenticate($credentials, false);
if ($user)
{
return Redirect::route('admin.pages.index');
}
}
catch(\Exception $e)
{
return Redirect::route('admin.login')->withErrors(array('login' => $e->getMessage()));
}
}
/**
* 注銷
* @return Redirect
*/
public function getLogout()
{
Sentry::logout();
return Redirect::route('admin.login');
}
}
這就是我們登錄、注銷的控制器,MVC中的C。接下來我將講解命名空間,這是Laravel的基礎,或者說是composer的基礎,是整個Laravel教程中的重點、難點,希望大家锱铢必較,任何不懂都不要放過。可以到phphub論壇或者golaravel論壇相應帖子下面提問,或者直接發帖提問。
我們首先觀察這個文件的位置,它位於 app/controllers/admin 目錄下,這有什麼不同呢?在其他框架如 CI 中,子文件夾直接加上文件夾名就可以直接調用到了,雖然最多只能有一層。而Laravel沒有這麼簡單,涉及到了PHP的命名空間。
1. composer 支持 PSR-0 及 PSR-4 標准,標准規定 PHP 包以命名空間為區分,向外提供服務,所有暴露出來的類都應該在 \作者名\包名 命名空間下,例如 \lui\MFFC\Mail 類。這樣,哪怕是名稱一樣的包只要是不同作者也可以在https://packagist.org/上共存,供大家使用。
2. 命名空間可以類比成 Linux 系統中的 目錄,在任何目錄下都可以直接使用文件名打開當前目錄下的所有文件和可執行程序,如果需要打開其他目錄下的文件,就需要使用絕對路徑或者相對路徑。
3. 大家可能在許多其他教程中見到過controller頭部沒有 namesapce 申明,更沒有那一堆的 use xxx,像這個文件https://github.com/cecoo/laravel4demo/blob/master/app/controllers /BlogController.php。這個文件在第8行直接使用了 Blog 這個類,這是為什麼呢?
因為他們都已經在 learnlaravel 這個 composer 應用的配置文件中聲明為自動加載了,而他們沒有在頂部聲明他們所在的命名空間,這樣就會被自動加為頂級命名空間。這個配置文件是 composer.json,對象配置項為autoload 下的classmap 項。這個聲明會讓 Composer 在生成自動載入文件的時候,自動掃描該文件下所有的類以及所有子文件夾中的類,只要沒有聲明特定的命名空間,將會被自動加載為頂級空間。【之前表述有誤,特此更正!】
關於命名空間更多詳情,可以參考 【PHP 命名空間 入門】。
OK,到目前為止我們的MVC三元素已經集齊了,那接下來該做什麼了呢?配置路由。這裡的路由並不是家裡用的無線路由 :-D,而是 用戶請求的URL到控制器某個方法的轉換,function是PHP中代碼段的最小單位,所以用戶請求的一個路徑,如 http://ooxx.com/fuck/me ,這條URL打給路由之後,路由就會去解析,應該調用哪個function,最終返回結果給用戶。
Laravel的路由采用閉包的方式返回結果,在app/routes.php 中增加下列內容:
Route::get('admin/logout', array('as' => 'admin.logout', 'uses' => 'App\Controllers\Admin\AuthController@getLogout'));
Route::get('admin/login', array('as' => 'admin.login', 'uses' => 'App\Controllers\Admin\AuthController@getLogin'));
Route::post('admin/login', array('as' => 'admin.login.post', 'uses' => 'App\Controllers\Admin\AuthController@postLogin'));
Route::group(array('prefix' => 'admin', 'before' => 'auth.admin'), function()
{
Route::any('/', 'App\Controllers\Admin\PagesController@index');
Route::resource('articles', 'App\Controllers\Admin\ArticlesController');
Route::resource('pages', 'App\Controllers\Admin\PagesController');
});
前三條的意思是hold住兩個get請求和一個post請求,下面是一個路由組,規定了一個前綴admin,增加了一個過濾器,auth.admin,內部有一個能同時適應get和post請求的‘/'路徑,其完整路徑是 http://ooxx.com/admin/。剩下的兩個資源控制器本質上只是一種簡寫,URL和控制器類中的方法名的對應表見 資源控制器。
上面說的那個過濾器 auth.admin,是Laravel提供的一個請求過濾器,這個文件就在路由文件的旁邊,app/filters.php,在文件末尾增加:
Route::filter('auth.admin', function()
{
if ( ! Sentry::check()) {
return Redirect::route('admin.login');
}
});
這樣我們的權限驗證就完成了。上面的代碼意思是,在進入這個路由組中的任何一條路由之前,會先過一遍 auth.admin這個filter,這個filter會調用Sentry::check(),如果為false,將會進入if代碼塊,將用戶的請求跳轉到 命名路由‘admin.login',命名路由文檔。從這個命名路由的名稱大家也能看出來,就是跟訪客說:傻逼,干啥呢,登錄去~
這裡的“命名路由”功能是為了模仿 Ruby On Rails 的 “link_to”到對象 的路由綁定功能,無奈PHP上傳即部署無守護進程的特性,使得我們沒法維護一個全量代碼的路由表,沒法像Rails那樣實現 資源路由-資源對象-路由調用 三者綁定的功能,只能搞出一個半成品命名路由,人為地解決了當調整 /people 到 /human 時,要求名稱改變而功能不變,同時要求代碼自適應的需求。
這時候,我們就可以嘗試訪問我們的項目了。推薦配置Apache將一個端口指向learnlaravel這個項目的public目錄下,即項目通過 http://127.0.0.1:8080 這樣的地址訪問,十分不建議從子文件夾訪問。如果你不會,可以運行
php artisan serve
啟動PHP5.4的內建HTTP服務器。地址將會是http://localhost:8000,注意此處 127.0.0.1 不可以訪問。
下面,我們在浏覽器中訪問 /admin,注意URL會自動跳轉到 /admin/login,這說明我們的filter起作用了,但你可能得到以下頁面
這說明代碼出錯了。接下來我們修改 app/config/app.php 第一項為:
'debug' => true,
刷新頁面,錯誤提示出來了!有沒有感覺Laravel4.2的錯誤提示很好看啊,確實不錯,但我覺得沒有4.1之前的好看 :-D。我得到了如下錯誤:
說“App\Controllers\Admin\AuthController”這個類未找到,這是為什麼呢?這個文件明明有啊。
這就涉及到了另一個問題,Laravel中的autoload問題。Laravel基於命名空間,它只會自動加載所有頂級命名空間的類,就是說我們新增的這個控制器類不是在頂級命名空間下,所以就需要告訴Laravel,我這個類是存在的,怎麼告訴它呢?運行
composer dump-autoload
可以了,刷新頁面,他告訴我
View [admin._partials.assets] not found.
這個確實是,我們還沒建立這個文件呢。建立一個空文件即可,如果是用generator建的話,別忘了把裡面默認的內容刪掉哦。再刷新頁面,如果還有問題,我相信這個問題你可以自己解決。
OK,一個丑的一逼的頁面出現了,為什麼它這麼丑?(鴿子為什麼這麼大?)因為我們沒有引入任何css和js文件,甚至連導航欄的html都不完整。這不要緊,來,按照我github上的代碼,自己復制到相應文件中吧。另外,非常重要的一點,把我的項目中的public文件下的 js 和 css 兩個文件夾完全復制到你們的public文件夾中。
再刷新,如果你看到以下頁面,說明你成功了!
3. 嘗試登錄
用seed新增一名管理員,順便新增一個管理員組。新建app/database/seeds/SentrySeeder.php,內容為:
<?php
class SentrySeeder extends Seeder {
public function run()
{
DB::table('users')->delete();
DB::table('groups')->delete();
DB::table('users_groups')->delete();
Sentry::getUserProvider()->create(array(
'email' => '[email protected]',
'password' => "ooxx",
'first_name' => 'OO',
'last_name' => 'XX',
'activated' => 1,
));
Sentry::getGroupProvider()->create(array(
'name' => 'Admin',
'permissions' => ['admin' => 1],
));
// 將用戶加入用戶組
$adminUser = Sentry::getUserProvider()->findByLogin('[email protected]');
$adminGroup = Sentry::getGroupProvider()->findByName('Admin');
$adminUser->addGroup($adminGroup);
}
}
給app/database/seeds/DatabaseSeeder.php 新增一行:
$this->call('SentrySeeder');
然後運行:
php artisan db:seed
成功以後,進數據庫就會發現,users、groups、users_groups表均新增了一行。但是,articles和pages表也分別新增了10行,對,seed就是這麼蠢萌^_^
讓我們來嘗試登錄!如果你得到:
Class App\Controllers\Admin\PagesController does not exist
這說明你成功了!
它可以讓你從面條一樣雜亂的代碼中解脫出來;它可以幫你構建一個完美的網絡APP,而且每行代碼都可以簡潔、富於表達力。1、Bundle是Laravel的擴展包組織形式或稱呼。Laravel的擴展包倉庫已經相當成熟了,可以很容易的幫你把擴展包(bundle)安裝到你的應用中。你可以選擇下載一個擴展包(bundle)然後拷貝到bundles目錄,或者通過命令行工具“Artisan”自動安裝。2、在Laravel中已經具有了一套高級的PHP ActiveRecord實現 -- Eloquent ORM。它能方便的將“約束(constraints)”應用到關系的雙方,這樣你就具有了對數據的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查詢構造器(query-builder)的所有方法。3、應用邏輯(Application Logic)可以在控制器(controllers)中實現,也可以直接集成到路由(route)聲明中,並且語法和Sinatra框架類似。Laravel的設計理念是:給開發者以最大的靈活性,既能創建非常小的網站也能構建大型的企業應用。4、反向路由(Reverse Routing)賦予你通過路由(routes)名稱創建鏈接(URI)的能力。只需使用路由名稱(route name),Laravel就會自動幫你創建正確的URI。這樣你就可以隨時改變你的路由(routes),Laravel會幫你自動更新所有相關的鏈接。5、Restful控制器(Restful Controllers)是一項區分GET和POST請求邏輯的可選方式。比如在一個用戶登陸邏輯中,你聲明了一個get_login()的動作(action)來處理獲取登陸頁面的服務;同時也聲明了一個post_login()動作(action)來校驗表單POST過來的數據,並且在驗證之後,做出重新轉向(redirect)到登陸頁面還是轉向控制台的決定。6、自動加載類(Class Auto-loading)簡化了類(class)的加載工作,以後就可以不用去維護自動加載配置表和非必須的組件加載工作了。當你想加載任何庫(library)或模型(model)時,立即使用就行了,Laravel會自動幫你加載需要的文件。7、視圖組裝器(View Composers)本質上就是一段代碼,這段代碼在視圖(View)加載時會自動執行。最好的例子就是博客中的側邊隨機文章推薦,“視圖組裝器”中包含了加載隨機文章推薦的邏輯,這樣,你只需要加載內容區域的視圖(view)就行了,其它的事情Laravel會幫你自動完成。8、反向控制容器(IoC container)提供了生成新對象、隨時實例化對象、訪問單例(singleton)對象的便捷方式。反向控制(IoC)意味著你幾乎不需要特意去加載外部的庫(libraries),就可以在代碼中的任意位置訪問這些對象,並且不需要忍受繁雜、冗余的代碼結構。9、遷移(Migrations)就像是版本控制(version control)工具,不過,它管理的是數據庫范式,並且直接集成在了Laravel中。你可以使用“Artisan”命令行工具生成、執行“遷移”指令。當你的小組成員改變了數據庫范式的時候,你就可以輕松的通過版本控制工具更新當前工程,然後執行“遷移指令即可,好了,你的數據庫已經是最新的了!11、自動分頁(Automatic Pagination)功能避免了在你的業務邏輯中混入大量無關分頁配置代碼。方便的是不需要記住當前頁......余下全文>>
它可以讓你從面條一樣雜亂的代碼中解脫出來;它可以幫你構建一個完美的網絡APP,而且每行代碼都可以簡潔、富於表達力。1、Bundle是Laravel的擴展包組織形式或稱呼。Laravel的擴展包倉庫已經相當成熟了,可以很容易的幫你把擴展包(bundle)安裝到你的應用中。你可以選擇下載一個擴展包(bundle)然後拷貝到bundles目錄,或者通過命令行工具“Artisan”自動安裝。2、在Laravel中已經具有了一套高級的PHP ActiveRecord實現 -- Eloquent ORM。它能方便的將“約束(constraints)”應用到關系的雙方,這樣你就具有了對數據的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查詢構造器(query-builder)的所有方法。3、應用邏輯(Application Logic)可以在控制器(controllers)中實現,也可以直接集成到路由(route)聲明中,並且語法和Sinatra框架類似。Laravel的設計理念是:給開發者以最大的靈活性,既能創建非常小的網站也能構建大型的企業應用。4、反向路由(Reverse Routing)賦予你通過路由(routes)名稱創建鏈接(URI)的能力。只需使用路由名稱(route name),Laravel就會自動幫你創建正確的URI。這樣你就可以隨時改變你的路由(routes),Laravel會幫你自動更新所有相關的鏈接。5、Restful控制器(Restful Controllers)是一項區分GET和POST請求邏輯的可選方式。比如在一個用戶登陸邏輯中,你聲明了一個get_login()的動作(action)來處理獲取登陸頁面的服務;同時也聲明了一個post_login()動作(action)來校驗表單POST過來的數據,並且在驗證之後,做出重新轉向(redirect)到登陸頁面還是轉向控制台的決定。6、自動加載類(Class Auto-loading)簡化了類(class)的加載工作,以後就可以不用去維護自動加載配置表和非必須的組件加載工作了。當你想加載任何庫(library)或模型(model)時,立即使用就行了,Laravel會自動幫你加載需要的文件。7、視圖組裝器(View Composers)本質上就是一段代碼,這段代碼在視圖(View)加載時會自動執行。最好的例子就是博客中的側邊隨機文章推薦,“視圖組裝器”中包含了加載隨機文章推薦的邏輯,這樣,你只需要加載內容區域的視圖(view)就行了,其它的事情Laravel會幫你自動完成。8、反向控制容器(IoC container)提供了生成新對象、隨時實例化對象、訪問單例(singleton)對象的便捷方式。反向控制(IoC)意味著你幾乎不需要特意去加載外部的庫(libraries),就可以在代碼中的任意位置訪問這些對象,並且不需要忍受繁雜、冗余的代碼結構。9、遷移(Migrations)就像是版本控制(version control)工具,不過,它管理的是數據庫范式,並且直接集成在了Laravel中。你可以使用“Artisan”命令行工具生成、執行“遷移”指令。當你的小組成員改變了數據庫范式的時候,你就可以輕松的通過版本控制工具更新當前工程,然後執行“遷移指令即可,好了,你的數據庫已經是最新的了!11、自動分頁(Automatic Pagination)功能避免了在你的業務邏輯中混入大量無關分頁配置代碼。方便的是不需要記住當前頁......余下全文>>