| West Wind Web Store |
| The Web Store Home Page |
DO WEBSTOREMAIN
in VFP and then navigate your browser to:
http://localhost/wwstore/default.wws
The home page of the Web store will pop up at this time:
The default page is the entry point to the Web store and it demonstrates a number of the features that are common to all pages that drive the store. Note that users can enter the store any way they choose - you don't have to go through the default page, so users can directly go to the item or itemlist pages for example which is useful if you link to product information from within your site.
First remember the flow of how requests fire in the Web Connection server:
Since this is our first request let's look at how code gets to the default() method. The code starts out in the wwStore::Process method which sets up or attaches to a Session object.
*********************************************************************
* Function wwStore :: Process
************************************
*** If you need to hook up generic functionality that occurs on
*** every hit, implement this method then call DoDefault() to
*** get the default Request Processing functionality. See docs
*** for more info on how to customize wwProcess::Process behavior.
*********************************************************************
FUNCTION Process
PRIVATE Request, Response, Config
Request = THIS.oRequest
Response = THIS.oResponse
Response.cStyleSheet = "/wwstore/wwstore.css"
Config = THIS.oServer.oConfig.owwStore
THIS.InitSession(Config.cCookiename,3600,.t.)
*** Support XML retrieval of data on select request
THIS.nResultMode = IIF(Request.QueryString("Display") = "XML",2,0)
DODEFAULT()
RETURN .T.
ENDFUNC
Notice that the Config object is set up here as a PRIVATE variable to make it available through the entire wwStore class and all of its methods. The only two things that happen in this method is setting up the Web Connection Session object (this is how we track our users and manage our profiles) and checking for an XML request.
The Session is set up with a permanent Cookie using the name specified in the configuration file with the CookieName key. InitSession creates a new session if the Cookie doesn't exist yet, or else simply attaches to an existing session. The Session will be accessible with the Session PRIVATE variable. We'll put the Session object to good use in the the Default method.
Notice that the home page remembers if you were there before: it remembered that my fist name is Rick. This code is handled by the Default method when it tries to reattach to my user profile using the cCustomer object to match the user's Cookie to the UserId field store in the customer table. This is done using the business object's FindByUserId() method.
************************************************************************
* wwStore :: Default
*********************************
*** Function: The store's homepage. Not much happening here other than
*** trying to reattach to the customer's profile.
*** The template page performs banner operations and
*** displaying the category listing using the GetBanner and
*** CategoryList methods of this class.
************************************************************************
FUNCTION Default
PRIVATE pcWelcome
LOCAL oCustomer
oCustomer = CREATE([WWS_CLASS_CUSTOMER])
#IF WWSTORE_USE_SQL_TABLES
oCustomer.SetSQLObject(Server.owwStoreSQL)
#ENDIF
*** See if we can reattach to our profile/customer
IF oCustomer.FindByUserID(Session.cSessionId)
Session.SetSessionVar("CustomerPK",TRANS(oCustomer.oData.pk))
pcWelcome = "<b>Welcome back, " + TRIM(oCustomer.oData.FirstName) + ".</b><p>"
*** Preset Foreign or US/Can status in session for shopping cart
IF !INLIST(oCustomer.oData.CountryId,"US","CA")
Session.SetSessionVar("Foreign","True")
ENDIF
ELSE
pcWelcome = ""
Session.TimeoutSessions()
ENDIF
Session.SetSessionVar("CookiesOn","True")
Response.ExpandTemplate( Config.cHTMLPagePath + "default.wws" )
RETURN
ENDFUNC
This method introduces you to our first business object: cCustomer which represents our customers/user profile records for each visitor of the site. The permanent cookie we create with the session is mapped to the UserID field of the wws_customers table and the FindByUserId() method retrieves the customer record for it if he exists. If found, we store the customer's PK into the session for later retrieval. We also check to see if the customer is a foreign customer so the shopping cart can pre-set shipping options on the shopping cart page. If the user doesn't exist yet, we do nothing: We're not going to get a filled object back, but rather just a blank object.
Remember that the home page displayed my name when it remembered me? Well, here's how it's done: We read the customer business object and retrieve the name from there. We then build a string called pcWelcome and that will be embedded into the HTML template called in the ExpandTemplate() method call at the end of the method. The string is set to blank if no match was found.
The ExpandTemplate call accesses the default.wws page which was generated in MS FrontPage:
This page happens to be fairly static. All of the content in the main area of this form containing the items is actually hand typed. It's easy enough to automate but a homepage tends to be the most important part of any store and it's important it looks just right and hand designing will provide this more accurately than a generated list.
Compare the FrontPage document to the actual HTML in the first figure. You'll notice that the toolbar at the top and the left sidebar menu are missing from this FrontPage view. The reason for this is that these two components are dynamically loaded into the page, since the header and sidebar are used on all of the store's pages. This allows customization of these pages individually in one place and be reflected in the entire store.
If you look at the top of Default.wws you'll find the following code:
<!-- Start Header --> <%= CacheFile( Config.cHtmlPagePath + "Header.wws",0 ) %> <!-- End Header --> <table border="0" cellspacing="0" cellpadding="0" class="body" height="100%" width="812"> <tr> <td valign="top" align="right" width="180" background="images/newwave.jpg"> <!-- Start SideBar --> <%= CacheFile( Config.cHtmlPagePath + "LeftSideBar.wws",0 ) %> <!-- End Sidebar --></p> </td> <td width="22" bgcolor="white" align="left" valign="top"> </td> <!-- Custom Form Stuff --> <td valign="top" bgcolor="#FFFFFF" class="body" width="614"> ... the main body HTML will start here
These two ASP-Style expressions are found in every one of the Web Store template (.wws) pages and load the header (header.wws) and sidebar (LeftSideBar.wws). The CacheFile function is used to cache these files so that they don't have to be read from disk everytime and instead are loaded from a cursor that caches the content which is faster.
Notice the LeftSideBar.wws is loaded into the midst of a table. This is done so that the actual page you view (default.wws in this case) looks to a degree like what you will see in the browser in FrontPage, so you have a working idea of the layout. Leftsidebar.wws, contains a mixture of static code (the Shopping table on top) and a dynamic table generated by Process.GetCategoryList() which is actually loaded with <%= Process.GetCategoryList()). The bottom table HTML from the template looks like this:
<table width="100%">
<tr>
<td>
<div align="center">
<table bgcolor="#0066cc" width="120" cellpadding="0" cellspacing="3">
<tr>
<td width="100%" class="menuband" bgcolor="#003399" valign="center" align="center" height="22">
Categories</td>
</tr>
<tr>
<td width="100%" align="right" height="18">
<a href="itemlist.wws" class="menulink">All Products</a></td>
</tr>
<tr>
<td height="1">
<img src="space.gif" width="100%" height="1"></td>
</tr>
<%= Process.CategoryList() %>
</table>
</div>
</td>
</tr>
</table>
GetProcessList() is simply a method in the Web Connection Process class that generates an HTML string and returns it. It calls the business object to retrieve the Category list in a cursor and then proceeds to generate customized HTML that matches the look and feel of the table. To keep the design of this flexible CSS stylesheets are used for each of the items generated:
The same approach is used for pulling in the categories available using the <%= Process.CategoryList() %> method. This method however uses part of the wwStore business objects:
*********************************
* wwStore :: Categorylist
*********************************
*** Function: Creates the Category list as part of the
*** toolbar portion of the display
************************************************************************
FUNCTION Categorylist
LOCAL lcOutput, oLookups
*** Check if already used
IF !USED("_TLookups")
oLookups = CREATE([WWS_CLASS_LOOKUPS])
#IF WWSTORE_USE_SQL_TABLES
oLookups.SetSQLObject(Server.owwStoreSQL)
#ENDIF
oLookups.GetCategories("_TLookups",,.T.)
ELSE
*** Just select it
SELE _TLookups
LOCATE
ENDIF
IF !USED("_TLOOKUPS")
RETURN "*** Couldn't retrieve lookups"
ENDIF
*** Build a simple string outptu from the categories
*** HTML includes specific HTML formatting for hover
*** buttons and underline adding to the look and feel
lcOutput = ""
SCAN
lcoutput = lcOutput + ;
[<tr><td width=100% align="right" class="menulink">] +;
[<a href="itemlist.wws?Category=] + UrlEncode(TRIM(cData1)) + ;
[" class="menulink">]+TRIM(cData1) + [</a></td></tr>]+ CRLF + ;
[<tr><td height="1"><img src="space.gif" width="100%" height="1"></td></tr>] + CRLF
ENDSCAN
RETURN lcOutput
ENDFUNC
* wwStore :: Catogorylist
This method simply uses a helper business object to retrieve a list of categories from the lookups table in the form of a cursor result. It then builds an HTML string on the fly out of the data. Notice that this function caches the data it retrieves since the category list is fairly static. So rather than retrieving the data each time it only does so once and then leaves the cursor open. On the next hit the cursor will still be there and if it is it is simply reused so the data is not requeried.
The main portion of the document follows the <!-- Custom Form Stuff --> marker. In this case the content that goes there is almost entirely static as mentioned before. The only dynamic piece inside of it is the pcWelcome string at the top of the page:
<br> <img border="0" src="images/cccards.gif" align="right"> <%= pcWelcome %> <p> Welcome to the West Wind Web Store! Here you can purchase West Wind tools and products using<font size="2" face="Verdana"> your <b>VISA</b>, <b>MasterCard</b> or <strong>American Express</strong> credit card.</font> <p> ...
If you'll recall if we're not a repeat visitor the string will be empty so nothing displays. Otherwise pcWelcome is set to Welcome back Rick.
Let's move on by clicking on one of the categories off the home page.
Last Updated: 06/02/03 |
Send topic feedback