CodeIgniter 採 MVC 分層,業務邏輯通常寫在 Controller,Model 僅負責資料庫操作。隨業務複雜度提升,Controller 膨脹難維護。以「用戶下單」為例:更新購物車、新增訂單、會員加分等一連串操作,且下單場景多樣,若寫在 Controller 難以復用;寫在 Model 又會導致持久層與業務層耦合。現有專案常見將業務邏輯寫在 Model 並互相調用,極不合理,導致 Model 難維護、方法難復用。
在 Controller 與 Model 間加入業務邏輯層 Service,封裝業務邏輯,提供介面供 Controller 復用。
於 application/core/MY_Service.php:
<?php
class MY_Service
{
public function __construct()
{
log_message('debug', "Service Class Initialized");
}
function __get($key)
{
$CI = & get_instance();
return $CI->$key;
}
}
於 application/core/MY_Loader.php:
<?php
class MY_Loader extends CI_Loader
{
protected $_ci_services = array();
protected $_ci_service_paths = array();
public function __construct()
{
parent::__construct();
$this->_ci_service_paths = array(APPPATH);
}
public function service($service = '', $params = NULL, $object_name = NULL)
{
if (is_array($service)) {
foreach ($service as $class) {
$this->service($class, $params);
}
return;
}
if ($service == '' or isset($this->_ci_services[$service])) {
return FALSE;
}
if (!is_null($params) && !is_array($params)) {
$params = NULL;
}
$subdir = '';
if (($last_slash = strrpos($service, '/')) !== FALSE) {
$subdir = substr($service, 0, $last_slash + 1);
$service = substr($service, $last_slash + 1);
}
foreach ($this->_ci_service_paths as $path) {
$filepath = $path . 'service/' . $subdir . $service . '.php';
if (!file_exists($filepath)) continue;
include_once($filepath);
$service = strtolower($service);
if (empty($object_name)) $object_name = $service;
$service = ucfirst($service);
$CI = &get_instance();
if ($params !== NULL) {
$CI->$object_name = new $service($params);
} else {
$CI->$object_name = new $service();
}
$this->_ci_services[] = $object_name;
return;
}
}
}
Controller 調用 Service:
<?php
class User extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->service('user_service');
}
public function login()
{
$name = 'phpddt.com';
$psw = 'password';
print_r($this->user_service->login($name, $psw));
}
}
Service 調用 Model:
<?php
class User_service extends MY_Service
{
public function __construct()
{
parent::__construct();
$this->load->model('user_model');
}
public function login($name, $password)
{
$user = $this->user_model->get_user_by_where($name, $password);
// ..... 業務邏輯處理
return $user;
}
}
Model 僅處理資料庫:
<?php
class User_model extends CI_Model
{
public function __construct()
{
parent::__construct();
}
public function get_user_by_where($name, $password)
{
//$this->db ...
return array('id' => 1, 'name' => 'mckee');
}
}
基本實作思路即如此。