Fecshop 服務原理

2018-05-24 14:16 更新

Fecshop 服務原理

fecshop服務是一個公用性的底層,為各個應用系統(tǒng)提供底層服務

1.原則約定

各個“應用系統(tǒng)”,譬如appfront,appadmin,apphtml5,是一個獨立的文件結構 ,他們都有獨立的模塊,里面有controller(控制層) block(數(shù)據(jù)中間邏輯處理層) theme(模板view層) ,但是沒有model層,在原則上約定,各個“應用系統(tǒng)”不能直接訪問model, 只能訪問Fecshop Service(服務),來進行數(shù)據(jù)的獲取和處理工作,然后由service層 訪問model層進行數(shù)據(jù)的獲取處理等工作。

2.服務層的功能粒度:

首先,對于model層的函數(shù)粒度,對應的是數(shù)據(jù)的操作,譬如更改某一行數(shù)據(jù),添加一行數(shù)據(jù)等,這個地球人都知道。

對于service層的函數(shù)粒度,一般是我們語言描述需求的最小粒度,譬如:把一個產品加入購物車, 刪除購物車的某個產品,調出某個分類下的產品,登錄用戶,計算產品的最終價格,等等,對于上面的這些最小的 語言描述粒度,會在服務層實現(xiàn),然后直接訪問該服務中的方法即可。

3.實現(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()

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號