最近更新: 2008-02-20

文件格式之 URI Route Rule 與 CodeIgniter 之實作示範

我習慣將控制元件行為的最後一個參數,設為文件(呈現內容)的"格式",如使用者想要 XML 格式的回傳內容,則傳入 'xml'。例如:

程式定義:
  class Controller {
    function method( docType ) {
      // return result as a XML document.
    }
  }
  var controller = new Controller;

調用控制項時的 URI:
  controller/method/xml
  # invoke  controller->method('xml');

不過,我更喜歡將"文件格式"這個參數放在 URI 的副檔名部份。這部份我放在文章後段。

再看一個更具體的例子。控制元件 Human 有一個行為 query 可以查詢某人的資料,第一個參數是人名,最後一個參數是查詢結果的資料格式。

class Human {
    function query( $name, $docType='html') {
        $result = $db->query("name={$name}");
        
        $view = 'human.' . $docType;
        
        showView($view);        
    }
}

調用控制元件時的 URI:

human/query/rock/html 回傳:
    <html>
        <title>Rock</title>
        <table>
            <tr>
                <td>Name</td>
                <td>rock</td>
            </tr>
            <tr>
                <td>Address</td>
                <td>Taiwan</td>
            </tr>
            <tr>
                <td>Age</td>
                <td>??</td>
            </tr>
        </table>
    </html>
human/query/rock/xml 回傳:
    <?xml version="1.0" encoding="windows-1250"?>
    <human>
        <name>rock</name>
        <address>Taiwan</address>
        <age>??</age>
    </human>

不過,我更喜歡將"文件格式"這個參數放在 URI 的副檔名部份,讓使用者認為他是直接取得"一份那種格式的文件"。亦即使用者認為他是在觀看一份靜態的文件。再舉前例說明如下:

human/query/rock/html
可寫成:
human/query/rock.html


human/query/rock/xml
可寫成:
human/query/rock.xml

在 PHP 中,基本上可解析 $_SERVER['PATH_INFO'] 的內容取得參數內容。而 CodeIgniter Framework 則可透過 URI Route 的設定,新增一條 route 規則,將 URI 副檔名部份轉接為最後一個 segment 項目。例如:

  $route['(.+)(\.)(\w+)$'] = "$1/$3";

撰寫程式碼時,我則在控制元件的建構子中設定文件格式。以 CodeIgniter Framework 為例,我通常會以下列所示的方式撰寫控制元件。

class Human extends Controller {
    protected $docType;

    protected $mimeTypeTable = array(
        'html' => 'text/html',
        'xml'  => 'application/xml',
        'json' => 'application/json'
    );

    function __construct() {
        parent::__construct();

        $rsegc = $this->uri->total_rsegments();
        if ($rsegc > $this->uri->total_segments()) {
            $this->docType = $this->uri->rsegment($rsegc);
        }
        else {
            $this->docType = 'html'; //default
        }
    }

    function query( $name ) {
        $result = $db->query("name={$name}");
        
        $viewFile = 'humanQuery.' . $this->docType;

        $this->output->set_header(
            'Content-type: ' . $this->mimeTypeTable[$this->docType]);
        $this->load->view($viewFile);        
    }
}

附帶一提,如果案子不小,有很多控制元件,而且每個都支援上述的多種文件格式,那麼我建議按照 CodeIgniter 的方式衍生自定的輸出類別 (CodeIgniter 提供2種擴充,一是 Extending Core Class,二是 Hook),將 $docType$mimeTypeTable 放到自定的輸出類別。

相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/5569813.html