Building the Shopping Cart

This section contains a description of the code you can use to build the Web-based shopping cart.

BasicSession.pm

We base the whole shopping cart around the BasicSession module we create in the chapter on tied hashes. However, since we aren’t keeping user preferences only, but are keeping a cart of items, we have to modify the code a bit.

The @EXPORT = qw(Wrap_Page Get_Session); needs to be changed to:

@EXPORT = qw(Wrap_Page Get_Session Print_Page);

We need to print some of the templates without wrapping them, so we need to export Print_Page. That is it for the changes to BasicSession.pm. Can you believe it? I love the smell of re-useable code in the morning!

The catalog program is used to display a listing of the items that can be added to the cart. This program uses the SOAP catalog to grab the whole listing. Figure 15-1 shows the catalog. Note that these fonts have been greatly enlarged for the book.

click to expand
Figure 15-1: Catalog listing

When you click Add Item, the item is added to the cart. Take a look at the code we use for this.

catalog.cgi

start example
01: #!/usr/bin/perl -wT 02: use strict; 03: use SOAP::Lite; 04: use CGI qw(:standard); 05: use lib qw(.); 06: use BasicSession;
end example

Line 1 tells the system where to find Perl and turns on warnings and taint checking.

Line 2 loads the strict module.

Line 3 loads the SOAP::Lite module. We need this so that we can access the SOAP catalog.

Line 4 loads the CGI module and its :standard functions.

Line 5 tells Perl to look in the current directory for modules.

Line 6 loads the BasicSession module. This is the version we modify slightly so that we can use the Print_Page function as well.

07: our $sess; 08: my  %cart;

Line 7 declares the variable $sess as an our variable. This makes it accessible from the BasicSession module.

Line 8 declares a hash named %cart.

09: $sess = Get_Session(); 10: tie %cart, ‘BasicSession’;

Line 9 uses the Get_Session function to get/set the session cookie for this user. This allows us to track the user between pages by storing a cookie that our session database table uses for its unique id.

Line 10 ties the %cart hash to the methods in the BasicSession module. By tying the hash to BasicSession, we are able to modify how the hash behaves and have it directly modify a database table just by doing the normal operations on the hash.

11: my $add_to_cart = param(‘add_to_cart’); 12: ++$cart{$add_to_cart} if $add_to_cart;

Line 11 declares a variable named $add_to_cart and sets it to the value returned by the call to the param function param(‘add_to_cart’);

Line 12 adds 1 to the $cart with a key of $add_to_cart if $add_to_cart contains a value.

13: my $remove= param(‘remove’); 14: delete $cart{$remove} if $remove; 

Line 13 declares a variable named $remove and sets it to the value returned by the call to the param function param(‘remove’);.

Line 14 deletes the item with the key of $remove if $remove contains a value. If there is no item in the %item hash with key $remove, nothing will happen.

15: my $products = SOAP::Lite 16:   -> uri(‘http://goliath.perlguy.net/Catalog’) 17:   -> proxy(‘http://goliath.perlguy.net/cgi-                 bin/soap_server19.cgi’) 18:   -> Get_Product_List() 19:   -> result;

Line 15 declares a scalar variable named $products and assigns it to the value returned by the call to the SOAP::Lite module. Since the Get_Products_List SOAP method returns a reference to an array of references, a reference is stored in $products.

Lines 15–19 are actually several methods from the SOAP::Lite module strung together. These commands make up a SOAP client that gets data from the SOAP server that we built in Chapter 12.

Line 16 tells the SOAP client the URI, or namespace, of the service we are calling.

Line 17 is the address of the SOAP server we are contacting. We actually have to modify one line in the soap_server.cgi, so this one is renamed soap_server19.cgi. The modification simply adds the price field to the return results.

Line 18 is the remote function we are calling on the SOAP server.

Line 19 calls the result method, which returns the results of the function we have called.

20: Print_Page("./templates", "header.tmpl", \%cart); 21: Print_Page("./templates", "catalog_header.tmpl", \%cart);

Line 20 calls the Print_Page function to print the page header HTML.

Line 21 calls the Print_Page function to print the catalog_header template HTML. This prints the table header for the catalog page.

22: for my $p (@$products){ 23:     print qq( 24:       <tr><td> 25:  [<a href="catalog.cgi?add_to_cart=$p->[1]">Add Item</a>] 26:       </td><td> 27:   <a href="item_details.cgi?item_num=$p->[1]">$p->[1]</a> 28:       </td><td>$p->[0] 29:       </td><td>&nbsp;$p->[2] 30:       </td><td align="center">&nbsp;$item{$p->[1]} 31:       </td><td>            [<a href="catalog.cgi?remove=$p->[1]">Delete</a>] 32:       </td></tr>\n); 33: } 

Line 22 begins a loop that iterates through all of the values in the array that is referenced by $products.

Line 23 begins a qq block that prints the HTML for one table row of catalog data.

Lines 24–32 print one table row of catalog data. $products holds a reference to an array of arrays. So, each time through the loop, $p is actually a reference to an array. Notice that we access these items by using the arrow operator $p->[1] and so on.

Line 33 closes the for loop that begins on line 22.

34: Print_Page("./templates", "catalog_footer.tmpl", \%cart);

Line 34 finishes off by printing the HTML in the catalog_footer.tmpl template.

That is it for the catalog program. Since we are reusing code and using the SOAP server to send us the catalog data, we are been able to save a lot of time.

Next, we cover the item_details.cgi program. This program is similar to the script we use when we create the book catalog in Chapter 12. This time, however, we add links to manipulate your cart. Figure 15-2 contains a view of what occurs when you view a specific item.

click to expand
Figure 15-2: Item details

Notice the links at the bottom and the Qty in Cart item; these are added for the shopping cart.

item_details.cgi

start example
01: #!/usr/bin/perl -wT 02: use strict; 03: use CGI qw(:standard); 04: use SOAP::Lite; 05: use XML::Simple; 06: use lib qw(.); 07: use BasicSession;
end example

Line 1 tells the system where to find Perl and turns on warnings and taint checking.

Line 2 loads the strict module.

Line 3 loads the CGI module and its :standard functions.

Line 4 loads the SOAP::Lite module so that we can access the SOAP server.

Line 5 loads the XML::Simple module. We are accessing an alternative SOAP function; this time, the SOAP server returns XML data, so we need to be able to parse the catalog data.

Line 6 tells Perl to look in the current directory for modules.

Line 7 loads the BasicSession module.

08: our $sess; 09: my  %session;

Line 8 declares the variable $sess using the our function. By using the our function, we are able to access this data from the BasicSession module.

Line 9 declares the %session hash. We already have a hash named %cart in this program. To make code reuse easier, the hash we are adding to this program is renamed.

10: $sess = Get_Session(); 11: tie %session, ‘BasicSession’; 

Line 10 calls the Get_Session module to get/set the session cookie for this user.

Line 11 ties the %session hash to the BasicSession module.

12: my $input = param(‘item_num’);

Line 12 declares a scalar variable named $input and sets it to the value returned by the call to the param function param(‘item_num’);.

13: my $data = SOAP::Lite 14:   -> uri(‘http://goliath.perlguy.net/Catalog’) 15:   -> proxy(‘http://goliath.perlguy.net/cgi-                 bin/soap_server.cgi’) 16:   -> Get_Product_Data($input) 17:   -> result;

Line 13 declares a scalar variable named $data and assigns it to the value returned by the call to the SOAP::Lite module. The value returned by the Get_Product_Data is a string that makes up an XML document.

Lines 13–17 are actually several methods from the SOAP::Lite module strung together. These commands make up a SOAP client that gets data from the SOAP server.

Line 14 tells the SOAP client the URI, or namespace, of the service we are calling.

Line 15 is the address of the SOAP server we are contacting.

Line 16 is the remote function we are calling on the SOAP sever. We pass the value in $input to the Get_Product_Data function.

Line 17 calls the result method, which returns the results of the function we have called.

Note 

Note that the result SOAP method does not have to be changed like the former method we’ve used. This module has returned all of the data we need.

18: $data =~ s/\&amp;|\&/\&amp;/g; 19: my $item = XMLin($data);

Line 18 replaces any ampersands HTML markups (&amp;) or lone ampersands (&) in the XML document that was returned, with their equivalent HTML markup (&amp;). A plain ampersand in an XML document causes an error when the document is parsed. We included &amp; in our search to ensure that we don’t change an already marked-up ampersand from &amp; to &amp;amp;.

Line 19 declares a scalar variable named $item. This new scalar variable is set to the value returned by the call to the XMLin function. XMLin is part of the XML::Simple module; it returns a reference to a hash containing the parsed XML document.

20: ++$session{$item->{isbn}}  if(param(‘add_to_cart’));

Line 20 increments the number of this item in the cart by one if a value is passed in add_to_cart.

21: my $cart_qty = $session{$item->{isbn}}; 22: $cart_qty    = 0 unless $cart_qty; 23: $item->{‘cart_qty’} = $cart_qty;

Line 21 declares a scalar variable named $cart_qty and sets it to the value in %session at the key $item->{isbn}. This pulls the current cart quantity from the database; remember that %session is tied to the database.

Line 22 sets $cart_qty to 0 if nothing is in $cart_qty.

Line 23 sets the value in the %item hash to the current cart quantity. We set the %item hash because we are passing it to the templates for the output of the HTML.

24: Print_Page("./templates", "header.tmpl"      , $item); 25: Print_Page("./templates", "item_details.tmpl", $item);

Lines 24–25 use the Print_Page function to print the HTML contained in the templates header.tmpl and item_details.tmpl, respectively. Notice that we are passing $item instead of \%item. The function expects a reference to a hash, and $item holds a reference to a hash already.

This is a quick little program. By using a tied hash, we are able to remove much of the work we usually have to take care of in each program.

Now we take a look at the items in the cart (Figure 15-3). The cart.cgi program is designed to show the user what he or she has in the cart. It gives the user the option of adding more of an item or deleting an item altogether. This program is similar to catalog.cgi program, except we have to add a little more functionality to handle calculating the prices and printing the bottom line of the table.

click to expand
Figure 15-3: Items in the shopping cart

If you click the Delete link next to an item, it will remove the item from the cart and redisplay the screen (Figure 15-4).

click to expand
Figure 15-4: Shopping cart with item removed

cart.cgi

start example
 01: #!/usr/bin/perl -wT 02: # cart.cgi 03: use strict; 04: use SOAP::Lite; 05: use CGI qw(:standard); 06: use lib qw(.); 07: use BasicSession;
end example

Line 1 tells the system where to find Perl and turns on warnings and taint checking.

Line 2 is simply a comment that contains this program’s name.

Line 3 loads the strict module.

Line 4 loads the SOAP::Lite module so that we can access the SOAP catalog data.

Line 5 loads the CGI module and its :standard functions.

Line 6 tells Perl to look in the current directory for modules.

Line 7 loads the BasicSession module. This is the version we modify slightly so we can use the Print_Page function as well.

08: our $sess; 09: my  %session;

Line 8 declares the variable $sess as an our variable. This makes it accessible from the BasicSession module.

Line 9 declares a hash named %session.

10: $sess = Get_Session(); 11: tie %session, ‘BasicSession’;

Line 10 uses the Get_Session function to get/set the session cookie for this user. This allows us to track the user between pages by storing a cookie that our session database table uses for its unique id.

Line 11 ties the %session hash to the methods in the BasicSession module. By tying the hash to BasicSession, we are able to modify how the hash behaves and have it directly modify a database table just by doing the normal operations on the hash.

12: my $add_to_cart = param(‘add_to_cart’); 13: ++$session{$add_to_cart} if($add_to_cart);

Line 12 declares a variable named $add_to_cart and sets it to the value returned by the call to the param function – param(‘add_to_cart’);

Line 13 adds 1 to the $session with a key of $add_to_cart if $add_to_cart contains a value.

14: my $remove= param(‘remove’); 15: delete $session{$remove}; 

Line 14 declares a variable named $remove and sets it to the value returned by the call to the param function—param(‘remove’);

Line 15 deletes the member of the %session hash with the key of $remove. If there is no item in the %session hash with key $remove, nothing will happen.

16: my $products = SOAP::Lite 17:   -> uri(‘http://goliath.perlguy.net/Catalog’) 18:   -> proxy(‘http://goliath.perlguy.net/cgi-                 bin/soap_server19.cgi’) 19:   -> Get_Product_List() 20:   -> result;

Line 16 declares a scalar variable named $products and assigns it to the value returned by the call to the SOAP::Lite module. Since the Get_Products_List SOAP method returns a reference to an array of references, a reference is stored in $products.

Lines 16–20 are actually several methods from the SOAP::Lite module strung together. These commands make up a SOAP client that gets data from the SOAP server.

Line 17 tells the SOAP client the URI, or namespace, of the service we are calling.

Line 18 is the address of the SOAP server we are contacting. We actually have to modify one line in the soap_server.cgi, so this one is renamed soap_server19.cgi. The modification simply adds the price field to the return results.

Line 19 is the remote function we are calling on the SOAP sever.

Line 20 calls the result method, which returns the results of the function we have called.

21: Print_Page("./templates", "header.tmpl", \%session); 22: Print_Page("./templates", "catalog_header.tmpl", \%session); 

Line 21 calls the Print_Page function to print the page header HTML.

Line 22 calls the Print_Page function to print the catalog_header template HTML. This prints the table header for the catalog page.

Now we are finished with the code that is identical to the catalog.cgi program.

23: delete($session{‘cart_qty_total’});  24: delete($session{‘cart_price_total’});

Lines 23–24 delete whatever is stored at the cart_qty_total and cart_price_total hash indexes. We delete these values because any remaining old values are unnecessary. Remember, this is not a normal hash; it is tied to a database and can remember values between program calls.

We need to delete the old values to make sure that the calculations we are about to perform start fresh.

25: for my $prod (@$products){ 26:     next unless ($session{$prod->[1]});

Line 25 is again like the catalog.cgi program. It loops through each of the items in the @$products array. Each time through the loop, the current value (a reference to another array) is set to $prod.

Line 26 checks to see if the current the hash $session{$prod->[1]} contains any data. If it does, this item is in the users shopping cart and we want to show it. If it does not contain any data, we want to cause the loop to move on to the next item, so we call the next function.

27:     $session{‘cart_qty_total’}   += $session{$prod->[1]}; 28:     $session{‘cart_price_total’} +=              Calc_Price($session{$prod->[1]} , $prod->[2]);

Line 27 reads the quantity of this item from $session{$prod->[1]} and adds that to the current value stored at $session{‘cart_qty_total’}. This keeps a running total of the number of items in the cart.

Line 28 does basically the same thing as line 27, except this one is keeping a running total of the price. The Calc_Price function gets passed the qty ($prod->[1]) and the price ($prod->[2]) so that they can be multiplied and returned.

29:     print qq( 30:       <tr><td> 31:   [<a href="cart.cgi?add_to_cart=$prod->[1]">Add Item</a>] 32:       </td><td> 33:   <a href="item_details.cgi?item_num=$prod->[1]">$prod->[1]</a> 34:       </td><td> 35:         $prod->[0] 36:       </td><td align="right"> 37:         &nbsp;$prod->[2] 38:       </td><td align="center"> 39:         &nbsp;$session{$prod->[1]} 40:       </td><td> 41:         [<a href="cart.cgi?remove=$prod->[1]">Delete</a>] 42:       </td></tr>\n 43:     ); 44: }

Lines 29–44 do the exact same thing as the lines 22–33 in the catalog.cgi program; they print one table row of data corresponding to the current item.

45: $session{‘cart_price_total’} =           sprintf("%.2f", $session{‘cart_price_total’});

Line 45 calls the sprintf function to format the cart price total value so that it contains two decimal points. We then overwrite $item{‘cart_price_total’} with the newly formatted value.

46: Print_Page("./templates", "cart_total.tmpl"    , \%session); 47: Print_Page("./templates", "catalog_footer.tmpl", \%session);

Lines 46 and 47 use the Print_Page function to print the HTML from the cart_total.tmpl and catalog_footer.tmpl templates. This prints the bottom of the resulting HTML page.

48: sub Calc_Price { 49:     my($qty, $price) = @_;

Line 48 begins the Calc_Price subroutine.

Line 49 declares two variables and sets them to the values passed to this subroutine.

50:     $price =~ s/[ \$]//g; 51:     return($qty * $price); 52: }

Line 50 strips any spaces or dollar signs from the value in $price.

Line 51 returns the product of $qty and $price.

Line 52 ends the Calc_Price subroutine, as well as this program.

Finally, we write a script that generates a basic invoice. This program is very similar to cart.cgi program—so similar, in fact, that they can probably be merged into

one program that determines which templates to use based upon a passed value. This is a great user exercise, enabling you to learn how to combine similar programs if you want to maximize shared code.

Figure 15-5 shows what a simple invoice looks like. The really nice thing about using templates is that you can create a much better looking invoice without changing anything in the invoice program at all.

click to expand
Figure 15-5: The invoice

invoice.cgi

start example
01: #!/usr/bin/perl -wT 02: use strict; 03: use SOAP::Lite; 04: use CGI qw(:standard); 05: use lib qw(.); 06: use BasicSession;
end example

Line 1 tells the system where to find Perl and turns on warnings and taint checking.

Line 2 loads the strict module.

Line 3 loads the SOAP::Lite module so that we can get the catalog data.

Line 4 loads the CGI module and its :standard functions.

Line 5 tells Perl to look in the current directory when looking for modules.

Line 6 loads the BasicSession module.

07: our $sess; 08: my  %session;

Line 7 declares the variable $sess as an our variable. This makes it accessible from the BasicSession module.

Line 8 declares a hash named %session.

09: $sess = Get_Session(); 10: tie %session, ‘BasicSession’;

Line 9 uses the Get_Session function to get/set the session cookie for this user. This allows us to track the user between pages by storing a cookie that our session database table uses for its unique id.

Line 10 ties the %session hash to the methods in the BasicSession module. By tying the hash to BasicSession, we are able to modify how the hash behaves and have it directly modify a database table just by doing the normal operations on the hash.

11: my $products = SOAP::Lite 12:   -> uri(‘http://goliath.perlguy.net/Catalog’) 13:   -> proxy(‘http://goliath.perlguy.net/cgi-                 bin/soap_server19.cgi’) 14:   -> Get_Product_List() 15:   -> result;

Line 11 declares a scalar variable named $products and assigns it to the value returned by the call to the SOAP::Lite module. Since the Get_Products_List SOAP method returns a reference to an array of references, a reference is stored in $products.

Lines 11–15 are actually several methods from the SOAP::Lite module strung together. These commands make up a SOAP client that gets data from the SOAP server.

Line 12 tells the SOAP client the URI, or namespace, of the service we are calling.

Line 13 is the address of the SOAP server we are contacting.

Line 14 is the remote function we are calling on the SOAP sever.

Line 15 calls the result method, which returns the results of the function we have called.

16: Print_Page("./templates", "header.tmpl", \%session); 17: Print_Page("./templates", "invoice_header.tmpl", \%session);

Lines 16 and 17 use the Print_Page subroutine to print the header.tmpl and invoice_header.tmpl templates.

18: delete($session{‘cart_qty_total’}); 19: delete($session{‘cart_price_total’});

Lines 18 and 19 clear any values that may be at the cart_qty_total and cart_price_total indexes.

20: for my $prod (@$products){ 21:     next unless ($session{$prod->[1]});

Line 20 is like the catalog.cgi program. It loops through each of the items in the @$products array. Each time through the loop, the current value (which is a reference to another array) is set to $prod.

Line 21 checks to see if the current the hash $session{$prod->[1]} contains any data. If it does, this item is in the user’s shopping cart, and we want to show it. If it does not contain any data, we want to cause the loop to move to the next item, so we call the next function.

22:     $session{‘cart_qty_total’}   += $session{$prod->[1]}; 23:     $session{‘cart_price_total’} +=              Calc_Price($session{$prod->[1]} , $prod->[2]);

Line 22 reads the quantity of this item from $session{$prod->[1]} and adds that to the current value stored at $session{‘cart_qty_total’}. This keeps a running total of the number of items in the cart.

Line 23 does basically the same thing as line 22, except this one is keeping a running total of the price. The Calc_Price function gets passed the qty ($prod->[1]) and the price ($prod->[2]) so that they can be multiplied and returned.

24:     print qq( 25:       <tr> 26:        <td align="center" valign="top"> 27:         $prod->[1] 28:        </td> 29:        <td align="left"> 30:         &nbsp;&nbsp;$prod->[0] 31:        </td> 32:        <td align="center" valign="top"> 33:         $session{$prod->[1]} 34:        </td> 35:        <td align="right" valign="top"> 36:         $prod->[2] 37:        </td> 38:        <td align="right" valign="top"> 39:     );

Lines 24–39 print most of the HTML for one row of data on the invoice. We need to format the price properly, so we stop short of a complete row of data.

40:   printf("\$%.2f", Calc_Price($session{$prod->[1]}, $prod->[2]) );

Line 40 uses the printf function to print the value returned by our call to Calc_Price and to format it so that it contains two decimal points. Notice here that we use printf, not sprintf as we did previously. sprintf is used when you are setting a variable or something to the result, whereas printf is used to print the item directly.

41:     print qq( 42:        </td> 43:       </tr>\n 44:     ); 45: }

Lines 41–45 finish the HTML for the row of data. On line 45, we close the for loop that we began on line 20.

46: $session{‘cart_price_total’} =          sprintf("%.2f", $session{‘cart_price_total’}); 47: Print_Page("./templates", "invoice_footer.tmpl", \%session);

Line 46 uses sprintf to set the current cart_price_total index so that it is formatted to two decimal places.

Line 47 prints the HTML in invoice_footer.tmpl to close this invoice page.

48: sub Calc_Price { 49:     my($qty, $price) = @_; 

Line 48 begins the Calc_Price subroutine.

Line 49 declares two variables and sets them to the values passed to this subroutine.

50:     $price =~ s/[ \$]//g; 51:     return($qty * $price); 52: }

Line 50 strips any spaces or dollar signs from the value in $price.

Line 51 returns the product of $qty and $price.

Line 52 ends the Calc_Price subroutine, as well as this program.

And that wraps up the invoice program. This program is pretty much a re-do of the cart program but formatted to look like an invoice.



Perl Database Programming
Perl Database Programming
ISBN: 0764549561
EAN: 2147483647
Year: 2001
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net