Fecshop 2016-07-27 09:26:27 7098次浏览 2条评论 2 1 0

原文链接: yii2 给Yii 添加一个变量,Yii::$service,并像组件component那样可以添加单例配置

在yii2中,组件是可以通过配置的方式添加到Yii::$app中的。

现在我们想添加一个Yii静态变量,$service,下面都称呼这个变量为服务,

可以通过Yii::$service访问,然后添加服务,以及服务的子服务,
譬如我添加了一个cms服务,以及cms服务的子服务article。

那么我想访问cms服务,可以通过Yii::$service->cms访问,

如果我想访问cms服务的子服务,那么,我可以通过Yii::$service->cms->article访问。

上面的使用访问和yii2的组件很类似,是单例模式。下面说具体实现方式:

1.创建一个Yii.php添加$service参数: @vendor/fancyecommerce/fecshop/yii/Yii.php

    <?php
    $dir = __DIR__ . '/../../../yiisoft/yii2';
    require($dir.'/BaseYii.php');
    /**
     * Yii is a helper class serving common framework functionalities.
     *
     * It extends from [[\yii\BaseYii]] which provides the actual implementation.
     * By writing your own Yii class, you can customize some functionalities of [[\yii\BaseYii]].
     *
     * @author Qiang Xue <qiang.xue@gmail.com>
     * @since 2.0
     */
    class Yii extends \yii\BaseYii
    {
      public static $service;
      
    }
    spl_autoload_register(['Yii', 'autoload'], true, true);
    Yii::$classMap = require($dir.'/classes.php');
    Yii::$container = new yii\di\Container();

2.在入口文件index.php中,将对yii的Yii.php去掉,换成:

    require(__DIR__ . '/../../vendor/fancyecommerce/fecshop/yii/Yii.php');

也就是加载上面,我创建的文件。

然后修改index.php底部代码:

    new fecshop\services\Application($config['services']);
    unset($config['services']);
    //var_dump($config);
    $application = new yii\web\Application($config);
    $application->run();

也就是添加了代码:

    new fecshop\services\Application($config['services']);
    unset($config['services']);

这个代码的作用是,给$service变量赋值,Yii::$service = fecshop\services\Application($config[‘services’]);

3.下面我们实现这个Application。

    <?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);
        
      }
      
    }
  1. 在配置中添加配置:
    [
    'services' => [
        'cms' => [
            'class' => 'fecshop\services\Cms',
            
            # 子服务
            'childService' => [
                'article' => [
                    'class'             => 'fecshop\services\cms\Article',
                    'storage' => 'mysqldb', # mysqldb or mongodb.
                ],
            ],
        ],
    ]

5.上面的配置,给cms添加了一个子服务article。

cms 对应的class的代码如下:

    <?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\InvalidValueException;
    use yii\base\InvalidConfigException;
    use fec\helpers\CSession;
    use fec\helpers\CUrl;
    /**
     * Breadcrumbs services
     * @author Terry Zhao <2358269014@qq.com>
     * @since 1.0
     */
    class Cms extends Service
    {
      /**
       * cms storage db, you can set value: mysqldb,mongodb.
       */
      public $storage = 'mysqldb';
      
    }

artile的代码如下:

    <?php
    /**
     * FecShop file.
     *
     * @link http://www.fecshop.com/
     * @copyright Copyright (c) 2016 FecShop Software LLC
     * @license http://www.fecshop.com/license/
     */
    namespace fecshop\services\cms;
    use Yii;
    use yii\base\InvalidValueException;
    use yii\base\InvalidConfigException;
    use fec\helpers\CSession;
    use fec\helpers\CUrl;
    use fecshop\services\Service;
    use fecshop\services\cms\article\ArticleMysqldb;
    use fecshop\services\cms\article\ArticleMongodb;
    /**
     * Breadcrumbs services
     * @author Terry Zhao <2358269014@qq.com>
     * @since 1.0
     */
    class Article extends Service
    {
      public $storage = 'mongodb';
      protected $_article;
      
      
      public function init(){
        if($this->storage == 'mongodb'){
          $this->_article = new ArticleMongodb;
        }else if($this->storage == 'mysqldb'){
          $this->_article = new ArticleMysqldb;
        }
      }
      /**
       * Get Url by article's url key.
       */
      public function getUrlByPath($urlPath){
        //return Yii::$service->url->getHttpBaseUrl().'/'.$urlKey;
        return Yii::$service->url->getUrlByPath($urlPath);
      }
      /**
       * get artile's primary key.
       */
      public function getPrimaryKey(){
        return $this->_article->getPrimaryKey();
      }
      /**
       * get artile model by primary key.
       */
      public function getByPrimaryKey($primaryKey){
        return $this->_article->getByPrimaryKey($primaryKey);
      }
      
      
      
      /**
       * @property $filter|Array
       * get artile collection by $filter
       * example filter:
       * [
       *     'numPerPage'   => 20,    
       *     'pageNum'    => 1,
       *     'orderBy'  => ['_id' => SORT_DESC, 'sku' => SORT_ASC ],
       *     'where'      => [
       *       'price' => [
       *         '?gt' => 1,
       *         '?lt' => 10,
       *       ],
       *       'sku' => 'uk10001',
       *     ],
       *   'asArray' => true,
       * ]
       */
      public function coll($filter=''){
        return $this->_article->coll($filter);
      }
      
      /**
       * @property $one|Array , save one data .
       * @property $originUrlKey|String , article origin url key.
       * save $data to cms model,then,add url rewrite info to system service urlrewrite.                 
       */
      public function save($one,$originUrlKey){
        return $this->_article->save($one,$originUrlKey);
      }
      
      public function remove($ids){
        return $this->_article->remove($ids);
      }
      
    }

他们继承的service类代码如下:

    <?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\Object;
    use yii\base\InvalidConfigException;
    /**
     * @author Terry Zhao <2358269014@qq.com>
     * @since 1.0
     */
    class Service extends  Object
    {
      public $childService;
      public $_childService;
      
      /**
       * 得到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);
        
      }
      
    }

然后,我就可以使用了,按照上面的方法

    Yii::$service->cms->$storage     # 获取存储方式,这个变量可以在service配置中注入。
    Yii::$service->cms->article->remove($ids)  # cms服务对应子服务artile的删除功能。

由于这种方式是单例模式,因此,可以用这种方式,在controller和model之间,做一个中间服务层,方便日后的扩展和使用,譬如我如果把mysql换成了mongodb,只需要把这个服务的public方法 重新实现以下就可以了,目前fecshop采用了这种实现方式。

觉得很赞
  • 评论于 2016-07-27 17:43 举报

    66666

  • 评论于 2016-12-22 09:16 举报

    最后,推荐一下我的Fecshop ,开源商城,github地址:https://github.com/fancyecommerce/yii2_fecshop

    演示地址:http://fecshop.appfront.fancyecommerce.com/

    截止到2016-11-12号,产品,分类,首页,评论,用户中心,搜索,多语言,多货币 等功能已经做完,除了购物车和支付部分,其他的基本都已经完成,关注fecshop的 在等2-3个月,也就是明年2,3月份,版本已经就可以出来,2017年4,5月份在把手机web 做一下,预计到明年5月份,后台,pc前台,手机web前台 ,命令控制台 这几个入口 基本可以完善,多谢大家关注和你们的Star,谢谢,我会坚持把他写好。

    作者QQ:2358269014

您需要登录后才可以评论。登录 | 立即注册