One of the most common needs in terms of customizing SoftSlate Commerce is to extend the application's business objects to include additional data beyond what's supported by default. For example, in the case of a bookstore, you may need to store additional fields like subtitle, author, and publisher with your products. In other cases, for customers, you may need to track how they first found out about your store or other idiosyncratic fields.
Fortunately, SoftSlate Commerce provides three ways to extend its built-in objects. As you will see, each of the methods has its advantages and disadvantages. We hope that the first two methods are fairly self-explanatory: they require minimal or no custom programming to use. For the last method, we'll go through a detailed example.
A number of the database tables feature 'Extra' fields named
extra1
, extra2
,
extra3
, etc. These fields are intended to store any custom, generic
data not supported by the built-in fields. To use the various 'Extra' fields, simply
populate them in the database, or by using the Administrator as you add and edit your
objects.
Supported Objects.
sscCategory
sscCustomer
sscCustomerAddress
sscDiscount
sscOrder
sscOrderDelivery
sscOrderDiscount
sscOrderItem
sscProduct
sscSKU
Advantages.
sscProduct.extra1
->
sscOrderItem.extra1
) with each order, so they
can be used during order processing in addition to being displayed in
the product catalog.Disadvantages.
The two objects that most commonly need to be extended are categories and products. For
these objects, you have the option to define custom settings, which are stored for each
product and category respectively in the sscProductSetting
and
sscCategorySetting
tables.
Supported Objects.
sscCategorySetting
sscProductSetting
Advantages.
Products -> Products -> Details -> Custom
Settings
)Products -> Categories ->
Details -> Custom Settings
, is available for
categories.Disadvantages.
To populate sscProductSetting
and
sscCategorySetting
with custom data related to products and
categories, the easiest way may be to use the Administrator's interface. For products,
this interface is found by navigating to Products -> Products -> Details ->
Custom Settings
.
On this screen, you find the following text input fields:
Custom
you can display it by placing this tag in a custom
product.jsp
template: <c:out
value="${productSettings.Custom.value}"/>
sscProductSetting
is used to
store the value.)The method is both the most flexible and powerful, and also the one that takes the most work.
Supported Objects.
Advantages.
sscProduct.newField
->
sscOrderItem.newField
.) Disadvantages.
Let's go through an example of adding a field to a database table. In this example, we'll
imagine we are running a bookstore, and that we've decided to add a field to
sscProduct
to store each book's author.
Example 17.1. Extending the Product Object by Adding a Field to
sscProduct
Create a new class that extends the built in
com.softslate.commerce.businessobjects.product.ProductBean
class. To keep things clean, we strongly recommend you place all your custom
classes in a separate Java package. We'll call our class
CustomProduct
and we'll put it in a new package
named com.softslate.commerce.demo
. Here's
the source code for our new class:
package com.softslate.commerce.demo; import com.softslate.commerce.businessobjects.product.ProductBean; public class CustomProduct extends ProductBean { private static final long serialVersionUID = 6874908321131548936L; String author = null; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
Note that we are extending the built-in
com.softslate.commerce.businessobjects.product.ProductBean
class. Strictly speaking, you don't have to extend the built-in class, but
you must implement the
com.softslate.commerce.businessobjects.product.Product
interface.
Create the Hibernate mapping file for the new class. The Hibernate
mapping file tells Hibernate how to map a class' properties to the columns of
the database table it corresponds to. Make a copy of the
ProductBean.hbm.xml
file, place it next to the new
CustomProduct.class
file, rename it
CustomProduct.hbm.xml
, and replace the existing
<subclass> tag with the following:
<subclass name="com.softslate.commerce.demo.CustomProduct"> <property name="author" length="255"/> </subclass>
If you are adding more than one property to your extended class,
include all of them inside the <subclass>
tag.
To ensure that your new class is used when Hibernate loads it lazily,
add the lazy="false"
attribute to the opening
<class>
tag:
<class name="com.softslate.commerce.businessobjects.product.Product" table="Product" lazy="false">
Now add the new column to the product database table:
ALTER TABLE sscProduct ADD author VARCHAR(255);
Update the product database table's class
field to use the new custom class. This tells Hibernate to instantiate
instances of the new class when loading data from the database:
UPDATE sscProduct SET class = 'com.softslate.commerce.demo.CustomProduct';
In the
/WEB-INF/classes/appComponents.properties
file, update the value of the productImplementer
property with the fully-qualified classname of our new custom class:
productImplementer = com.softslate.commerce.demo.CustomProduct
This tells the application to load the
CustomProduct.hbm.xml
file as part of the
Hibernate initialization process.
To display our new author field, first put some data into the new column of the database:
UPDATE sscProduct SET author = 'Truman Capote' WHERE productID = 1;
Then, create a custom version of the
product.jsp
JSP template in the
/WEB-INF/layouts/custom/product
directory.
Paste some JSP code into the custom template that displays the value of the
new field if it is defined:
<c:if test="${!empty product.author}"> <tr> <td class="productLabel" valign="top" nowrap="nowrap"> Author: </td> <td class="productData" valign="top"> <bean:write name="product" property="author"/> </td> </tr> </c:if>
After extending the product object to add new properties, you may need to make them accessible in the Administrator so they can be viewed and edited there. The following example takes us through the steps required to add a new field to the Administrator interface.
Example 17.2. Adding a New Product Field to the Administrator Screens
Create a new class that extends the built in
com.softslate.commerce.administrator.product.ProductForm
class. This will handle the processing and display
of the the control screen in the
administrator. We'll
call our class
CustomProductForm
and
we'll put it in a package named
com.softslate.commerce.demo
. Here's the source code for our new
CustomProductForm
class:
package com.softslate.commerce.demo; import java.util.Arrays; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import com.softslate.commerce.administrator.product.ProductForm; /** * Adding author field * * @author David Tobey */ public class CustomProductForm extends ProductForm { private static final long serialVersionUID = 1571534730516598703L; static Log log = LogFactory.getLog(CustomProductForm.class); // Add the new field to the list of fields private String[] fields = { "productID", "code", "name", "keywords", "shortDescription", "description", "isActive", "unitCost", "unitPrice", "altPrice", "weight", "header", "footer", "isTaxed", "smallImage", "mediumImage", "largeImage", "extra1", "extra2", "extra3", "extra4", "extra5", "primaryCategoryID", "manufacturerID", "productOrder", "author" }; // Add a human readable label for it private String[] fieldLables = { "Product ID", "Code", "Name", "Keywords", "Short Desc", "Description", "Active", "Cost", "Price", "Alt Price", "Weight", "Header", "Footer", "Taxed", "Small Image", "Medium Image", "Large Image", "Extra 1", "Extra 2", "Extra 3", "Extra 4", "Extra 5", "Pri Category", "Manufacturer", "Order", "Author" }; // Should it be displayed on the control screen by default? Yes. private String[] displayFields = { "code", "name", "isActive", "unitPrice", "productOrder", "author" }; private String[] searchableFields = { "code", "name", "keywords", "shortDescription", "extra1", "extra2", "extra3", "extra4", "extra5", "author" }; // Need a property for the control screen's edit mode - a String[] private String[] author = null; public String[] getAuthor() { return author; } public void setAuthor(String[] author) { this.author = author; } public String[] getDisplayFields() { return displayFields; } public void setDisplayFields(String[] displayFields) { this.displayFields = displayFields; } public String[] getFieldLables() { return fieldLables; } public void setFieldLables(String[] fieldLables) { this.fieldLables = fieldLables; } public String[] getFields() { return fields; } public void setFields(String[] fields) { this.fields = fields; } public String[] getSearchableFields() { return searchableFields; } public void setSearchableFields(String[] searchableFields) { this.searchableFields = searchableFields; } // Let's say we must have an author - so let's add it to the validation public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { if (log.isDebugEnabled()) log.debug("Starting validation."); setProperties(); // Run the original validations ActionErrors errors = super.validate(mapping, request); if (getProductID() != null) { for (int i = 0; i < getProductID().length; i++) { if (Arrays.asList(getDisplayFields()).contains("code")) { if (getAuthor().length < i + 1 || getAuthor()[i] == null || getAuthor()[i].equals("")) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.required", "Author")); } } } } return errors; } }
Similarly, create a new class that extends the
built in
com.softslate.commerce.administrator.product.ProductAddEditForm
class. This will handle the processing and display
of the the product detail screen in the
administrator. We'll call our class
CustomProductAddEditForm
. Here's the source code for this class:
package com.softslate.commerce.demo; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import com.softslate.commerce.administrator.product.ProductAddEditForm; /** * Adding author property * * @author David Tobey * */ public class CustomProductAddEditForm extends ProductAddEditForm { private static final long serialVersionUID = 4589930821507654940L; static Log log = LogFactory.getLog(CustomProductAddEditForm.class); private String author = null; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { if (log.isDebugEnabled()) log.debug("Starting validation."); initializeProperties(mapping, request); super.validate(mapping, request); if (getCode() == null || getCode().equals("")) { getErrors().add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.required", "Author")); } return getErrors(); } }
Now let's tell Struts to use our new form
classes instead of the defaults. Add the following
Action Form definitions to the <form-beans>
section of
/WEB-INF/conf/administrator/core/struts-config-custom.xml
:
<!-- Adding an author field to the product admin screens --> <form-bean name="productAddEditForm" type="com.softslate.commerce.demo.CustomProductAddEditForm"> </form-bean> <form-bean name="productForm" type="com.softslate.commerce.demo.CustomProductForm"> </form-bean>
Next is to add the HTML form elements for the new field to our JSP templates.
Let's start with the product detail screen. The JSP template responsible for it is
/WEB-INF/templates/administrator/default/product/productFormGuts.jsp
.
We want to create a custom version of that file, so create a new file of the same name in the
custom
directory: /WEB-INF/templates/administrator/custom/product/productFormGuts.jsp
In our custom version of productFormGuts.jsp
, place the following content to display a text box for the new author field. Note we'll include the original JSP file to avoid duplication:
<%@ include file="/WEB-INF/layouts/default/core/tagDefinitions.jsp" %> <!-- Start custom productFormGuts.jsp --> <tr> <td class="genericLabel">Author:</td> <td> <html:text maxlength="100" name="productAddEditForm" property="author"/> </td> </tr> <tr> <td> </td> <td class="genericData"> Enter the author of this book. <br /> <br /> </td> </tr> <jsp:include page="/WEB-INF/templates/administrator/default/product/productFormGuts.jsp"/> <!-- End custom productFormGuts.jsp -->
Next is the control screen for products. The JSP template responsible for displaying the product fields on that screen is
/WEB-INF/templates/administrator/default/product/productFieldColumns.jsp
.
We want to use the same file, but just add some new logic for the author field. So let's place a copy of productFieldColumns.jsp
in the custom
directory: /WEB-INF/templates/administrator/custom/product/productFieldColumns.jsp
In our copy of productFieldColumns.jsp
, add the following lines in the appropriate spots in that file to display the new author field, both when "edit mode" is on and when it is off. (Some analysis of the JSP tags is necessary here!)
When edit mode is on:
<logic:equal name="field" value="author"> <input type="text" size="15" maxlength="100" name="<bean:write name="field"/>" value="<bean:write name="item" property="<%= field %>"/>" class="genericGridData"/> </logic:equal>
When edit mode is off:
<logic:equal name="field" value="partNumber"> <bean:write name="item" property="<%= field %>"/> </logic:equal>
Copyright © 2008 SoftSlate, LLC. All Rights Reserved.
Powered by SoftSlate Commerce