codeIgniter and Eloquent

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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *