鍍金池/ 教程/ PHP/ 擴展框架
Laravel Cashier
Eloquent ORM
HTTP 響應
發(fā)行說明
擴展包開發(fā)
HTTP 控制器
事件
擴展框架
Contracts
開發(fā)
配置
表單驗證
錯誤與日志
Hashing
貢獻指南
郵件
Session
遷移與數據填充
查詢構造器
Redis
升級向導
概覽
緩存
服務提供者
Envoy 任務執(zhí)行器
隊列
單元測試
服務容器
文件系統 / 云存儲
認證
請求的生命周期
加密
模板
視圖 (View)
Laravel Homestead
Laravel 安裝指南
介紹
Command Bus
分頁
輔助方法
應用程序結構
HTTP 路由
HTTP 請求
基本用法
本地化
HTTP 中間件
結構生成器
Facades
Laravel Elixir

擴展框架

管理者和工廠 緩存 Session 認證 基于服務容器的擴展

管理者和工廠

Laravel 有幾個 Manager 類,用來管理創(chuàng)建基于驅動的組件。這些類包括緩存、session 、認證和隊列組件。管理者類負責基于應用程序的配置建立一個特定的驅動實現。例如,CacheManager 類可以建立 APC 、 Memcached 、文件和各種其他的緩存驅動實現。

這些管理者都擁有 extend 方法,可以簡單地用它來注入新的驅動解析功能到管理者。我們將會在下面的例子,隨著講解如何為它們注入自定義驅動支持,涵蓋這些管理者的內容。

注意: 建議花點時間來探索 Laravel 附帶的各種 Manager 類,例如:CacheManager 和 SessionManager??催^這些類將會讓你更徹底了解 Laravel 表面下是如何運作。所有的管理者類繼承 Illuminate\Support\Manager 基礎類,它提供一些有用、常見的功能給每一個管理者。

緩存

為了擴展 Laravel 緩存功能,我們將會使用 CacheManagerextend 方法,這方法可以用來綁定一個自定義驅動解析器到管理者,并且是全部的管理者類通用的。例如,注冊一個新的緩存驅動名為「mongo」,我們將執(zhí)行以下操作:

Cache::extend('mongo', function($app)
{
    return Cache::repository(new MongoStore);
});

傳遞到 extend 方法的第一個參數是驅動的名稱。這將會對應到你的 config/cache.php 配置文件里的 driver 選項。第二個參數是個應該返回 Illuminate\Cache\Repository 實例的閉包。 $app 將會被傳遞到閉包,它是 Illuminate\Foundation\Application 和服務容器的實例。

Cache::extend 的調用可以在新的 Laravel 應用程序默認附帶的 App\Providers\AppServiceProvider 的 boot 方法中完成,或者你可以建立自己的服務提供者來放置這個擴展 - 記得不要忘記在 config/app.php 的提供者數組注冊提供者。

要建立自定義緩存驅動,首先需要實現 Illuminate\Contracts\Cache\Store contract 。所以,我們的 MongoDB 緩存實現將會看起來像這樣:

class MongoStore implements Illuminate\Contracts\Cache\Store {

    public function get($key) {}
    public function put($key, $value, $minutes) {}
    public function increment($key, $value = 1) {}
    public function decrement($key, $value = 1) {}
    public function forever($key, $value) {}
    public function forget($key) {}
    public function flush() {}

}

我們只需要使用 MongoDB 連接來實現這些方法。當實現完成,就可以完成自定義驅動注冊:

Cache::extend('mongo', function($app)
{
    return Cache::repository(new MongoStore);
});

如果你正在考慮要把自定義緩存驅動代碼放在哪里,請考慮把它放上 Packagist !或者,你可以在 app 的目錄中建立 Extensions 命名空間。記得 Laravel 沒有嚴格的應用程序架構,你可以依照喜好自由的組織應用程序。

Session

自定義 session 驅動來擴展 Laravel 和擴展緩存系統一樣簡單。我們將會再一次使用 extend 方法來注冊自定義代碼:

Session::extend('mongo', function($app)
{
    // Return implementation of SessionHandlerInterface
});

在哪里擴展 Session

你應該把 session 擴展代碼放置在 AppServiceProviderboot 方法里。

實現 Session 擴展

要注意我們的自定義緩存驅動應該要實現 SessionHandlerInterface 。這個接口只包含少數需要實現的簡單方法。一個基本的 MongoDB 實現會看起來像這樣:

class MongoHandler implements SessionHandlerInterface {

    public function open($savePath, $sessionName) {}
    public function close() {}
    public function read($sessionId) {}
    public function write($sessionId, $data) {}
    public function destroy($sessionId) {}
    public function gc($lifetime) {}

}

因為這些方法不像緩存的 StoreInterface 一樣容易理解,讓我們快速地看過這些方法做些什么:

open 方法通常會被用在基于文件的 session 保存系統。因為 Laravel 附帶一個 file session 驅動,幾乎不需要在這個方法放任何東西。你可以讓它留空。PHP 要求我們去實現這個方法,事實上明顯是個差勁的接口設計 (我們將會晚點討論它)。 close 方法,就像 open 方法,通常也可以忽略。對大部份的驅動來說,并不需要它。 read 方法應該返回與給定 $sessionId 關聯的 session 數據的字串形態(tài)。當你的驅動取回或保存 session 數據時不需要做任何序列化或進行其他編碼,因為 Laravel 將會為你進行序列化 write 方法應該寫入給定 $data 字串與 $sessionId 的關聯到一些永久存儲系統,例如:MongoDB、 Dynamo、等等。 destroy 方法應該從永久存儲移除與 $sessionId 關聯的數據。 gc 方法應該銷毀所有比給定 $lifetime UNIX 時間戳記還舊的 session 數據。對于會自己過期的系統如 Memcached 和 Redis,這個方法可以留空。 當 SessionHandlerInterface 實現完成,我們準備好要用 Session 管理者注冊它:

Session::extend('mongo', function($app)
{
    return new MongoHandler;
});

當 session 驅動已經被注冊,我們可以在 config/session.php 配置文件使用 mongo 驅動。

注意: 記住,如果你寫了個自定義 session 處理器,請在 Packagist 分享它!

認證

認證可以用與緩存和 session 功能相同的方法擴展。再一次的,使用我們已經熟悉的 extend 方法:

Auth::extend('riak', function($app)
{
    // 返回 Illuminate\Contracts\Auth\UserProvider 的實現
});

UserProvider 實現只負責從永久存儲系統抓取 Illuminate\Contracts\Auth\Authenticatable 實現,存儲系統例如: MySQL 、 Riak ,等等。這兩個接口讓 Laravel 認證機制無論用戶數據如何保存或用什么種類的類來代表它都能繼續(xù)運作。

讓我們來看一下 UserProvider contract :

interface UserProvider {

    public function retrieveById($identifier);
    public function retrieveByToken($identifier, $token);
    public function updateRememberToken(Authenticatable $user, $token);
    public function retrieveByCredentials(array $credentials);
    public function validateCredentials(Authenticatable $user, array $credentials);

}

retrieveById 函數通常接收一個代表用戶的數字鍵,例如:MySQL 數據庫的自動遞增 ID。這方法應該取得符合 ID 的 Authenticatable 實現并返回。

retrieveByToken 函數用用戶唯一的 $identifier 和保存在 remember_token 字段的「記住我」 $token 來取得用戶。跟前面的方法一樣,應該返回 Authenticatable 的實現。

updateRememberToken 方法用新的 $token 更新 $userremember_token 字段。新 token 可以是在「記住我」成功地登錄時,傳入一個新的 token,或當用戶注銷時傳入一個 null。

retrieveByCredentials 方法接收當嘗試登錄應用程序時,傳遞到 Auth::attempt 方法的憑證數組。這個方法應該接著「查找」底層使用的永久存儲,找到符合憑證的用戶。這個方法通常會對 $credentials['username'] 用「 where 」條件查找。 并且應該返回一個 UserInterface 接口的實現。這個方法不應該嘗試做任何密碼驗證或認證。

validateCredentials 方法應該通過比較給定的 $user$credentials 來驗證用戶。舉例來說,這個方法可以比較 $user->getAuthPassword() 字串跟 Hash::make 后的 $credentials['password']。這個方法應該只驗證用戶的憑證數組并且返回布爾值。

現在我們已經看過 UserProvider 的每個方法,接著來看一下 Authenticatable。記住,提供者應該從 retrieveByIdretrieveByCredentials 方法返回這個接口的實現:

interface Authenticatable {

    public function getAuthIdentifier();
    public function getAuthPassword();
    public function getRememberToken();
    public function setRememberToken($value);
    public function getRememberTokenName();

}

這個接口很簡單。 The getAuthIdentifier 方法應該返回用戶的「主鍵」。在 MySQL 后臺,同樣,這將會是個自動遞增的主鍵。getAuthPassword 應該返回用戶哈希過的密碼。這個接口讓認證系統可以與任何用戶類一起運作,無論你使用什么 ORM 或保存抽象層。默認,Laravel 包含一個實現這個接口的 User 類在 app 文件夾里,所以你可以參考這個類當作實現的例子。

最后,當我們已經實現了 UserProvider,我們準備好用 Auth facade 來注冊擴展:

Auth::extend('riak', function($app)
{
    return new RiakUserProvider($app['riak.connection']);
});

extend 方法注冊驅動之后,在你的 config/auth.php 配置文件切換到新驅動。

基于服務容器的擴展

幾乎每個 Laravel 框架引入的服務提供者都會綁定對象到服務容器中。你可以在 config/app.php 配置文件中找到應用程序的服務提供者清單。如果你有時間,你應該瀏覽過這里面每一個提供者的源代碼。通過這樣做,你將會更了解每一個提供者添加什么到框架,以及用什么鍵值來綁定各種服務到服務容器。

例如, HashServiceProvider綁定 hash 做為鍵值到服務容器,它將解析成 Illuminate\Hashing\BcryptHasher 實例。你可以在應用程序中覆寫這個 IoC 綁定,輕松地擴展并覆寫這個類。例如:

<?php namespace App\Providers;

class SnappyHashProvider extends \Illuminate\Hashing\HashServiceProvider {

    public function boot()
    {
        parent::boot();

        $this->app->bindShared('hash', function()
        {
            return new \Snappy\Hashing\ScryptHasher;
        });
    }

}

要注意的是這個類擴展 HashServiceProvider,不是默認的 ServiceProvider 基礎類。當你擴展了服務提供者,在 config/app.php 配置文件把 HashServiceProvider 換成你擴展的提供者名稱。

這是被綁定在容器的所有核心類的一般擴展方法。實際上,每個以這種方式綁定在容器的核心類都可以被覆寫。再次強調,看過每個框架引入的服務提供者將會使你熟悉:每個類被綁在容器的哪里、它們是用什么鍵值綁定。這是個好方法可以了解更多關于 Laravel 如何結合它們。

上一篇:HTTP 響應下一篇:認證