Friday 31 August 2018

Dynamic Attribute in Hybris


* We Use Dynamic Attributes to define attributes whose values are not persisted in a database.

Dynamic attribute has some key features:-
· The persistence type is set to dynamic
· The  attributeHandler points to a bean that must handle the DynamicAttributeHandler
 interface
· The write attribute is set to false, and therefore the attribute is read-only
UseCase:-
    Calculate age based on date of birth. Here Age attribute is not present in DB. But we can calculating using Dynamic attribute.

==============================================================

Step 1:-  Add the attributes date of birth and age to customer model in *core-items.xml.  

<itemtype code="Customer" autocreate="false" generate="false">
<attributes>
  <attribute type="java.util.Date" qualifier="dob">
    <persistence type="property"></persistence>
    <modifiers read="true" write="true" optional="true"/>
  </attribute>
 <attribute type="java.lang.Integer" qualifier="age">
  <persistence type="dynamic"   attributeHandler="dynamicAgeHandler"></persistence>
  <modifiers read="true" write="true" optional="true"/>
 </attribute>
 </attributes>
</itemtype>

Step 2:-
For dynamic attributes, we have the attributesHandler property which is to be set to the bean id of the class which is implementing DynamicAttributeHandler interface.

* we have to create a class 


package com.training.facades.attributehandler;


import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.servicelayer.model.attribute.DynamicAttributeHandler;

import java.util.Calendar;
import java.util.Date;


public class DynamicAgeHandler implements DynamicAttributeHandler<Integer, CustomerModel>

{

public static int age = 0;

@Override
public Integer get(final CustomerModel model)

{
try
{
System.out.println("***** Before date1 :");

final Date date = model.getDob();

System.out.println("************************" + date);

final Calendar cal = Calendar.getInstance();

cal.setTime(date);

final int year = cal.get(Calendar.YEAR);

System.out.println(year);

final int year1 = Calendar.getInstance().get(Calendar.YEAR);

System.out.println(year1);

age = year1 - year;

System.out.println("***** age :" + age);

}

catch (final Exception e)
{
e.printStackTrace();
}

return Integer.valueOf(age);

}

@Override
public void set(final CustomerModel model, final Integer val)

{
if (val != null)
{
throw new UnsupportedOperationException();
}
}

}






Step 3:-
In **facade-springs.xml create a bean  for above class

<bean id="dynamicAgeHandler" class="com.training.facades.attributehandler.DynamicAgeHandler"></bean>


Step 4:-

   For Registerdata add a new field in *facades-beans.xml

<bean class="de.hybris.platform.commercefacades.user.data.RegisterData">
 <property name="age" type="java.lang.String"/> 
 <property name="dob" type="java.util.Date"/> 
</bean>

Ant clean all to clean and build with newly added fields.

Step 5:-

 In register.tag  add fields for getting the value from and store into
  DB.
  ---------------------------------------------------------------
<formElement:formInputBox idKey="register.dob" labelKey="register.dob" path="dob" inputCSS="text" mandatory="true"/>

IN base-en.properties in storefront add a label for dob.

register.dob    = Date of Birth


Step 6:-

In RegisterForm.java add your own fields and write setter and getter
   methods.

  @DateTimeFormat(pattern = "dd/MM/yyyy")
private Date dob;
      public Date getDob()
{
return dob;
}

void setDob(final Date dob)
{
this.dob = dob;
}


Step 7:-

In LoginPageController.java add your own attribute by getting the  
  values from form and set into RegisterData object in
  processRegisterUserRequest() method.


@RequestMapping(value = "/register", method = RequestMethod.POST)
public String doRegister(@RequestHeader(value = "referer", required = false) final String referer, final RegisterForm form,
final BindingResult bindingResult, final Model model, final HttpServletRequest request,
final HttpServletResponse response, final RedirectAttributes redirectModel) throws CMSItemNotFoundException

{
     getRegistrationValidator().validate(form, bindingResult);
   return processRegisterUserRequest(referer, form, bindingResult, model, request, response,              redirectModel);
}

@Override
protected String processRegisterUserRequest(final String referer, final RegisterForm form, final BindingResult bindingResult,
final Model model, final HttpServletRequest request, final HttpServletResponse response,
final RedirectAttributes redirectModel) throws CMSItemNotFoundException
{

if (bindingResult.hasErrors())
{
  model.addAttribute(form);
  model.addAttribute(new LoginForm());
  model.addAttribute(new GuestForm());
  GlobalMessages.addErrorMessage(model, "form.global.error");
  return handleRegistrationError(model);
}

final RegisterData data = new RegisterData();
data.setFirstName(form.getFirstName());
data.setLastName(form.getLastName());
data.setLogin(form.getEmail());
data.setPassword(form.getPwd());
data.setTitleCode(form.getTitleCode());
data.setDob(form.getDob());
System.out.println("************** data is set" + form.getDob());
try
{
  getCustomerFacade().register(data);
  getAutoLoginStrategy().login(form.getEmail().toLowerCase(), form.getPwd(), request,                   response);

GlobalMessages.addFlashMessage(redirectModel, GlobalMessages.CONF_MESSAGES_HOLDER,
"registration.confirmation.message.title");
}
catch (final DuplicateUidException e)
{
LOG.warn("registration failed: " + e);
model.addAttribute(form);
model.addAttribute(new LoginForm());
model.addAttribute(new GuestForm());
bindingResult.rejectValue("email", "registration.error.account.exists.title");
GlobalMessages.addErrorMessage(model, "form.global.error");
return handleRegistrationError(model);
}

return REDIRECT_PREFIX + getSuccessRedirect(request, response);
}





Step 8:-
In DefaultCustomerFacade.javain register() method add your Attribute.

 newCustomer.setDob(registerData.getDob());

Step 9:-
To get the details of current user CustomerModel we create a class in facades

DynamicCusAge.java


package com.training.facade.impl;

import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.core.model.user.UserModel;
import de.hybris.platform.servicelayer.user.UserService;

import org.springframework.beans.factory.annotation.Autowired;


public class DynamicCusAge

{

@Autowired
private UserService userService;


public UserService getUserService()
{
return userService;
}

public void setUserService(final UserService userService)
{
this.userService = userService;
}

public Integer getAge()
{

final UserModel cus = getUserService().getCurrentUser();
final CustomerModel cus1 = (CustomerModel) cus;

final Integer age = cus1.getAge();

return age;

}
}


Step 10:-

In **facade-springs.xml create a bean id for above class


<bean id="dynamicCusAge" class="com.training.facade.impl.DynamicCusAge">
<property name="userService" ref="userService"/>

Step 11:-

Into the AccountPageController.java , in profile() method through    
   Your DynamicCusAge class call the method to get the age.


@Autowired
private DynamicCusAge dynamicCusAge;
....
.
.
....
@RequestMapping(value = "/profile", method = RequestMethod.GET)
@RequireHardLogIn
public String profile(final Model model) throws CMSItemNotFoundException
{
final List<TitleData> titles = userFacade.getTitles();

final CustomerData customerData = customerFacade.getCurrentCustomer();

if (customerData.getTitleCode() != null)
{
model.addAttribute("title", findTitleForCode(titles, customerData.getTitleCode()));
}


final Integer age = dynamicCusAge.getAge();
System.out.println("************ AGe:" + age);
model.addAttribute("age", age);
model.addAttribute("customerData", customerData);

storeCmsPageInModel(model, getContentPageForLabelOrId(PROFILE_CMS_PAGE));
setUpMetaDataForContentPage(model, getContentPageForLabelOrId(PROFILE_CMS_PAGE));
model.addAttribute("breadcrumbs", accountBreadcrumbBuilder.getBreadcrumbs("text.account.profile"));
model.addAttribute("metaRobots", "noindex,nofollow");
return getViewForPage(model);
}


Step 12:-
        In accountprofilepage.jsp

    <h2><u>Dynamic Attribute</u></h2>
<table>
<tr>
<td><spring:theme code="profile.firstName" text="First name"/>:
<b>${fn:escapeXml(customerData.firstName)}</b></td>
</tr>
<tr>
<td><spring:theme code="profile.lastName" text="Last name"/> :
<b>${fn:escapeXml(customerData.lastName)}</b></td>
</tr>
 <tr>
<td><spring:theme code="profile.age" text="Age"/> :
<b>${age} years</b></td>
</tr>
</table>


Step 13:-

       We have to create the PageTemplate,ContentPage,contentslot,JspIncludeComponent through impex.

INSERT_UPDATE PageTemplate;$contentCV[unique=true];uid[unique=true];name;frontendTemplateName;restrictedPageTypes(code);active[default=true]

  ;;AccountPageTemplate;Account Page Template;account/accountLayoutPage;ContentPage

 INSERT_UPDATE ContentPage;$contentCV[unique=true];uid[unique=true];name;masterTemplate(uid,$contentCV);label;defaultPage[default='true'];approvalStatus(code)[default='approved'];homepage[default='false']

;;ProfileContentPage;profile Content Page;AccountPageTemplate;profile

 INSERT_UPDATE JspIncludeComponent;$contentCV[unique=true];uid[unique=true];name;page;actions(uid,$contentCV);&componentRef

;;ProfilePageComponent;Profile Page Component;accountProfilePage.jsp;;ProfilePageComponent
  

INSERT_UPDATE ContentSlot;$contentCV[unique=true];uid[unique=true];name;active;cmsComponents(&componentRef);;;

;;ProfilePageComponentCOntentSlot;Profile Page Component ContentSlot;true;ProfilePageComponent;;;

  
INSERT_UPDATE ContentSlotForPage;$contentCV[unique=true];uid[unique=true];position[unique=true];page(uid,$contentCV)[unique=true][default='ProfileContentPage'];contentSlot(uid,$contentCV)[unique=true];;;

;;ProfilePageComponentCOntentSlotPage;profile;;ProfilePageComponentCOntentSlot;;;





Step 13:-
     add below code in this file AccountLayoutPage.jsp.

 <div class="account-section">
    <cms:pageSlot position="profile" var="feature" element="div" class="account-section-content">
                <cms:component component="${feature}" />
      </cms:pageSlot>
   </div>


Note:
=> Position profile’ must be same in ContentSlotForPage and AccountLayoutPage.jsp
 =>Try by adding full path of jsp in JspIncludeComponent.

These are the URL's to access the electronic site with our storefront.