2015/10/06

CodeIgniter Drivers

Codeigniter 裡面有一個功能叫 drivers,但官方的文件著墨很少,網路上討論的文章也不算多,但我覺得以一個不是使用 namespace 那麼方便做 DI 以及調用資源的 framework 來說,這個功能還頗好應用的,一般人使用 CI 都會用他的 library 功能,把自己的 class 放在這邊調用,但大部分就是一層式的沒有階級觀念,就不用提 interface 了,dirvers 可以靈活的做到調用,先來講怎麼設定 driver 環境,以各家第三方登入為例。

首先我們先建立目錄

  • Auth
  • Auth/Auth.php
  • Auth/drivers
  • Auth/drivers/Auth_facebook.php
  • Auth/drivers/Auth_google.php

命名規則就是檔名必須跟目錄名稱相同,第一個字首要大寫(包含初始的目錄),只要任何一個名稱取錯都不會動,我試過了。

Auth.php
class Auth extends CI_Driver_Library
{
    protected $valid_drivers;

    public function __construct()
    {
        $this->valid_drivers = array('facebook', 'google');
    }

    public function login()
    {
        echo 'login from auth driver'.PHP_EOL;
    }
}

$valid_drivers 是必要參數,他表示允許調用的 dirver 名稱,呼叫的時候不需要帶 parent name,這樣寫起來也比較清爽。

Auth_facebook.php
class Auth_facebook extends CI_Driver
{
    public function login()
    {
        echo 'login from auth facebook'.PHP_EOL;
    }
}

基本上被調用的 driver 子項目很簡單,繼承 CI_Driver 就可以了,我們接著建立一個叫 Login 的 controller。

application/controllers/Login.php
class Login extends CI_Controller
{
    public function index()
    {
        $this->load->driver('auth');
        $this->auth->login();
        $this->auth->facebook->login();
    }
}

在 command line 執行 php index.php login index 會得到

login from auth driver
login from auth facebook

寫到這就知道前面部屬好的話,之後要調用各家的 login 只要在 Auth/drivers 下增加,並且加入 $valid_drivers 設定即可,根據 SOLID 原則,會變動的 config 內容不應該存在在 class 裡面,所以我們在 config 增加一個 auth.php

application/config/auth.php
$config['valid_drivers'] = array('facebook', 'google');

然後將 Auth.php 改寫如下。

class Auth extends CI_Driver_Library
{
    protected $valid_drivers;
    protected $ci;

    public function __construct()
    {
        $this->ci =& get_instance();
        $this->ci->config->load('auth', true);
        $this->valid_drivers = $this->ci->config->item('valid_drivers', 'auth');
    }

    public function login()
    {
        echo 'login from auth driver'.PHP_EOL;
    }
}

這樣的話之後要加內容只要改 config 就好,但這樣的彈性還不是最好的,我們應該要讓 Login controller 可以接受變數選擇調用哪個登入才對,來對他動一點手腳。

class Login extends CI_Controller
{
    public function index($method = null)
    {
        $this->load->driver('auth');
        $this->auth->login();
        $this->auth->{$method}->login();
    }
}

然後執行 php index.php login index facebook,這樣會得到跟上面一樣的結果,但我們應該更嚴謹一點,檢查該 method 是否存在,在來強化一下。

class Login extends CI_Controller
{
    public function index($method = null)
    {
        $this->config->load('auth', true);

        if (!in_array($method, $this->config->item('valid_drivers', 'auth'))) {
            die('method not exists');
        }

        $this->load->driver('auth');
        $this->auth->login();
        $this->auth->{$method}->login();
    }
}

如果亂執行一通 php index.php login index twitter,會得到 method not exists,這大致上是 drivers 的全貌,怎麼變化應用讓功能更有彈性就要視不同的情況去配置了。

沒有留言: