fecshop服務是一個公用性的底層,為各個應用系統(tǒng)提供底層服務
各個“應用系統(tǒng)”,譬如appfront,appadmin,apphtml5,是一個獨立的文件結構 ,他們都有獨立的模塊,里面有controller(控制層) block(數(shù)據(jù)中間邏輯處理層) theme(模板view層) ,但是沒有model層,在原則上約定,各個“應用系統(tǒng)”不能直接訪問model, 只能訪問Fecshop Service(服務),來進行數(shù)據(jù)的獲取和處理工作,然后由service層 訪問model層進行數(shù)據(jù)的獲取處理等工作。
首先,對于model層的函數(shù)粒度,對應的是數(shù)據(jù)的操作,譬如更改某一行數(shù)據(jù),添加一行數(shù)據(jù)等,這個地球人都知道。
對于service層的函數(shù)粒度,一般是我們語言描述需求的最小粒度,譬如:把一個產品加入購物車, 刪除購物車的某個產品,調出某個分類下的產品,登錄用戶,計算產品的最終價格,等等,對于上面的這些最小的 語言描述粒度,會在服務層實現(xiàn),然后直接訪問該服務中的方法即可。
3.1 實例化過程:
當我們執(zhí)行 Yii::$service->cart
,就會訪問fecshop cart service 服務
當執(zhí)行Yii::$service->cart->coupon
就會訪問 cart的子服務coupon。
下面是實例化原理:
在index.php入口文件中可以看到如下代碼:
new fecshop\services\Application($config['services']);
unset($config['services']);
查看 fecshop\services\Application.php的代碼如下:
<?php
/**
* FecShop file.
*
* @link http://www.fecshop.com/
* @copyright Copyright (c) 2016 FecShop Software LLC
* @license http://www.fecshop.com/license/
*/
namespace fecshop\services;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
/**
* @author Terry Zhao <2358269014@qq.com>
* @since 1.0
*/
class Application
{
public $childService;
public $_childService;
public function __construct($config = [])
{
Yii::$service = $this;
$this->childService = $config;
}
/**
* 得到services 里面配置的子服務childService的實例
*/
public function getChildService($childServiceName){
if(!$this->_childService[$childServiceName]){
$childService = $this->childService;
if(isset($childService[$childServiceName])){
$service = $childService[$childServiceName];
$this->_childService[$childServiceName] = Yii::createObject($service);
}else{
throw new InvalidConfigException('Child Service ['.$childServiceName.'] is not find in '.get_called_class().', you must config it! ');
}
}
return $this->_childService[$childServiceName];
}
/**
*
*/
public function __get($attr){
return $this->getChildService($attr);
}
}
service配置,譬如:@fecshop\config\services\Cart.php
<?php
/**
* FecShop file.
* @link http://www.fecshop.com/
* @copyright Copyright (c) 2016 FecShop Software LLC
* @license http://www.fecshop.com/license/
*/
return [
'cart' => [
'class' => 'fecshop\services\Cart',
# 子服務
'childService' => [
'quote' => [
'class' => 'fecshop\services\cart\Quote',
],
'quoteItem' => [
'class' => 'fecshop\services\cart\QuoteItem',
],
'info' => [
'class' => 'fecshop\services\cart\Info',
/**
* 單個sku加入購物車的最大個數(shù)。
*/
'maxCountAddToCart' => 100,
# 上架狀態(tài)產品加入購物車時,
# 如果addToCartCheckSkuQty設置為true,則需要檢查產品qty是否>購買qty,
# 如果設置為false,則不需要,也就是說產品庫存qty小于購買qty,也是可以加入購物車的。
'addToCartCheckSkuQty' => true,
],
'coupon' => [
'class' => 'fecshop\services\cart\Coupon',
],
],
],
];
Yii::$service->cart 就是cart服務
Yii::$service 對應的是 fecshop\services\Application
當執(zhí)行Yii::$service->cart時,找不到cart變量就會執(zhí)行 __get()魔術方法,進而執(zhí)行
getChildService(),將上面cart配置的class對應的文件fecshop\services\Cart
,
進行實例化,也就是說 Yii::$service->cart 對應的是 fecshop\services\Cart 實例化的對象,
如果下次使用 Yii::$service->cart ,不會再實例化對象,F(xiàn)ecShop Service是單例模式。
Fecshop子服務:Yii::$service->cart->coupon,通過上面的配置,會實例化
fecshop\services\cart\Coupon
,子服務的原理和服務類似,都是單例模式。
3.2 關于service類
上面講解了 Yii::$service->cart,如何找到 fecshop\services\Cart的步驟,下面詳細講述 service類。
所有的服務類,譬如上面說的cart服務,都必須繼承
@fecshop\services\Service
。
里面的方法都必須以action開頭,和controller中類似,
譬如執(zhí)行 Yii::$service->cart->addProductToCart($item)
,對應的是
fecshop\services\Cart中的 protected function actionAddProductToCart($item)
方法。
原理為:當訪問 addProductToCart時,由于找不到該函數(shù),就會執(zhí)行
@fecshop\services\Service->__call()
魔術方法,然后由魔術方法,
將 addProductToCart
改成 actionAddProductToCart
,然后去查找函數(shù),就會找到
,這樣做的好處是,可以在__call()
函數(shù)中記錄每一個service的方法調用開始時間
和結束時間,這樣就可以更好的調試出來哪一個service方法耗費的時間長,
這個是為了更好地統(tǒng)計各個services的狀況,譬如:排查耗費時間最長的services,
使用最頻繁的services等,
當然會耗費一定的時間,
在線上可以關掉log記錄時間的功能,也可以間斷性的手動開啟,進行線上調試。
關于services log的開啟:@fecshop\config\services\Helper
中看到如下配置:
return [
'helper' => [
'class' => 'fecshop\services\Helper',
# 子服務
'childService' => [
'ar' => [
'class' => 'fecshop\services\helper\AR',
],
'log' => [
'class' => 'fecshop\services\helper\Log',
'log_config' => [
# service log config
'services' => [
# if enable is false , all services will be close
'enable' => false, # 這里可以開啟services log功能。
通過配置helper log服務的enable設置為true,可以開啟services的日志功能
當然helper log服務還有其他的一些設置,具體請參看詳細代碼。
當然,您可以把服務中的類函數(shù)定義成public
,函數(shù)名不以action
開頭,
這種方式定義的函數(shù),開啟services log,不會被記錄,因為直接找到函數(shù)名,不會
訪問魔術方法__call()
。
更多建議: