Hello Everyone,
In today's blog, I am going to explain the third step that would complete the data exchange between Sitecore XP and XC.
Objective: Create a SXA component for our storefront that would consume the rest service endpoint that has been created in commerce engine (Part 1). For creating a SXA component, we need following things:
Basic building blocks of a SXA component:
1. Controller: It provides useful properties and logic to automatically resolve the view name and provide the model.
2. Model : A class that defines the properties to be used by a controller.
3. View : A view is used to display data using the model class object.
If you have used MVC design pattern, you are already familiar with above blocks. Let's talk about the rest 2 that are used by SXA.
4. Repository: SXA uses repositories to provide model for the MVC views. So we must inject the repository into the controller to access the model.
5. Configurator: We need to register the repository into the DI (Dependency Injection) container. We can do this by either using a config file or by defining a class that extends IServicesConfigurator.
For this exercise, I am going to create one more class:
6. Manager: This class is going to access the Sitecore Commerce Engine container and fetch the products.
Let's say we have to build a page in our storefront as shown in below image:
If you have read Part 1 and Part 2, you would understand the data structure of a product and the ways in which this small exercise could be helpful for a big task.
Let's Code this:
Manager Interface and Class: Let's start by creating a manager class that would interact with the end point in commerce and get results.
IProductInformationManager.cs
public interface IProductInformationManager
{
ManagerResponse<GetProductInformationResult, ProductsList> GetProductInformation(
string CommonProductID,
IStorefrontContext storefrontContext, IVisitorContext visitorContext);
}
As seen below, we are providing the CommonProductID as the payload of our request.
ProductInformationManager.cs
public virtual ManagerResponse<GetProductInformationResult, ProductsList> GetProductInformation(
string CommonProductID,
IStorefrontContext storefrontContext, IVisitorContext visitorContext)
{
GetProductInformationResult serviceResult = new GetProductInformationResult();
ProductsList productDataResult = null;
try
{
//get the Sitecore XC engine container
var container = EngineConnectUtility.GetShopsContainer(shopName: storefrontContext.CurrentStorefront.ControlPanel.Name, customerId: visitorContext.CustomerId);
var response = Proxy.DoCommand(container.GetProductInformation(CommonProductID));
if (response != null)
{
if (response.Models.Count > 0)
{
var productsModel = response.Models.OfType<ProductsList>().FirstOrDefault<ProductsList>();
if (productsModel != null)
{
productDataResult = productsModel;
serviceResult.ProductInformation = productsModel;
serviceResult.Success = true;
}
}
}
}
catch (Exception ex)
{
//catching & logging exceptions
Log.Error(ex.Message, this);
}
return new ManagerResponse<GetProductInformationResult, ProductsList>(serviceResult, productDataResult);
}
2. Model: Model classes used in this blog are the one's created in the commerce engine(Part 1). As per the requirement you can create additional models if required.
3. Repository: It gets the response from the manager and sets the model(ProductsList) to inject into the controller.
IProductsRepository.cs
public interface IProductsRepository : IModelRepository
{
ProductsList GetProductInformationModel(
IStorefrontContext storefrontContext, IVisitorContext visitorContext);
}
public class ProductsRepository : ModelRepository, IProductsRepository
{
private readonly Managers.IGetProductInformationManager _getProductInformationManager;
private readonly IModelProvider _modelProvider;
public ProductsRepository(
IGetProductInformationManager getProductInformationManager,
IModelProvider modelProvider) : base()
{
Assert.ArgumentNotNull(modelProvider, nameof(modelProvider));
this._getProductInformationManager = getProductInformationManager;
_modelProvider = modelProvider;
}
/// <param name="storefrontContext"></param>
/// <param name="visitorContext"></param>
/// <returns></returns>
public ProductsList GetProductInformationModel(IStorefrontContext storefrontContext, IVisitorContext visitorContext)
{
ProductsList model = new ProductsList();
string commonProductID = GetCommonProductID();
ManagerResponse<GetProductsInformationResult, ProductsList> result = this._getProductInformationManager.GetProductInformation(commonProductID,
storefrontContext, visitorContext);
if (result.ServiceProviderResult.Success)
{
model = result.Result;
}
return model;
}
/// <summary>
/// Create a product temaplte.
/// Get the common product id.
/// </summary>
/// <returns></returns>
private string GetCommonProductID()
{
return PageContext.Current.Parent.Fields[Templates.Products.Fields.CommonProductID].Value;
}
}
}
4. Controller: Gets products information and returns to the view.
public class ProductsController : BaseCommerceStandardController
{
private IProductsRepository _productsRepository;
private IVisitorContext _visitorContext;
private IModelProvider _modelProvider;
public ProductsController(
IProductsRepository productsRepository,
IVisitorContext visitorContext,
IStorefrontContext storefrontContext,
IModelProvider modelProvider,
IContext iContext) :
base(storefrontContext, iContext)
{
_productsRepository = productsRepository;
_visitorContext = visitorContext;
_modelProvider = modelProvider;
}
/// <summary>
/// Gets products information and returns to the view.
/// </summary>
/// <returns></returns>
public ActionResult GetProductInformation()
{
return View("GetProductInformation", _productsRepository.GetProductInformationModel(StorefrontContext, _visitorContext));
}
}
5. Views: Just providing here a sample of the view.
@model Plugin.Example.Products.Models.ProductsList
<div>
<div class="wrapper">
<div class="row">
<div class="col-8">
@Model.BaseLevelProduct.ProductName
@Model.BaseLevelProduct.ProductDescription
</div>
</div>
@foreach (var item in Model.FirstLevelProducts)
{
<div class="row">
<div class="col-8">
@item.ProductName
@item.ProductDescription
</div>
</div>
}
@foreach (var item1 in Model.SecondLevelProducts)
{
<div class="row">
<div class="col-8">
@item1.ProductName
@item1.ProductDescription
</div>
</div>
}
</div>
</div>
Hope this blog helps. Thank you!
Comentarios