
想要在 codeIgniter orm,找一找看一看 php 的好幾套
,最後比較偏好用 Laravel 的 orm eloquent,只是他是不同框架的東西,能拿來用嗎?
剛好有這篇文章
能參考,的確是能 work,但實際使用上自己遇到一些問題要解決,就紀錄一下了。
Laravel 的核心設計的頗模組化,大量利用了 php 的一些新的物件導向特性,用了蠻漂亮的方式解決了不少問題。
https://github.com/laravel/framework/tree/master/src/Illuminate
因為 Laravel 核心的每個功能都設計成獨立的元件,因此也可以單獨把他拆出來再別的專案裡面使用,例如這次要拿出他的 database 部份來玩。
Laravel 的安裝方式是 composer 所以就先裝好 composer。
$ curl -sS https://getcomposer.org/installer | php
就會下載一個 composer.phar,就可以直接用 php 執行了,先把設定檔裝好,在 codeIgniter 專案底下建一個 composer 設定檔,指定要安裝 Laravel 的 illuminate/database 套件。
{
"require": {
"php": ">=5.3.0",
"illuminate/database": "dev-master"
},
"autoload": {
"classmap": [
"application/models/orm"
]
}
}
放好就能執行 composer install 來讀取設定檔安裝套件囉~
$ php composer.phar install
然後在專案下就會多一個 vendor 的資料夾,下面就是自動下載下來的套件了,然後裡面會有一個 autoload.php 就是 用來載入 composer 套件的程式。
然後說明一下我的專案結構,我想要將 orm 的 object 都放在 application/models/orm 這個資料夾下,然後我會建一個處理 codeigniter 跟 eloquent 相容的物件在 application/models/orm/eloquent.php,因此我要載入 autoload.php 跟 eloquent.php 到 index.php 裡面。
require_once "vendor/autoload.php"; require_once "application/models/orm/eloquent.php"; ..
以下是我的相容物件,參考 Using Eloquent ORM inside Codeigniter 文章的實作在做一些修改,主要差異是我建了一個 Eloquent class 來作為在 codeigniter 跟 eloquent model 之間的橋接,感覺用起來比較自然,又能做些額外的擴充。我在這邊又特別建了一個 namespace 來解決一些 model 命名問題。
所以又複寫了跟關聯相關的函式來將載入的物件都自動加上 namespace,還另外寫了一個 autoload 來載入自己在 orm 資料夾下面建立的檔案。namespace + autoload 有點違背 codeIgniter 那舊式 php 的設計 XD
namespace orm;
use Illuminate\Database\Eloquent\Model;
spl_autoload_register(function($class) {
$parts = explode('\\', $class);
$class = strtolower(end($parts));
$classpath = dirname(__FILE__) . '/' . $class . EXT;
if(file_exists($classpath))
{
require_once($classpath);
}
});
class Eloquent extends Model {
public function __construct()
{
parent::__construct();
$CI = & get_instance();
$CI->load->database();
$config = $CI->db; // Get the DB object
$pdo = new \PDO('mysql:host='.$config->hostname.';dbname='.$config->database, $config->username, $config->password);
$pdo->exec('SET CHARACTER SET utf8');
$drivers = array(
'mysql' => '\Illuminate\Database\MySqlConnection',
'pgsql' => '\Illuminate\Database\PostgresConnection',
'sqlite' => '\Illuminate\Database\SQLiteConnection',
);
$conn = new $drivers['mysql']($pdo, $config->database, $config->dbprefix);
$resolver = new \Illuminate\Database\ConnectionResolver;
$resolver->addConnection('default', $conn);
$resolver->setDefaultConnection('default');
\Illuminate\Database\Eloquent\Model::setConnectionResolver($resolver);
}
public function hasMany()
{
$args = func_get_args();
$args[0] = 'orm\\' . $args[0];
return call_user_func_array(array('parent', 'hasMany'), $args);
}
public function belongsTo($table, $fk = NULL, $lk = NULL)
{
$args = func_get_args();
$args[0] = 'orm\\' . $args[0];
return call_user_func_array(array('parent', 'belongsTo'), $args);
}
public function hasOne()
{
$args = func_get_args();
$args[0] = 'orm\\' . $args[0];
return call_user_func_array(array('parent', 'hasOne'), $args);
}
public function hasManyThrough()
{
$args = func_get_args();
$args[0] = 'orm\\' . $args[0];
$args[1] = 'orm\\' . $args[1];
return call_user_func_array(array('parent', 'hasManyThrough'), $args);
}
}
之後就可以在 orm/ 下面開始寫 orm 了。飯例如 Laravel 官網
users
id – integer
name – string
posts
id – integer
user_id – integer
title – string
namespace orm;
class User extends Eloquent {
public function posts()
{
return $this->hasMany('Post');
}
}
namespace orm;
class Post extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
然後就可以在 Controller 裡面使用 orm 了,使用時都會 autoload 只是使用時都要指定 orm 這個 namespace,主要是為了解決不要跟 controller 命名衝突,是喜好問題啦~如果名字都加 postfix 就不需要這樣做了。
class User extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
var_dump( orm\User::find(1)->posts );
}
}