如何使用yii2 fecshop的小部件widget

首先需要说明的是,fecshop的小部件和yii2的不同,fecshop的小部件是由

Yii::$app->page->widget->render($configKey) 函数得到的内容

小部件的介绍:相当于个独立功能块,有2部分组成,1. 数据提供者block,2. view部分,view部分是html内容,一些动态数据需要从block中获取,通过数据提供部分和数据显示部分组成一个独立块。

小部件的功能:在电商网站,或者其他网站,我们会有一些块,在很多页面显示,譬如newsletter,rss,product view history等,可能在产品页面侧栏,分类页面搜索页侧栏面,账户中心侧栏等页面显示这个快,因此我引入了小部件的功能,通过配置直接添加,比较方面。

小部件实现的原理:分为3块,1.view文件和多模板路径,通过优先级依次匹配,直到文件存在,返回viewFile 。2. 通过配置里面的类以及方法,得到动态数据,数据格式为数组,3.通过view组件的renderFile函数,把view的路径和动态参数param,画出来最终的html。

小部件的使用:

1.添加配置:

在page组件中找到子组件widget

return [
  'page' => [
    'class' => 'fecshop\services\Page',
    //'terry' => 'xxxx',
    
    # 子服务
    'childService' => [
                'widget' => [
        'class' 		=> 'fecshop\services\page\Widget',
        # 定义默认方法,也就是widgetConfig 里面各个部件里面的method如果没有填写
        # 则使用该配置。
        # 'defaultObMethod' => 'getLastData',
        
        'widgetConfig' => [
          'menu' =>[
            # 必填
            'class' => 'fec\block\TestMenu',
            # view 的绝对路径配置方式
            'view'  => '@fec/views/testmenu/index.php',
            # 下面为选填
            'method'=> 'getLastData',
            'terry1'=> 'My1',
            'terry2'=> 'My2',
          ],
          'love' => [
            'class' => 'fecshop\app\appfront\modules\Cms\block\widget\Test',
            # 根据多模板的优先级,依次去模板找查找该文件,直到找到这个文件。
            'view'  => 'cms/home/test.php',
            'terry' => 'II',
          ]
        ]
        
      ],

上面定义了2个小部件,一个是menu,一个是love,

class是数据提供的类,method是返回数据的方法,view是html部分,其他的参数为class初始化传入类变量,

对于class 是和namesapces一致的

对于view 有2中方法,一种是加入@,譬如@fec,@vendor等,通过autoload查找绝对路径,另外一种就是通过多模板路径,通过多模板的优先级,依次到路径里面查找该view文件,最终返回view文件,因此,优先级低的view文件如果想更改,可以在高优先级的模板中新建这个文件即可(路径要对应好)。

下面以love举例:

新建class文件:

<?php
namespace fecshop\app\appfront\modules\Cms\block\widget;
use Yii;
use fecshop\app\appfront\modules\AppfrontController;
class Test 
{
  public $terry;
  # 网站信息管理
    public function getLastData()
    {
    return [
      'i'   	=> $this->terry,
      'love' 	=> 'loves',
      'you' 	=> 'terry',
    ];
  }
}



view文件内容:appfront/theme/terry/theme01/cms/home/test.php

love test
<?= "$i $love $you"  ?>

通过上面,我们在page-theme组件中加入了配置,新建了小部件的class和对应的方法和变量,view文件,下面我们就可以调用了

在controller中调用:

echo Yii::$app->page->widget->render('love');

可以看到页面输出:

love test II loves terry

我们在controller,view,layout等加入这个小部件,然后对应的html就会显示出来,还是蛮好用的。我们可以配置好各个小部件,有需要就直接添加,甚至给一个小部件做几种样式,在不同的页面调用。

 

 

 

 

yii2 fecshop 服务组件的详细介绍

yii2 fecshop 服务组件的详细介绍

在  vendor/fancyecommerce/fecshop/services路径下就是所有的fecshop组件,组件分为组件和子组件,组件本质上是yii2的组件,子组件的原理是组件的属性指向子组件对象,譬如Yii::$app->page是组件,Yii::$app->page->theme是子组件,组件的配置是在 vendor/fancyecommerce/fecshop/config/services里面,下面是一个配置组件和子组件的例子:

<?php
/**
 * FecShop file.
 *
 * @link http://www.fecshop.com/
 * @copyright Copyright (c) 2016 FecShop Software LLC
 * @license http://www.fecshop.com/license/
 */
return [
  'page' => [
    'class' => 'fecshop\services\Page',
    //'terry' => 'xxxx',
    
    # 子服务
    'childService' => [
      'breadcrumbs' => [
        'class' 		=> 'fecshop\services\page\Breadcrumbs',
        'homeName' 		=> 'Home',  # if homeName => '', Home will not show in breadcrums.
        'ifAddHomeUrl'	=> true,  	# default true, if set false, home will not add url (a).
        //'intervalSymbol'=> ' >> '	# default value:' > '
      ],
      
      'cms' => [
        'class' 		=> 'fecshop\services\page\Cms',
      ],
      'theme' => [
        'class' 		=> 'fecshop\services\page\Theme',
      ],
      'widget' => [
        'class' 		=> 'fecshop\services\page\Widget',
        # 定义默认方法,也就是widgetConfig 里面各个部件里面的method如果没有填写
        # 则使用该配置。
        # 'defaultObMethod' => 'getLastData',
        
        'widgetConfig' => [
          'menu' =>[
            # 必填
            'class' => 'fec\block\TestMenu',
            # view 的绝对路径配置方式
            'view'  => '@fec/views/testmenu/index.php',
            # 下面为选填
            'method'=> 'getLastData',
            'terry1'=> 'My1',
            'terry2'=> 'My2',
          ],
          'love' => [
            'class' => 'fecshop\app\appfront\modules\Cms\block\widget\Test',
            # 根据多模板的优先级,依次去模板找查找该文件,直到找到这个文件。
            'view'  => 'cms/home/test.php',
            'terry' => 'II',
          ]
        ]
        
      ],
      'currency' => [
        'class' => 'fecshop\services\page\Currency',
        'currencys' => [
          'USD' => [
            'rate' 		=> 1,
            'symbol' 	=> '$',
          ],
          'RMB' => [
            'rate' 		=> 6.3,
            'symbol' 	=> '¥',
          ],
        ],
        //'defaultCurrency' => 'USD',
      ],
      
      'footer' => [
        'class' 		=> 'fecshop\services\page\Footer',
       
      ],
      
      
      'newsletter' => [
        'class' 		=> 'fecshop\services\page\Newsletter',
      ],
      
      'staticblock' => [
        'class' 		=> 'fecshop\services\page\StaticBlock',
      ],
      
      'menu' => [
        'class' => 'fecshop\services\page\Menu',
        'displayHome' => [
          'enable' => true,
          'display'=> 'Home',
        ],
        /**
         *	custom menu  in the front menu section.
         */
        'frontCustomMenu' => [
          [
            'name' 		=> 'my custom menu',
            'urlPath'	=> '/my-custom-menu.html',
            'childMenu' => [
              [
                'name' 		=> 'my custom menu 2',
                'urlPath'	=> '/my-custom-menu-2.html',
              ],
              [
                'name' 		=> 'my custom menu 2',
                'urlPath'	=> '/my-custom-menu-2.html',
                'childMenu' => [
                  [
                    'name' 		=> 'my custom menu 2',
                    'urlPath'	=> '/my-custom-menu-2.html',
                  ],
                  [
                    'name' 		=> 'my custom menu 2',
                    'urlPath'	=> '/my-custom-menu-2.html',
                  ],
                ],	
              ],
            ],	
          ],
          [
            'name' 		=> 'my custom menu 2',
            'urlPath'	=> '/my-custom-menu-2.html',
          ],
        ],
        /**
         *	custom menu  behind the menu section.
         */
        'behindCustomMenu' => [
          [
            'name' 		=> 'my behind custom menu',
            'urlPath'	=> '/my-behind-custom-menu.html',
          ],
          [
            'name' 		=> 'my behindcustom menu 2',
            'urlPath'	=> '/my-behind-custom-menu-2.html',
          ],
        ],
      ],
      
    ],
  ],
];

上面是page组件的配置,childService里面是page组件的子组件配置,配置方法和组件类似。

在fecshop的底层,组件作为整个开源商城服务的支撑,组件服务为上层的modules提供数据,为各个应用提供数据,有点类似SOA架构的服务,

下面是目前的服务的列表:

Affiliate.php: 网站联盟组件服务

Blog.php:博客服务组件

Cart.php:购物车服务组件

Category.php:分类服务组件

Coupon.php:优惠券服务组件

Customer.php:用户账号服务组件

——–Customer子组件 – 地址:Address

——–Customer子组件 – 网盟:Affiliate

——–Customer子组件 – 优惠券:Coupon

——–Customer子组件 – 线下分销:DropShip

——–Customer子组件 – 收藏:Favorite

——–Customer子组件 – 面包屑导航:Breadcrumbs

——–Customer子组件 – 消息:Message

——–Customer子组件 – 订单:Order

——–Customer子组件 – 积分:Point

——–Customer子组件 – 评论:Review

——–Customer子组件 – 批发:Wholesale

Email.php:邮件服务组件

Order.php:订单服务组件

Page.php:页面等服务组件

——–Page子组件 – 面包屑导航:Breadcrumbs

——–Page子组件 – cms Page:cms

——–Page子组件 – 货币:Currency

——–Page子组件 – 页面底部:Footer

——–Page子组件 – 菜单:menu

——–Page子组件 – 邮件订阅:newsletter

——–Page子组件 – 静态块:Static Block

——–Page子组件 – 模板配置功能:theme

——–Page子组件 – 小部件:Widget

Payment.php:支付服务组件

point.php:积分服务组件

Product.php:产品服务组件

——–Product子组件 – 产品访问历史记录:ViewLog

————————–ViewLog子组件 – Db.php:Mysql 存储

————————–ViewLog子组件 – Mongodb.php:Mongodb 存储

————————–ViewLog子组件 – Session.php:Session 存储

——–Product子组件 – 热卖产品:BestSell

——–Product子组件 -买了的还买了:BuyAlsoBuy

——–Product子组件 – 产品分类:Category

——–Product子组件 – 产品集合:Coll

——–Product子组件 – 产品图片:Image

——–Product子组件 – 产品详细:Info

——–Product子组件 – 产品价格:Price

——–Product子组件 – 相关产品:Relate

——–Product子组件 – 产品评论:Review

——–Product子组件 -看了的还看了:ViewAlsoView

Request.php:Request服务组件

Search.php:搜索功能服务组件

Shipping:货运物流服务组件

Sitemap.php:Sitemap服务组件

Store.php:Store服务组件

Url.php:Url服务组件

Wholesale.php:批发功能服务组件

 

 

 

 

 

 

 

yii2 fecshop 的扩展开发

  1. 如何做一个基于composer的插件,来扩展fecshop。
  2. 如何通过yii2插件或者二次开发修改 重写yii2的功能
  3. 如何通过插件或者二次开发修改 重写fecshop service
    1. service列表
  4. 如何通过插件或者二次开发修改 重写fecshop module
    1. fecshop module 列表
  5. 如何通过插件或者二次开发修改fecshop module controller
    1. controller
  6. 如何做fecshop的模板?

上面是一些列表,找时间做深度解答。

yii2 fecshop 功能列表

fecshop的功能列表:

  1. 多入口机制,每一个入口添加一个域名,独立分开,譬
    1. demo.appadmin.fecshop.com  解析到 appadmin 应用.
    2. demo.appfront.fecshop.com    解析到 appfront   应用.
    3. demo.apphtml5.fecshop.com  解析到 apphtml5  应用.
    4. demo.appserver.fecshop.com 解析到 appserver 应用.
  2. 单入口单index.php 多域名,可以把多个域名解析到同一个入口,譬如为了实现多语言,我们把  en.appfront.fecshop , fr.appfront.fecshop , de.appfront.fecshop 都解析到appfront应用入口,然后通过不同的域名,加载不同的配置语言,和初始默认货币等,进而实现多语言。
  3. 单入口 多文件夹index.php 单域名,譬如将  www.fecshop.com解析到  appfront/web/index.php,然后新建
    1. appfront/web/fr/index.php
    2. appfront/web/es/index.php
    3. appfront/web/de/index.php

然后访问  www/fecshop.com   ,www/fecshop.com/fr ,www/fecshop.com/es ,www/fecshop.com/de,进行语言的切换。

4. 多语言  根据不同的store,加载不同的语言,也可以进行语言的切换

5.多货币,根据不同的store,加载不同的货币,也可以进行货币的切换

6.产品属性可配置化。分类选择一个属性组,用来做分类侧栏属性过滤 ,产品选择一个属性组,用来做属性的添加。最终在这个分类做属性过滤后,就会出现对应的属性产品。

7.组件化服务可配置,可重写

8.整体系统配置化,可以在不动fecshop源代码的情况下,修改任意功能。

9.多模板系统,通过各个模板的优先级顺序,加载view文件,如果在高级别的模板中文件不存在则依次到优先级低的模板中查找,直到找到view文件,  通过这种方式,高级别的模板如果想要重写低级别模板的某个文件,只要把这个文件复制到当前模板,路径对应好即可。

 

yii2 fecshop 框架特性

框架特性:

按照程序的执行顺序,大致分为4个层次:

1.app应用入口:首先通过nginx解析到appfront,appadmin,apphtml5等app层入口index文件,然后由index.php加载各个配置传递给application,这一层做的事情是配置的收集,组合,最终生成一个大的config数据传递给yii2 application,每一个app应用的配置文件是不同的,进而后面的各个层的执行都会不一样。

2.yii2初始化层,在第一步骤的config数组传递给yii2 application,就开始了yii2的初始化层,一直到执行conroller之前,也就是在做调度之前,都是yii2的初始化层,yii2系统执行的任务,设立涉及到很多对象的初始化,有yii2系统的,也有第三方添加的bootstrap部分,其中组件,模块都是可以添加bootstrap的,这一步骤发生在执行controller之前的初始化,也就是无论执行那个controller,都必须执行的部分。(注意,这里的bootstrap指的是yii2的初始化,而不是twitter 出的css框架 bootstrap)

3.Module层:在yii2初始化完成后,执行的就是模块层,这一层,里面有controller,block,view三层结构,controller仅仅负责调度,block负责解析前台传递的数据,调用相应的组件服务,产生相应的结果,对于content部分,是由controller接收,传递到view,也有直接使用block和view生成的html部分代码,

对于controller层和view层,都不会陌生,block层是我新加入的一个层,也就是把controller中对逻辑的处理,全部放到block层来完成,block像是肌肉层,负责连接,连接前台传递的数据,调用相应的组件服务,返回数据给controller,当然block也是某个小部件的数据提供者(独立功能块)。

view接收数据,view分为3部分,layout部分和view content部分,这个是yii2本身有的,另外还有通过render函数生成的独立块,独立块由block和view文件组成,将生成的html可以通过配置的方式加到很多页面,譬如产品访问记录块,在产品页面的侧栏,分类页面的侧栏可能都要显示,那么可以做成块的方式调用即可。

这一层是加入缓存最多的一层,甚至是整页缓存(full page cache),动态数据用ajax动态异步加载。

总之,module是一个大的调度层和数据显示层,本身不涉及到复杂的数据处理,负责的数据处理都是在组件层完成,在module层是不允许访问model层的,大致的流程为:解析前端请求,到后端的组件服务层提取数据,组织数据,结果传递给view,然后画出来整个页面。

4.组件服务层:在model层之上的,就是组件服务层,这一层面提供各种服务,服务的粒子大致为描述性粒度,譬如产品加入购物车,查看购物车的产品,生 成订单,删除购物车产品等,这些功能的操作都是通过组件的一个函数直接返回,有点类似于微服务结构里面的各个服务,不过fecshop的组件服务层是有状态的,另外,该层和上面的各个层是放到一个主机上面的,因为是直接通过组件服务进行调用方法,所以不可以分割到不同的主机。通俗来讲,组件服务层提供的是 一个描述性的操作粒度,为了快速响应,根据需求,这一层可能被加入缓存功能,总之,这一层面的操作,会涉及到多个model的 操作,最终成为一个描述性粒度的功能。

在举个例子:譬如产品加入购物车,假设我们要扣除库存,那么对应着操作:

当前用户是否登录,如果登录则…

验证传递的产品参数是否存在有效(前端传递数据的有效性),然后….

将产品数据加入到cart表中…

扣除库存…

等等,上面这一系列的操作,会涉及到很多表的查询和更新插入等操作,但是我们描述的粒度为  产品加入购物车,在数据库端要执行的所有操作,都是在一个描述粒度里面,后期可能加入很多其他方面的扩展,譬如判断是否有优惠券,是否使用积分等等,都会添加到这个粒度里面,但是对访问服务组件层的module来说,是透明的,无论服务层如何更改添加新功能,module还是按照之前的方式调用(当然有可能多传递一些参数,甚至返回的数据格式有变化)。

5.Model层:数据库操作层,分为mysql和mongodb,访问数据库层,所做的事情有:数据的查找,更新和插入时的数据验证,保存,数据的删除,以及其他一部分基于数据操作的函数等,这个层面提供的功能粒度比较小,是基于表操作的粒度,module不会添加事务,事务的控制在服务层添加。由组件服务层来组织。

OK,fecshop的框架大致如此。

 

 

 

yii2 fecshop的初衷

以下为做fecshop的初衷和fecshop的简介

1.关于对magento的情感

自从2010年进入外贸电商,就开始玩magento,magento一直以来,以seo友好,容易收录,功能强大,可配置性强,灵活度大,支持度高等各个方面完胜其他开源框架,基于xml的配置和基于EAV数据表模型,让magento的插件和模板异常的丰富,magento的插件,基本上可以在不修改源文件的前提,修改任意magento代码,当然,这些都是有代价的,magento的初始化必须加载完所有的xml文件才能进行解析controller,初始化过于笨重,自身的框架过于雍容,在速度,并发方面一直处于劣势,尤其是EAV模型的数据库模型,让magento在产品数据增多的情况下,一旦超过10000个产品后,性能就会带来一定的下降,当产品超过3,4万,性能明显下降,对mysql的内存消耗非常大,当插件增多的情况下,php端对xml解析对服务器的资源吃的也比较厉害。另外在产品很多,store很多的情况下,indexer索引也是硬伤,关于magneto的一些问题,我在知乎上面回答了一个问题:https://www.zhihu.com/question/19813425#zh-question-answer-wrap

总之,magento的灵活度高,解决了自身版本升级,第三方插件升级,和用户二次开发之间冲突的问题,通过配置的方式来协调使用那一块文件代码,magento除了自身功能完善,还有大量的第三方插件和模板,让magento这个闭环更加的完善,但是magento的并发性能较差,日ip超过2万的情况下,没有varnish,2台独立主机都很难平稳的抗住,另外,重构magento的某个底层也是比较困难,这些都是magento的不足。

2.对yii2的情感。

从2014年接触yii2,用yii2做了3个项目,一个电商网站,一个erp系统,一个业务数据分析系统,对yii2框架的认知加深后,越来越喜欢这个php框架,在架构方面非常的优秀,全程基于配置,用户可以在不修改yii2文件代码的前提下修改和扩展yii2框架的功能,单例模式的组件,等基于控制反转的思想设计而成,还有model的role验证,命令行模式的批处理console,类似于一个小系统的模块,多入口应用,可以新建一堆类似frontend,backend这样的入口应用,安全性高,可以通过bootstrap配置加入初始化代码,数据库升级migrate等,yii2是一个非常适合做产品的框架。

3.fecshop的想法

作为一个电商系统产品,我认为有两个大问题比较关键:

3.1 产品自身功能升级,和第三方插件扩展升级,和用户自身二次开发的矛盾的解决, 总体来说就是:各自在各自的文件系统中开发,通过配置的方式覆盖,yii2的配置是基于数据,而不是magento那类笨笨的xml,资源消耗小

3.2 对底层功能的重构和选择,对于一个底层的功能,譬如购物车,我前期用的是基于session,后期我发现不行,我需要吧购物车数据放到mysql中,后来我又想放到redis中(假设),如果我是标注的mvc模式,重构将非常的困难,因为对购物车的操作散步在各个地方,不知道那个地方会漏掉,因此,我们需要更改我们的模式,我想到的是用组件的形式提供服务,各个模块不允许调用数据库,只能通过对服务的调用来完成功能,如果我想重构某个服务,我只需要把这个服务组件里面所有的public方法实现即可,数据的流向为: model –>service component –>module->block->view

这样,我甚至可以对同一个功能做多个服务组件,譬如购物车,我做了session cart,mysql cart让用户选择。

糅合yii2的新型思维,mongodb的多维数组,mysql的事务性,mongodb的强大配置和灵活度,我想基于mysql和mongodb数据库,用yii2框架,参膜magento的灵活,实现一套电商开源系统,我给予的名字为fancy ecommerce shop,简称fecshop。