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

擴展框架

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

管理者和工廠

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

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

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

緩存

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

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

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

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

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

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 連接來實現(xiàn)這些方法。當實現(xiàn)完成,就可以完成自定義驅(qū)動注冊:

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

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

Session

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

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

在哪里擴展 Session

你應(yīng)該把 session 擴展代碼放置在 AppServiceProviderboot 方法里。

實現(xiàn) Session 擴展

要注意我們的自定義緩存驅(qū)動應(yīng)該要實現(xiàn) SessionHandlerInterface 。這個接口只包含少數(shù)需要實現(xiàn)的簡單方法。一個基本的 MongoDB 實現(xiàn)會看起來像這樣:

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

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

當 session 驅(qū)動已經(jīng)被注冊,我們可以在 config/session.php 配置文件使用 mongo 驅(qū)動。

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

認證

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

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

UserProvider 實現(xiàn)只負責從永久存儲系統(tǒng)抓取 Illuminate\Contracts\Auth\Authenticatable 實現(xiàn),存儲系統(tǒng)例如: MySQL 、 Riak ,等等。這兩個接口讓 Laravel 認證機制無論用戶數(shù)據(jù)如何保存或用什么種類的類來代表它都能繼續(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 函數(shù)通常接收一個代表用戶的數(shù)字鍵,例如:MySQL 數(shù)據(jù)庫的自動遞增 ID。這方法應(yīng)該取得符合 ID 的 Authenticatable 實現(xiàn)并返回。

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

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

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

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

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

interface Authenticatable {

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

}

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

最后,當我們已經(jīng)實現(xiàn)了 UserProvider,我們準備好用 Auth facade 來注冊擴展:

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

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

基于服務(wù)容器的擴展

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

例如, HashServiceProvider綁定 hash 做為鍵值到服務(wù)容器,它將解析成 Illuminate\Hashing\BcryptHasher 實例。你可以在應(yīng)用程序中覆寫這個 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 基礎(chǔ)類。當你擴展了服務(wù)提供者,在 config/app.php 配置文件把 HashServiceProvider 換成你擴展的提供者名稱。

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

上一篇:HTTP 響應(yīng)下一篇:認證