想要在 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 ); } }