در این آموزش، با استفاده از معماری پلاگین ها در ناپ کامرس برای پیاده سازی یک رهگیر محصول، استفاده می شود. قبل از اینکه توسعه را شروع کنیم بسیار مهم است که موارد مطرح شده در خودآموزهای زیر را بدرستی بخوانید من از برخی توضیحات که در مقالات قبلی وجود دارد می گذرم، اما میتوانید با استفاده از لینکهای ارائه شده، خلاصه ای از این بحث را دنبال کنید/
خودآموز برنامه نویسان بروزرسانی نهاد موجود. چگونگی افزودن یک مشخصه جدید. چگونگی نوشتن یک افزونه برای ناپ کامرس 4.00
ما شروع به برنامه نویسی با لایه دسترسی به داده ها می کنیم، به لایه سرویس می رویم، و در نهایت با ورود وابستگی پایان می دهیم.
نکته: کاربرد عملی این افزونه مورد سوال است، اما من نمیتوانم از ویژگیهایی که با nopCommerce همراه نبود و حجم این پست معقول باشد. اگر از این پلاگین در محیط واقعی استفاده می کنید، هیچ گونه ضمانتی ارائه نمی دهم. من همیشه به داستان های موفقیت علاقه مند هستم و خوشحال می شوم متوجه شوم که این پست بیش از یک نوشته آموزشی باشد.
یک پروژه کتابخانه کلاس جدید به نام "Nop.Plugin.Other.ProductViewTracker" ایجاد کنید.
پوشه های زیر و فایل plugin.json را اضافه کنید.
شما می توانید فایل plugin.json را در تصویر زیر مشاهده کنید.
سپس منابع را به پروژه های زیر اضافه کنید: Nop.Core, Nop.Data, Nop.Web.Framework
درون فضای نام دامنه "domain" قصد داریم یک کلاس عمومی به نام ProductViewTrackerRecord ایجاد کنیم. این کلاس BasicEntity را گسترش می دهد، اما در غیر این صورت یک فایل بسیار خسته کننده است. چیزی که باید به یاد بیاورد این است که همه مشخصه ها به عنوان مجازی مشخص شده اند و فقط برای سرگرمی نیستند. خواص مجازی در نهادهای پایگاه داده مورد نیاز است زیرا چارچوب Entity Framework کلاسهای مورد نیاز را ترسیم می کند. یکی دیگر از چیزهایی که باید یادآوری کرد این است که ما ویژگیهای ناوبری (خواص ارتباطی) نداریم و بعدا جزئیات بیشتری را خواهم دید.
namespace Nop.Plugin.Other.ProductViewTracker.Domain
{
public class ProductViewTrackerRecord : BaseEntity
public virtual int ProductId { get; set; }
public virtual string ProductName { get; set; }
public virtual int CustomerId { get; set; }
public virtual string IpAddress { get; set; }
public virtual bool IsRegistered { get; set; }
}
موقعیت فایل ها: برای فهمیدن اینکه هر فایل باید در چه محلی وجود داشته باشد، فضای نام را تجزیه و تحلیل می کند و فایل را بر اساس آن ایجاد می کند.
کلاس بعدی برای ایجاد کلاس نگاشت Entity Framework است. در داخل کلاس نگاشت ستون ها، روابط جدول ها و جدول پایگاه داده ها را می نویسیم.
namespace Nop.Plugin.Other.ProductViewTracker.Data
public class ProductViewTrackerRecordMap : NopEntityTypeConfiguration<ProductViewTrackerRecord>
public ProductViewTrackerRecordMap()
ToTable("ProductViewTracking");
//Map the primary key
HasKey(m => m.Id);
//Map the additional properties
Property(m => m.ProductId);
//Avoiding truncation/failure
//so we set the same max length used in the product tame
Property(m => m.ProductName).HasMaxLength(400);
Property(m => m.IpAddress);
Property(m => m.CustomerId);
Property(m => m.IsRegistered);
کلاس بعدی پیچیده ترین و مهم ترین کلاس در لایه دسترسی به داده است. چارچوب Entity Framework Object Context یک کلاس عبور است که به ما دسترسی به پایگاه داده و کمک به ردیابی حالت نهاد (به عنوان مثال اضافه کردن، به روز رسانی، حذف) را می دهد. زمینه همچنین برای تولید طرح پایگاه داده یا به روز رسانی یک طرح موجود استفاده می شود. در کلاسهای زمینه سفارشی ما نمیتوانیم به ارگان های موجود ارجاع دهیم، زیرا این نوعها قبلا به زمینه شیء دیگری مرتبط هستند. به همین دلیل است که ما ویژگی های ناوبری پیچیده ای در رکورد ردیابی نداریم.
public class ProductViewTrackerRecordObjectContext : DbContext, IDbContext
public ProductViewTrackerRecordObjectContext(string nameOrConnectionString) : base(nameOrConnectionString) { }
#region Implementation of IDbContext
#endregion
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Configurations.Add(new ProductViewTrackerRecordMap());
base.OnModelCreating(modelBuilder);
public string CreateDatabaseScript()
return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript();
public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
return base.Set<TEntity>();
public void Install()
//create the table
var dbScript = CreateDatabaseScript();
Database.ExecuteSqlCommand(dbScript);
SaveChanges();
public void Uninstall()
//drop the table
var tableName = this.GetTableName<ProductViewTrackerRecord>();
//var tableName = "ProductViewTracking";
this.DropPluginTable(tableName);
public System.Collections.Generic.IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
throw new System.NotImplementedException();
public System.Collections.Generic.IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters)
public void Detach(object entity)
if (entity == null)
throw new ArgumentNullException(nameof(entity));
((IObjectContextAdapter)this).ObjectContext.Detach(entity);
public virtual bool ProxyCreationEnabled
get
return Configuration.ProxyCreationEnabled;
set
Configuration.ProxyCreationEnabled = value;
public virtual bool AutoDetectChangesEnabled
return Configuration.AutoDetectChangesEnabled;
Configuration.AutoDetectChangesEnabled = value;
لایه سرویس لایه دسترسی داده ها و لایه ارائه را متصل می کند. از آنجا که به اشتراک گذاشتن مسئولیت های مختلف در کد کاری غلط است، هر لایه باید جداگانه و ایزوله باشد. لایه سرویس لایه داده منطق تجاری را پوشش می دهد و لایه ارائه بستگی به لایه سرویس دارد. از آنجا که وظیفه تعریفی ما بسیار کوچک است، لایه سرویس ما هیچ ارتباطی با مخزن ندارد (مخزن در nopCommerce به عنوان نماینده به زمینه شیء عمل می کند).
namespace Nop.Plugin.Other.ProductViewTracker.Services
public interface IProductViewTrackerService
/// <summary>
/// Logs the specified record.
/// </summary>
/// <param name="record">The record.</param>
void Log(ProductViewTrackerRecord record);
public class ProductViewTrackerService : IProductViewTrackerService
private readonly IRepository<ProductViewTrackerRecord> _productViewTrackerRecordRepository;
public ViewTrackingService(IRepository<ProductViewTrackingRecord> productViewTrackerRecordRepository)
_productViewTrackerRecordRepository = productViewTrackerRecordRepository;
public void Log(ProductViewTrackerRecord record)
_productViewTrackerRecordRepository.Insert(record);
مارتین فاولر یک توصیف عالی از تزریق وابستگی یا انحراف از کنترل نوشته است. من قصد ندارم کار ایشان را تکرار کنم، و شما می توانید این مقاله را در اینجا پیدا کنید. تزریق وابستگی چرخه عمر اشیا را مدیریت می کند و نمونه هایی را برای اشیاء وابسته برای استفاده فراهم می کند. ابتدا باید کانتینر وابستگی ها را پیکربندی کنیم تا بدانیم که کدام اشیا را کنترل می کند و چه قوانینی ممکن است به ایجاد آن اشیا اعمال شود.
namespace Nop.Plugin.Other.ProductViewTracker.Infrastructure
public class DependencyRegistrar : IDependencyRegistrar
private const string CONTEXT_NAME = "nop_object_context_product_view_tracker";
public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
builder.RegisterType<ProductViewTrackerService>().As<IProductViewTrackerService>().InstancePerLifetimeScope();
//data context
this.RegisterPluginDataContext<ProductViewTrackerRecordObjectContext>(builder, CONTEXT_NAME);
//override required repository with our custom context
builder.RegisterType<EfRepository<ProductViewTrackerRecord>>()
.As<IRepository<ProductViewTrackerRecord>>()
.WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT_NAME))
.InstancePerLifetimeScope();
public int Order
get { return 1; }
در کد بالا ما انواع مختلفی از اشیا را ثبت می کنیم تا بعدا بتوان آنها را به کنترل کننده ها، سرویس ها و مخازن تزریق کرد. اکنون ما موضوعات جدید را پوشش می دهیم و بعضی از آن ها را دوباره مطرح می کنیم تا بتوانیم پلاگین را به اتمام برسانیم.
بیایید یک کامپوننت view ایجاد کنیم:
namespace Nop.Plugin.Other.ProductViewTracker.Components
[ViewComponent(Name = "ProductViewTracker")]
public class ProductViewTrackerViewComponent : NopViewComponent
private readonly IProductService _productService;
private readonly IProductViewTrackerService _productViewTrackerService;
private readonly IWorkContext _workContext;
public ProductViewTrackerViewComponent(IWorkContext workContext,
IProductViewTrackerService productViewTrackerService,
IProductService productService)
_workContext = workContext;
_productViewTrackerService = productViewTrackerService;
_productService = productService;
public IViewComponentResult Invoke(int productId)
//Read from the product service
roduct productById = _productService.GetProductById(productId);
//If the product exists we will log it
if (productById != null)
//Setup the product to save
var record = new ProductViewTrackerRecord();
record.ProductId = productId;
record.ProductName = productById.Name;
record.CustomerId = _workContext.CurrentCustomer.Id;
record.IpAddress = _workContext.CurrentCustomer.LastIpAddress;
record.IsRegistered = _workContext.CurrentCustomer.IsRegistered();
//Map the values we're interested in to our new entity
_productViewTrackerService.Log(record);
return Content("");
namespace Nop.Plugin.Other.ProductViewTracker
public class ProductViewTrackerPlugin : BasePlugin
private readonly ProductViewTrackerRecordObjectContext _context;
public ProductViewTrackerPlugin(ProductViewTrackerRecordObjectContext context)
_context = context;
public override void Install()
_context.Install();
base.Install();
public override void Uninstall()
_context.Uninstall();
base.Uninstall();
کد ردیابی باید به فایل ProductTemplate.Simple.cshtml و ProductTemplate.Grouped.cshtml اضافه شود. اینها قالب های محصول هستند.
@await Component.InvokeAsync("ProductViewTrackerIndex", new { productId = Model.Id })
پی نوشت شما همچنین می توانید آن را به عنوان یک ویجت پیاده سازی کنید. در این مورد شما نیازی به ویرایش یک فایل cshtml نخواهید داشت.
طراحی فروشگاه خود را با امکانات بیشمار و قالب اختصاصی به ما بسپارید. نمونه پروژه های اجرا شده ما را ببینید.
ناپ شاپ با برگزاری دوره های آموزشی در دانشگاهها، ارائه راهنمای فارسی، انجمن گفتگو، فیلم های آموشی، وبلاگ، طراحی انواع پلاگین ها و راه اندازی انواع فروشگاه اینترنتی، در توسعه ناپ کامرس در ایران تلاش میکند.