In addition to the keyword and text search of the simple search functionality, the advanced search functionality allows the customer to search for products by part number and manufacturer, which are defined as product properties. Advanced search is divided into two types of search, part number search and searching by using manufacturer and category.
Part Number Searching
Since part number is not a property of Product
items but instead a property of sku
items, we use a different component, atg/projects/b2bstore/catalog/PartNumberSearchFormHandler
, to search for part numbers. This component uses a custom form handler, CatalogSearchFormHandler
, and uses different properties than AdvProductSearch
.
This is the properties file for catalogSearchFormHandler
:
# Allow users to search by part number # Part number exists on a sku $class=atg.commerce.catalog.custom.CatalogSearchFormHandler $scope=request catalogTools=/atg/commerce/catalog/CatalogTools doTextSearch=true textSearchPropertyNames=manufacturer_part_number itemTypes=sku repositories=/atg/commerce/catalog/ProductCatalog
The following is the code for Part Number searching in part_number_search.jsp
.
<dsp:form action="part_number_search.jsp" method="POST"> <table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="#FFCC66"> <tr><td colspan=2><dsp:img src= "../images/d.gif" height="10"/></td></tr> <tr valign="top"> <td width="15%" align="right"> <span class="smallb">Part#</span> </td> <td> <dsp:input bean="PartNumberSearchFormHandler.searchInput" size="25" type="text"/> <br> <span class="small">Use <b>*</b> for partial part number search.</span> </td> </tr> <tr> <td> </td> <td> <input name="repositoryKey" type="hidden" value="<dsp:valueof bean="/OriginatingRequest.requestLocale.locale"/>"> <input name="noCrumbs" type="hidden" value="<dsp:valueof param="noCrumbs"/>"><br> <dsp:input bean="PartNumberSearchFormHandler.search" type="hidden" value="Search"/> <dsp:input bean="PartNumberSearchFormHandler.search" type="submit" value="Search"/> </dsp:form></td>
The SearchInput
property of PartNumberSearchFormHandler
component is set using the part number input from user. Based on this manufacturer_part_number
property of SKU is searched.
part_number_search.jsp
invokes the PartNumberSearchResults.jsp
fragment passing the result of the search that contains the array of SKUs of the products found. The following is the code fragment in part_number_search.jsp
to include this:
<dsp:getvalueof id="pval0" idtype="java.util.List" bean="PartNumberSearchFormHandler.searchResults"> <dsp:include page="PartNumberSearchResults.jsp" flush="true"> <dsp:param name="Skus" value="<%=pval0%>"/> </dsp:include> </dsp:getvalueof>
Once we get SKUs with the given part number, we fetch products corresponding to those SKUs in PartNumberSearchResults.jsp
. We iterate through each SKU and get all the products corresponding to SKU using RQLQueryForEach
and display them.
The following is a snippet from PartNumberSearchResults.jsp
that display the products found:
<dsp:droplet name="ForEach"> <dsp:param name="array" param="Skus"/> <dsp:param name="elementName" value="element"/> <dsp:oparam name="outputStart"> <b>We found these products matching your search</b> <br><br> </dsp:oparam> <dsp:oparam name="output"> <dsp:droplet name="RQLQueryForEach"> <dsp:param name="skuId" param="element"/> <dsp:param name="repository" bean="/atg/commerce/catalog/ProductCatalog" /> <dsp:param name="itemDescriptor" value="product"/> <dsp:param name="queryRQL" value="childSKUs INCLUDES :skuId "/> <dsp:param bean="/atg/dynamo/transaction/TransactionManager" name="transactionManager"/> <dsp:oparam name="output"> <%-- Display a link to the element: --%> <dsp:getvalueof id="urlStr" idtype="java.lang.String" param="element.template.url"> <dsp:a page="<%=urlStr%>"> <dsp:param name="id" param="element.repositoryId"/> <dsp:param name="navAction" value="jump"/> <dsp:param name="Item" param="element"/> <dsp:valueof param="element.displayName">No name</dsp:valueof> - <dsp:valueof param="element.description"/> </dsp:a> </dsp:getvalueof> <br> </dsp:oparam> </dsp:droplet> </dsp:oparam> <dsp:oparam name="empty"> <b>There are no products matching your search</b> <p> </dsp:oparam> </dsp:droplet>
Manufacturer and Text Input Search
The AdvProductSearch
component is used for this search.
The advanced search functionality uses the SearchFormHandler
but requires a slightly more complex properties file than the simple search Nucleus component. Advanced searches return only products because the additional search criteria are based on products only.
/atg/commerce/catalog/AdvProductSearch.properties
$class=atg.commerce.catalog.SearchFormHandler $scope=session doKeywordSearch=true keywordsPropertyNames=keywords doTextSearch=true textSearchPropertyNames=description,displayName doAdvancedSearch=true advancedSearchPropertyNames=childSKUs doHierarchicalSearch=true ancestorCategoriesPropertyName=ancestorCategories minScore=1 catalogTools=CatalogTools itemTypes^=CatalogTools.productItemTypes maxResultsPerPage=20 enableCountQuery=true
At the Motorprise configuration layer, we added a manufacturer property to this component:
# /atg/commerce/catalog/AdvProductSearch
advancedSearchPropertyNames+=manufacturer
As with the simple search, the SearchFormHandler
is session scoped. Keyword and text searching are configured identically for both simple and advanced searches and they both use the same catalog. For the enumerated types used in the search (manufacturer), the possible values are inserted into <select>
input tags on the form. These values are not coded into the form, but instead are retrieved from the catalog via the propertyValuesByType
property of the SearchFormHandler
.
The propertyValuesByType
property is a map with property names for keys and arrays of all possible values for the given property. By default, no enumerated property information is available from the propertyValuesByType
property of the SearchFormHandler
. Instead, you must explicitly set the names of required enumerated properties in the search component’s advancedSearchPropertyNames
property. In this case, the value is manufacturer
.
Thus, when a search is performed in Motorprise the propertyValuesByType
map returns two entries. One entry corresponds to the category
item-type and the other entry corresponds to the product
item-type. This is because these are the two item-descriptor types that are searched on in the ProductCatalog
repository. Associated with the category entry will be a list of category repository items that were found in the search; similarly the product key will contain a list of product repository items.
By having the list of repository items split up by type, we are able to control how a repository item is displayed. For example, when a matching product repository item gets displayed, we want to link to product.jsp
; for categories we want to link to category.jsp
. That is why in the simple_search.jsp
example shown above, there is a switch statement on the key property of the propertyValuesByType
array.
The search form’s categories in the advanced search, manufacturer, is populated with valid choices for each item. These choices (<select>
components) are loaded from the repository rather than coded into the page so that the page need not be changed when changes are made to the repository.
To display the list of all categories, we used the RepositoryValues
servlet bean. It takes the input parameter itemDescriptorName
that in this case is set to category because that is the type of repository item that we want to list. The servlet bean outputs an array of repository items that can be rendered using the ForEach
component.
The following is part of the code for category search in advanced_search.jsp
:
<!--search box starts here--> <table width=100% bgcolor="#FFCC66" border=0 cellpadding=0 cellspacing=0> <tr bgcolor="#666666"> <td bgcolor="#666666" width=1><dsp:img src="../images/d.gif" width="1"/></td> <td colspan=2> <table cellpadding=3 cellspacing=0 border=0> <tr><td class=box-top> Advanced Product Search</td></tr> </table> </td> </tr> <tr> <td bgcolor="#666666" width=1><dsp:img src="../images/d.gif" width="1"/></td> <td> <table width=100% bgcolor="#FFCC66" border=0 cellpadding=0 cellspacing=0> <tr valign=top> <td width=50%> <dsp:form action="advanced_search.jsp" method="POST"> <table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="#FFCC66"> <tr><td colspan=2><dsp:img src= "../images/d.gif" height="10"/></td></tr> <tr valign=top> <td width="15%" align="right"><span class= "smallb">Text</span></td> <td><dsp:input bean="AdvProductSearch.searchInput" size="25" type="text"/> <br> <span class="small">Use <b>AND</b> or <b>OR</b> to separate words or phrases.</span> </td> </tr> <tr> <td align="right"><span class=smallb>Category</span></td> <td> <dsp:select bean="AdvProductSearch.hierarchicalCategoryId"> <dsp:option value=""/>-- All categories -- <dsp:droplet name="RepositoryValues"> <dsp:param name="itemDescriptorName" value="category"/> <dsp:oparam name="output"> <dsp:droplet name="ForEach"> <dsp:param name="array" param="values"/> <dsp:param name="sortProperties" value="+displayName"/> <dsp:oparam name="output"> <dsp:getvalueof id="elem" idtype="atg.repository.RepositoryItem" param="element"> <dsp:option value="<%=elem.getRepositoryId()%>"/> <dsp:valueof param="element.displayName"/> </dsp:getvalueof> </dsp:oparam> </dsp:droplet> </dsp:oparam> </dsp:droplet> </dsp:select> </td> </tr> <tr> <td align="right"> <span class= smallb>Manufacturer</span></td> <td> <dsp:select bean="AdvProductSearch.propertyValues.manufacturer"> <dsp:option value=""/>-- Any -- <dsp:droplet name="RepositoryValues"> <dsp:param name="itemDescriptorName" value="product"/> <dsp:param name="propertyName" value="manufacturer"/> <dsp:oparam name="output"> <dsp:droplet name="ForEach"> <dsp:param name="array" param="values"/> <dsp:param name="sortProperties" value="+displayName"/> <dsp:oparam name="output"> <dsp:getvalueof id="elemName" idtype="java.lang.String" param="element.displayName"> <dsp:option value="<%=elemName%>"/> <dsp:valueof param="element.displayName"/> </dsp:getvalueof> </dsp:oparam> </dsp:droplet> </dsp:oparam> </dsp:droplet> </dsp:select> </td> </tr> <tr> <td> </td> <td><br> <dsp:input bean="AdvProductSearch.currentResultPageNum" type="hidden" value="1"/> <input name="repositoryKey" type="hidden" value="<dsp:valueof bean="/OriginatingRequest.requestLocale.locale"/>"> <input name="noCrumbs" type="hidden" value="<dsp:valueof param="noCrumbs"/>"> <dsp:input bean="AdvProductSearch.search" type="hidden" value="Search"/> <dsp:input bean="AdvProductSearch.search" type="submit" value="Search"/> </td> </tr> <tr> <td colspan=2> </td> </tr> <tr> <td> </td> <td><span class=smallb><dsp:a href="simple_search.jsp"> <dsp:param name="noCrumbs" param="noCrumbs"/> Use simple search form</dsp:a></span> </td> </tr>