nopCommerce 3.9 大波浪系列 之 开发支持多店的插件

Posted 大波浪 要上进

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nopCommerce 3.9 大波浪系列 之 开发支持多店的插件相关的知识,希望对你有一定的参考价值。

一.基础介绍

       nop支持多店及多语言,本篇结合NivoSlider插件介绍下如何开发支持多商城的小部件。

       主要接口如下:

ISettingService 接口:设置接口,可实现多店配置。

ILocalizationService 接口:本地化资源接口,配合语言,实现多语言的显示。

二.插件安装、卸载

      我们在上一篇介绍了小部件如何使用(点击这里),这里介绍下如何安装、卸载插件。

【后台管理】【插件管理】【本地插件】可以对插件进行安装、卸载

Nop.Admin.Controllers.PluginController控制器用于插件的管理。Install负责安装插件、Uninstall负责卸载插件。

     所有插件都继承IPlugin接口,Install(),Uninstall()分别用于安装及卸载。

  1 namespace Nop.Core.Plugins
  2 {
  3     /// <summary>
  4     /// Interface denoting plug-in attributes that are displayed throughout 
  5     /// the editing interface.
  6     /// </summary>
  7     public interface IPlugin
  8     {
  9         /// <summary>
 10         /// Gets or sets the plugin descriptor
 11         /// </summary>
 12         PluginDescriptor PluginDescriptor { get; set; }
 13 
 14         /// <summary>
 15         /// Install plugin
 16         /// </summary>
 17         void Install();
 18 
 19         /// <summary>
 20         /// Uninstall plugin
 21         /// </summary>
 22         void Uninstall();
 23     }
 24 }
 25 

       BasePlugin抽象类继承了IPlugin接口,并实现了 Install(),Uninstall()方法,当安装时在"~/App_Data/InstalledPlugins.txt"文件中写入插件的SystemName,卸载时则在文件中删除。

  1 namespace Nop.Core.Plugins
  2 {
  3     /// <summary>
  4     /// Base plugin
  5     /// </summary>
  6     public abstract class BasePlugin : IPlugin
  7     {
  8         /// <summary>
  9         /// Gets or sets the plugin descriptor
 10         /// </summary>
 11         public virtual PluginDescriptor PluginDescriptor { get; set; }
 12 
 13         /// <summary>
 14         /// Install plugin
 15         /// </summary>
 16         public virtual void Install()
 17         {
 18             PluginManager.MarkPluginAsInstalled(this.PluginDescriptor.SystemName);
 19         }
 20 
 21         /// <summary>
 22         /// Uninstall plugin
 23         /// </summary>
 24         public virtual void Uninstall()
 25         {
 26             PluginManager.MarkPluginAsUninstalled(this.PluginDescriptor.SystemName);
 27         }
 28 
 29     }
 30 }
 31 

       我们看下NivoSlider插件在安装时都做了哪些操作。

  1 using System.Collections.Generic;
  2 using System.IO;
  3 using System.Web.Routing;
  4 using Nop.Core;
  5 using Nop.Core.Plugins;
  6 using Nop.Services.Cms;
  7 using Nop.Services.Configuration;
  8 using Nop.Services.Localization;
  9 using Nop.Services.Media;
 10 
 11 namespace Nop.Plugin.Widgets.NivoSlider
 12 {
 13     /// <summary>
 14     /// PLugin
 15     /// </summary>
 16     public class NivoSliderPlugin : BasePlugin, IWidgetPlugin
 17     {
 18         private readonly IPictureService _pictureService;
 19         private readonly ISettingService _settingService;
 20         private readonly IWebHelper _webHelper;
 21 
 22         public NivoSliderPlugin(IPictureService pictureService,
 23             ISettingService settingService, IWebHelper webHelper)
 24         {
 25             this._pictureService = pictureService;
 26             this._settingService = settingService;
 27             this._webHelper = webHelper;
 28         }
 29 
 30         /// <summary>
 31         /// Gets widget zones where this widget should be rendered
 32         /// </summary>
 33         /// <returns>Widget zones</returns>
 34         public IList<string> GetWidgetZones()
 35         {
 36             return new List<string> { "home_page_top" };
 37         }
 38 
 39         /// <summary>
 40         /// Gets a route for provider configuration
 41         /// </summary>
 42         /// <param name="actionName">Action name</param>
 43         /// <param name="controllerName">Controller name</param>
 44         /// <param name="routeValues">Route values</param>
 45         public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
 46         {
 47             actionName = "Configure";
 48             controllerName = "WidgetsNivoSlider";
 49             routeValues = new RouteValueDictionary { { "Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers" }, { "area", null } };
 50         }
 51 
 52         /// <summary>
 53         /// Gets a route for displaying widget
 54         /// </summary>
 55         /// <param name="widgetZone">Widget zone where it\'s displayed</param>
 56         /// <param name="actionName">Action name</param>
 57         /// <param name="controllerName">Controller name</param>
 58         /// <param name="routeValues">Route values</param>
 59         public void GetDisplayWidgetRoute(string widgetZone, out string actionName, out string controllerName, out RouteValueDictionary routeValues)
 60         {
 61             actionName = "PublicInfo";
 62             controllerName = "WidgetsNivoSlider";
 63             routeValues = new RouteValueDictionary
 64             {
 65                 {"Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers"},
 66                 {"area", null},
 67                 {"widgetZone", widgetZone}
 68             };
 69         }
 70 
 71         /// <summary>
 72         /// Install plugin
 73         /// </summary>
 74         public override void Install()
 75         {
 76             //pictures
 77             var sampleImagesPath = CommonHelper.MapPath("~/Plugins/Widgets.NivoSlider/Content/nivoslider/sample-images/");
 78 
 79 
 80             //settings
 81             var settings = new NivoSliderSettings
 82             {
 83                 Picture1Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner1.jpg"), MimeTypes.ImagePJpeg, "banner_1").Id,
 84                 Text1 = "",
 85                 Link1 = _webHelper.GetStoreLocation(false),
 86                 Picture2Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner2.jpg"), MimeTypes.ImagePJpeg, "banner_2").Id,
 87                 Text2 = "",
 88                 Link2 = _webHelper.GetStoreLocation(false),
 89                 //Picture3Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner3.jpg"), MimeTypes.ImagePJpeg, "banner_3").Id,
 90                 //Text3 = "",
 91                 //Link3 = _webHelper.GetStoreLocation(false),
 92             };
 93             _settingService.SaveSetting(settings);
 94 
 95 
 96             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture1", "Picture 1");
 97             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture2", "Picture 2");
 98             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture3", "Picture 3");
 99             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture4", "Picture 4");
100             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture5", "Picture 5");
101             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture", "Picture");
102             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture.Hint", "Upload picture.");
103             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Text", "Comment");
104             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Text.Hint", "Enter comment for picture. Leave empty if you don\'t want to display any text.");
105             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Link", "URL");
106             this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Link.Hint", "Enter URL. Leave empty if you don\'t want this picture to be clickable.");
107 
108             base.Install();
109         }
110 
111         /// <summary>
112         /// Uninstall plugin
113         /// </summary>
114         public override void Uninstall()
115         {
116             //settings
117             _settingService.DeleteSetting<NivoSliderSettings>();
118 
119             //locales
120             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture1");
121             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture2");
122             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture3");
123             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture4");
124             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture5");
125             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture");
126             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture.Hint");
127             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Text");
128             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Text.Hint");
129             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Link");
130             this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Link.Hint");
131 
132             base.Uninstall();
133         }
134     }
135 }
136 
Nop.Plugin.Widgets.NivoSlider

     在上边源代码中我们看到安装时调用Install()方法进行了如下操作

1.定义NivoSliderSettings类,该类继承ISettings,用于保存幻灯片的配置。将初始化的配置保存到数据库Setting表中。

2.this.AddOrUpdatePluginLocaleResource方法添加本地资源,主要用于配置资源在多语言支持。

3.base.Install() 进行插件安装。

     卸载插件时调用Uninstall()方法对配置进行删除,对本地资源进行删除同时卸载插件。

     以上就是在插件安装、卸载时调用的方法介绍,在二次开发时可在相关时间点进行插件的配置。

三.插件配置路由

      不同插件有属于自己的配置项,例如支付宝插件和微信支付插件同是支付插件但是配置却不一样。为了实现不同配置引入了配置路由。小部件IWidgetPlugin接口GetConfigurationRoute方法用于返回配置接口的路由信息。我们看下NivoSlider插件

  1    /// <summary>
  2         /// Gets a route for provider configuration
  3         /// </summary>
  4         /// <param name="actionName">Action name</param>
  5         /// <param name="controllerName">Controller name</param>
  6         /// <param name="routeValues">Route values</param>
  7         public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
  8         {
  9             actionName = "Configure";
 10             controllerName = "WidgetsNivoSlider";
 11             routeValues = new RouteValueDictionary { { "Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers" }, { "area", null } };
 12         }

      当点击配置时路由到WidgetsNivoSlider控制器Configure()方法,显示插件配置页面

C08]NI@_X%HO_J$H{VC$B53

四.多店配置实现

MYRGDJGMO~MSD@G{MC6$YEO

如果配置了两个以上的商城就会出现上边的多店设置。可针对不同商店进行不同的配置。

  1 [AdminAuthorize]
  2         [ChildActionOnly]
  3         public ActionResult Configure()
  4         {
  5             //加载可用商店的范围
  6             var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
  7             var nivoSliderSettings = _settingService.LoadSetting<NivoSliderSettings>(storeScope);//加载可用商店的配置
  8             var model = new ConfigurationModel();
  9             model.Picture1Id = nivoSliderSettings.Picture1Id;
 10             model.Text1 = nivoSliderSettings.Text1;
 11             model.Link1 = nivoSliderSettings.Link1;
 12             model.Picture2Id = nivoSliderSettings.Picture2Id;
 13             model.Text2 = nivoSliderSettings.Text2;
 14             model.Link2 = nivoSliderSettings.Link2;
 15             model.Picture3Id = nivoSliderSettings.Picture3Id;
 16             model.Text3 = nivoSliderSettings.Text3;
 17             model.Link3 = nivoSliderSettings.Link3;
 18             model.Picture4Id = nivoSliderSettings.Picture4Id;
 19             model.Text4 = nivoSliderSettings.Text4;
 20             model.Link4 = nivoSliderSettings.Link4;
 21             model.Picture5Id = nivoSliderSettings.Picture5Id;
 22             model.Text5 = nivoSliderSettings.Text5;
 23             model.Link5 = nivoSliderSettings.Link5;
 24             model.ActiveStoreScopeConfiguration = storeScope;
 25             if (storeScope > 0)
 26             {
 27                 model.Picture1Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture1Id, storeScope);
 28                 model.Text1_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text1, storeScope);
 29                 model.Link1_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link1, storeScope);
 30                 model.Picture2Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture2Id, storeScope);
 31                 model.Text2_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text2, storeScope);
 32                 model.Link2_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link2, storeScope);
 33                 model.Picture3Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture3Id, storeScope);
 34                 model.Text3_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text3, storeScope);
 35                 model.Link3_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link3, storeScope);
 36                 model.Picture4Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture4Id, storeScope);
 37                 model.Text4_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text4, storeScope);
 38                 model.Link4_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link4, storeScope);
 39                 model.Picture5Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture5Id, storeScope);
 40                 model.Text5_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text5, storeScope);
 41                 model.Link5_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link5, storeScope);
 42             }
 43 
 44             return View("~/Plugins/Widgets.NivoSlider/Views/Configure.cshtml", model);
 45         }
配置源码

查看源码我们会发现这两句是控制多店配置的

  1  //加载可用商店的范围
  2  var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
  3  var nivoSliderSettings = _settingService.LoadSetting<NivoSliderSettings>(storeScope);//加载可用商店的配置

首先加载当前配置的商店。获取到 storeScope后加载该商店NivoSliderSetting配置项的设置。

这样当选择不同的商城就可以获取到选择商城中配置的值了。

     我们再来看下Configure.cshtml视图

     @Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" })

     该路由用于生成nop多店设置模块image,选择不同商城会调用Setting控制器,ChangeStoreScopeConfiguration方法,该方法会将用户选择的商城id 保存在GenericaAttribute表中如下图。

(IDL)4E2P@]U8JOP_628@)I

     SystemCustomerAttributeNames.AdminAreaStoreScopeConfiguration变量对应的就是Key值,Velue保存为商城的Id。

当页面选择不同的商城时,经过上边方法的处理,再调用var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); 方法就可以获取到指定的商城了。

     image

当指定商城时我们会发现配置项每一项都多出一个单选框,选择则可针对该商城的该配置经进行设置,如果不选择则使用默认项。

在视图中如何生成这个单选项呢?看下源码

@Html.OverrideStoreCheckboxFor(model => model.Picture2Id_OverrideForStore, model => model.Picture2Id, Model.ActiveStoreScopeConfiguration)

使用该Html扩展来实现商城配置的定制。OverrideStoreCheckboxFor扩展是Nop.Web.Framework.HtmlExtensions 类中的扩展。

model.Picture2Id_OverrideForStore为True时使用自定义商城配置,model.Picture2Id为配置属性,model.ActiveStoreScopeConfiguration为当前商城id。

可以看出支持多店配置的model比普通model多出ActiveStoreScopeConfiguration属性用于保存商城id,同时每个属性多一个_OverrideForStore的bool方法用于判断是否覆盖店铺默认值。

  1 @{
  2     Layout = "";
  3 }
  4 @model Nop.Plugin.Widgets.NivoSlider.Models.ConfigurationModel
  5 @using Nop.Web.Framework;
  6 
  7 @Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" })
  8 
  9 @using (Html.BeginForm())
 10 {
 11     @Html.AntiForgeryToken()
 12     <div class="panel-group">
 13         <div class="panel panel-default">
 14             <div class="panel-heading">
 15                 @T("Plugins.Widgets.NivoSlider.Picture1")
 16             </div>
 17             <div class="panel-body">
 18                 <div class="form-group">
 19                     <div class="col-md-3">
 20                         @Html.OverrideStoreCheckboxFor(model => model.Picture1Id_OverrideForStore, model => model.Picture1Id, Model.ActiveStoreScopeConfiguration)
 21                         @Html.NopLabelFor(model => model.Picture1Id)
 22                     </div>
 23                     <div class="col-md-9">
 24                         @Html.NopEditorFor(model => model.Picture1Id)
 25                         @Html.ValidationMessageFor(model => model.Picture1Id)
 26                     </div>
 27                 </div>
 28                 <div class="form-group">
 29                     <div class="col-md-3">
 30                         @Html.OverrideStoreCheckboxFor(model => model.Text1_OverrideForStore, model => model.Text1, Model.ActiveStoreScopeConfiguration)
 31                         @Html.NopLabelFor(model => model.Text1)
 32                     </div>
 33                     <div class="col-md-9">
 34                         @Html.NopEditorFor(model => model.Text1)
 35                         @Html.ValidationMessageFor(model => model.Text1)
 36                     </div>
 37                 </div>
 38                 <div class="form-group">
 39                     <div class="col-md-3">
 40                         @Html.OverrideStoreCheckboxFor(model => model.Link1_OverrideForStore, model => model.Link1, Model.ActiveStoreScopeConfiguration)
 41                         @Html.NopLabelFor(model => model.Link1)
 42                     </div>
 43                     <div class="col-md-9">
 44                         @Html.NopEditorFor(model => model.Link1)
 45                         @Html.ValidationMessageFor(model => model.Link1)
 46                     </div>
 47                 </div>
 48             </div>
 49         </div>
 50         <div class="panel panel-default">
 51             <div class="panel-heading">
 52                 @T("Plugins.Widgets.NivoSlider.Picture2")
 53             </div>
 54             <div class="panel-body">
 55                 <div class="form-group">
 56                     <div class="col-md-3">
 57                         @Html.OverrideStoreCheckboxFor(model => model.Picture2Id_OverrideForStore, model => model.Picture2Id, Model.ActiveStoreScopeConfiguration)
 58                         @Html.NopLabelFor(model => model.Picture2Id)
 59                     </div>
 60                     <div class="col-md-9">
 61                         @Html.NopEditorFor(model => model.Picture2Id)
 62                         @Html.ValidationMessageFor(model => model.Picture2Id)
 63                     </div>
 64                 </div>
 65                 <div class="form-group">
 66                     <div class="col-md-3">
 67                         @Html.OverrideStoreCheckboxFor(model => model.Text2_OverrideForStore, model => model.Text2, Model.ActiveStoreScopeConfiguration)
 68                         @Html.NopLabelFor(model => model.Text2)
 69                     </div>
 70                     <div class="col-md-9">
 71                         @Html.NopEditorFor(model => model.Text2)
 72                         @Html.ValidationMessageFor(model => model.Text2)
 73                     </div>
 74                 </div>
 75                 <div class="form-group">
 76                     <div class="col-md-3">
 77                         @Html.OverrideStoreCheckboxFor(model => model.Link2_OverrideForStore, model => model.Link2, Model.ActiveStoreScopeConfiguration)
 78                         @Html.NopLabelFor(model => model.Link2)
 79                     </div>
 80                     <div class="col-md-9">
 81                         @Html.NopEditorFor(model => model.Link2)
 82                         @Html.ValidationMessageFor(model => model.Link2)
 83                     </div>
 84                 </div>
 85             </div>
 86         </div>
 87         <div class="panel panel-default">
 88             <div class="panel-heading">
 89                 @T("Plugins.Widgets.NivoSlider.Picture3")
 90             </div>
 91             <div class="panel-body">
 92                 <div class="form-group">
 93                     <div class="col-md-3">
 94                         @Html.OverrideStoreCheckboxFor(model => model.Picture3Id_OverrideForStore, model => model.Picture3Id, Model.ActiveStoreScopeConfiguration)
 95                         @Html.NopLabelFor(model => model.Picture3Id)
 96                     </div>
 97                     <div class="col-md-9">
 98                         @Html.NopEditorFor(model => model.Picture3Id)
 99                         @Html.ValidationMessageFor(model => model.Picture3Id)
100                     </div>
101                 </div>
102                 <div class="form-group">
103                     <div class="col-md-3">
104                         @Html.OverrideStoreCheckboxFor(model => model.Text3_OverrideForStore, model => model.Text3, Model.ActiveStoreScopeConfiguration)
105                         @Html.NopLabelFor(model => model.Text3)
106                     </div>
107                     <div class="col-md-9">
108                         @Html.NopEditorFor(model => model.Text3)
109                         @Html.ValidationMessageFor(model => model.Text3)
110                     </div>
111                 </div>
112                 <div class="form-group">
113                     <div class="col-md-3">
114                         @Html.OverrideStoreCheckboxFor(model => model.Link3_OverrideForStore, model => model.Link3, Model.ActiveStoreScopeConfiguration)
115                         @Html.NopLabelFor(model => model.Link3)
116                     </div>
117                     <div class="col-md-9">
118                         @Html.NopEditorFor(model => model.Link3)
119                         @Html.ValidationMessageFor(model => model.Link3)
120                     </div>
121                 </div>
122             </div>
123         </div>
124         <div class="panel panel-default">
125             <div class="panel-heading">
126                 @T("Plugins.Widgets.NivoSlider.Picture4")
127             </div>
128             <div class="panel-body">
129                 <div class="form-group">
130                     <div class="col-md-3">
131                         @Html.OverrideStoreCheckboxFor(model => model.Picture4Id_OverrideForStore, model => model.Picture4Id, Model.ActiveStoreScopeConfiguration)
132                         @Html.NopLabelFor(model => model.Picture4Id)
133                     </div>
134                     <div class="col-md-9">
135                         @Html.NopEditorFor(model => model.Picture4Id)
136                         @Html.ValidationMessageFor(model => model.Picture4Id)

以上是关于nopCommerce 3.9 大波浪系列 之 开发支持多店的插件的主要内容,如果未能解决你的问题,请参考以下文章

nopCommerce 3.9 大波浪系列 之 汉化-Roxy Fileman

nopCommerce 3.9 大波浪系列 之 global.asax

nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]

nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]

nopCommerce 3.9 大波浪系列 之 开发支持多店的插件

nopCommerce 3.9 大波浪系列 之 可退款的支付宝插件(上)