1. Trang chủ
  2. » Công Nghệ Thông Tin

Beginning PHP and MySQL E-Commerce From Novice to Professional phần 7 doc

74 286 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 74
Dung lượng 1,84 MB

Nội dung

</p> </form> 3. Create a new folder in your project’s root folder (tshirtshop) named scripts, add a new file named ajax.js in it, and type the following code: // Holds an instance of XMLHttpRequest var xmlHttp = createXmlHttpRequestObject(); // Display error messages (true) or degrade to non-AJAX behavior (false) var showErrors = true; // Contains the link or form clicked or submitted by the visitor var actionObject = ''; // Creates an XMLHttpRequest instance function createXmlHttpRequestObject() { // Will store the XMLHttpRequest object var xmlHttp; // Create the XMLHttpRequest object try { // Try to create native XMLHttpRequest object xmlHttp = new XMLHttpRequest(); } catch(e) { // Assume IE6 or older var XmlHttpVersions = new Array( "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"); // Try every id until one works for (i = 0; i < XmlHttpVersions.length && !xmlHttp; i++) { try { // Try to create XMLHttpRequest object xmlHttp = new ActiveXObject(XmlHttpVersions[i]); } catch (e) {} // Ignore potential error } } CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES 415 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 415 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com // If the XMLHttpRequest object was created successfully, return it if (xmlHttp) { return xmlHttp; } // If an error happened, pass it to handleError else { handleError("Error creating the XMLHttpRequest object."); } } // Displays an the error message or degrades to non-AJAX behavior function handleError($message) { // Ignore errors if showErrors is false if (showErrors) { // Display error message alert("Error encountered: \n" + $message); return false; } // Fall back to non-AJAX behavior else if (!actionObject.tagName) { return true; } // Fall back to non-AJAX behavior by following the link else if (actionObject.tagName == 'A') { window.location = actionObject.href; } // Fall back to non-AJAX behavior by submitting the form else if (actionObject.tagName == 'FORM') { actionObject.submit(); } } // Adds a product to the shopping cart function addProductToCart(form) { // Display "Updating" message document.getElementById('updating').style.visibility = 'visible'; // Degrade to classical form submit if XMLHttpRequest is not available if (!xmlHttp) return true; CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES416 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 416 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com // Create the URL we open asynchronously request = form.action + '&AjaxRequest'; params = ''; // obtain selected attributes formSelects = form.getElementsByTagName('SELECT'); if (formSelects) { for (i = 0; i < formSelects.length; i++) { params += '&' + formSelects[i].name + '='; selected_index = formSelects[i].selectedIndex; params += encodeURIComponent(formSelects[i][selected_index].text); } } // Try to connect to the server try { // Continue only if the XMLHttpRequest object isn't busy if (xmlHttp.readyState == 4 || xmlHttp.readyState == 0) { // Make a server request to validate the extracted data xmlHttp.open("POST", request, true); xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlHttp.onreadystatechange = addToCartStateChange; xmlHttp.send(params); } } catch (e) { // Handle error handleError(e.toString()); } // Stop classical form submit if AJAX action succeeded return false; } // Function that retrieves the HTTP response function addToCartStateChange() { // When readyState is 4, we also read the server response if (xmlHttp.readyState == 4) { // Continue only if HTTP status is "OK" CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES 417 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 417 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com if (xmlHttp.status == 200) { try { updateCartSummary(); } catch (e) { handleError(e.toString()); } } else { handleError(xmlHttp.statusText); } } } // Process server's response function updateCartSummary() { // Read the response response = xmlHttp.responseText; // Server error? if (response.indexOf("ERRNO") >= 0 || response.indexOf("error") >= 0) { handleError(response); } else { // Extract the contents of the cart_summary div element var cartSummaryRegEx = /^<div class="box" id="cart-summary">➥ ([\s\S]*)<\/div>$/m; matches = cartSummaryRegEx.exec(response); response = matches[1]; // Update the cart summary box and hide the Loading message document.getElementById("cart-summary").innerHTML = response; // Hide the "Updating " message document.getElementById('updating').style.visibility = 'hidden'; } } 4. Open presentation\templates\store_front.tpl, and add a reference to your JavaScript file, ajax.js: <html> <head> CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES418 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 418 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com <title>{$obj->mPageTitle}</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link href="{$obj->mSiteUrl}tshirtshop.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" </head> 5. Modify index.php as highlighted: // Load Business Tier require_once BUSINESS_DIR . 'catalog.php'; require_once BUSINESS_DIR . 'shopping_cart.php'; // URL correction Link::CheckRequest(); // Load Smarty template file $application = new Application(); // Handle AJAX requests if (isset ($_GET['AjaxRequest'])) { // Headers are sent to prevent browsers from caching header('Expires: Fri, 25 Dec 1980 00:00:00 GMT'); // Time in the past header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); header('Content-Type: text/html'); if (isset ($_GET['CartAction'])) { $cart_action = $_GET['CartAction']; if ($cart_action == ADD_PRODUCT) { require_once PRESENTATION_DIR . 'cart_details.php'; $cart_details = new CartDetails(); $cart_details->init(); $application->display('cart_summary.tpl'); } } else trigger_error('CartAction not set', E_USER_ERROR); } CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES 419 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 419 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com else { // Display the page $application->display('store_front.tpl'); } // Close database connection DatabaseHandler::Close(); 6. Open presentation\cart_details.php, and make the following changes in the switch block in the init() method: if (count($selected_attributes) > 0) $attributes = implode('/', $selected_attributes) . ': ' . implode('/', $selected_attribute_values); ShoppingCart::AddProduct($this->_mItemId, $attributes); if (!isset ($_GET['AjaxRequest'])) header('Location: ' . $this->mLinkToContinueShopping); else return; break; case REMOVE_PRODUCT: ShoppingCart::RemoveProduct($this->_mItemId); if (!isset ($_GET['AjaxRequest'])) header('Location: ' . Link::ToCart()); break; case UPDATE_PRODUCTS_QUANTITIES: for($i = 0; $i < count($_POST['itemId']); $i++) ShoppingCart::Update($_POST['itemId'][$i], $_POST['quantity'][$i]); if (!isset ($_GET['AjaxRequest'])) header('Location: ' . Link::ToCart()); break; case SAVE_PRODUCT_FOR_LATER: ShoppingCart::SaveProductForLater($this->_mItemId); if (!isset ($_GET['AjaxRequest'])) header('Location: ' . Link::ToCart()); break; case MOVE_PRODUCT_TO_CART: ShoppingCart::MoveProductToCart($this->_mItemId); CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES420 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 420 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com if (!isset ($_GET['AjaxRequest'])) header('Location: ' . Link::ToCart()); break; default: // Do nothing break; } 7. Modify the CheckRequest() method of the Link class, in link.php, as highlighted. We don’t validate the URL when responding to an AJAX request. // Redirects to proper URL if not already there public static function CheckRequest() { $proper_url = ''; if (isset ($_GET['Search']) || isset($_GET['SearchResults']) || isset ($_GET['CartAction']) || isset ($_GET['AjaxRequest'])) { return ; } 8. Open presentation\templates\cart_summary.tpl, and make the changes shown here: {* cart_summary.tpl *} {load_presentation_object filename="cart_summary" assign="obj"} {* Start cart summary *} <div class="box" id="cart-summary"> <p class="box-title">Cart Summary</p> <div id="updating">Updating </div> {if $obj->mEmptyCart} <p class="empty-cart">Your shopping cart is empty!</p> {else} 9. Add the following style definition to the tshirtshop.css file from the styles folder: #updating { background-color: #ff0000; border: none; color: #ffffff; margin: 2px; padding: 2px; visibility: hidden; position: absolute; width: 70px; } 10. Load your catalog, and ensure that the Add to Cart buttons work fine using the new AJAX code. CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES 421 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 421 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com How It Works We’ve modified the name of the submit HTML element to add_to_cart so that we can submit it from JavaScript: {/section} </p> {* Add the submit button and close the form *} <p> <input type="submit" name="add_to_cart" value="Add to Cart" /> </p> </form> We have a variable named showErrors, whose value affects the way errors are handled. If this variable is true, debugging error messages are displayed using alert(). This isn’t a very user-friendly method of handling errors, but it helps with debugging. If showErrors is false, no errors are shown. Instead, when a JavaScript error hap- pens, the behavior is degraded to a classical form submit. // Display error messages (true) or degrade to non-AJAX behavior (false) var showErrors = true; This variable is used in the handleError() function, which is called every time an error happens in the JavaScript code. If showErrors is true, this function simply displays the error details: // Displays an error message or degrades to non-AJAX behavior function handleError($message) { // Ignore errors if showErrors is false if (showErrors) { // Display error message alert("Error encountered: \n" + $message); return false; } If showErrors is false, we don’t display error details. Instead, we try to execute the action requested by the vis- itor in a non-AJAX fashion. Here we use actionObject, which represents the form submitted by the visitor or the action link clicked by the visitor. If actionObject isn’t set, it means the error happened in the JavaScript function referenced in the onclick or onsubmit attribute. In that case, we simply need to return true, which causes the original requested action to happen: // Fall back to non-AJAX behavior else if (!actionObject.tagName) { return true; } If actionObject is a link, it means the error happened after the visitor clicked a link, in which case we redirect the request to that URL: // Fall back to non-AJAX behavior by following the link else if (actionObject.tagName == 'A') CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES422 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 422 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com { window.location = actionObject.href; } If actionObject is a form, it means the error happened after the visitor submitted a form, in which case we redi- rect the request to that URL: // Fall back to non-AJAX behavior by submitting the form else if (actionObject.tagName == 'FORM') { actionObject.submit(); } } The index.php script was updated to respond to AJAX requests as well.When making an asynchronous request to index.php, the AjaxRequest parameter is added to the query string so that index.php knows to react accordingly. First it sets the appropriate header values to make sure the response isn’t cached: if (isset ($_GET['AjaxRequest'])) { // Headers are sent to prevent browsers from caching header('Expires: Fri, 25 Dec 1980 00:00:00 GMT'); // Time in the past header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); header('Content-Type: text/html'); Then the existing code that adds a new product to the cart is used to perform the requested action. The cart_summary.tpl template is sent to the output, and the JavaScript will use it to update the cart summary box using the JavaScript DOM functions: if (isset ($_GET['CartAction'])) { $cart_action = $_GET['CartAction']; if ($cart_action == ADD_PRODUCT) { require_once PRESENTATION_DIR . 'cart_details.php'; $cart_details = new CartDetails(); $cart_details->init(); $application->display('cart_summary.tpl'); } } else trigger_error('CartAction not set', E_USER_ERROR); } The updateCartSummary() JavaScript function in ajax.js is responsible for reading the HTML code gener- ated by cart_summary.tpl and injecting it into the cart summary box. The function first verifies that the request CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES 423 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 423 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com has not resulted in an error, in which case the handleError() function is called to either display the error or fall back to non-AJAX behavior: // Process server's response function updateCartSummary() { // Read the response response = xmlHttp.responseText; // Server error? if (response.indexOf("ERRNO") >= 0 || response.indexOf("error") >= 0) { handleError(response); } If the response doesn’t contain an error, it’s assumed to contain the HTML contents of the new cart summary box. This response will be something like this: {* Start cart summary *} <div class="box" id="cart-summary"> <p class="box-title">Cart Summary</p> <div id="updating">Updating </div> </div> Our JavaScript code must take the contents of the root <div> element and inject them into the page under the cart-summary <div> element. For this we used a regular expression named cartSummaryRegEx: else { // Extract the contents of the cart_summary div element var cartSummaryRegEx = /^<div class="box" id="cart-summary">➥ ([\s\S]*)<\/div>$/m; matches = cartSummaryRegEx.exec(response); response = matches[1]; Alternatively, we could have used the XML DOM or the substring feature of string. The substring method is the fastest and easiest to implement, but it has the disadvantage that it’s not flexible. If the format of the output or the name of the <div> element changes, it will not work anymore. Here’s a possible implementation: response = response.substring(25, response.length - 7); After obtaining the string, updateCartSummary() uses it to replace the contents of the cart-summary element of the page, effectively updating the cart summary. The “Loading ” text is also hidden: // Update the cart summary box and hide the Loading message document.getElementById("cart-summary").innerHTML = response; // Hide the "Updating " message document.getElementById('updating').style.visibility = 'hidden'; } } CHAPTER 13 ■ IMPLEMENTING AJAX FEATURES424 8644ch13FINAL.qxd 1/30/08 2:43 PM Page 424 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... the administration menu: < ?php class AdminMenu { public $mLinkToStoreAdmin; public $mLinkToAttributesAdmin; public $mLinkToCartsAdmin; public $mLinkToOrdersAdmin; public $mLinkToStoreFront; public $mLinkToLogout; public function construct() { $this->mLinkToStoreAdmin = Link::ToAdmin(); $this->mLinkToAttributesAdmin = Link::ToAttributesAdmin(); $this->mLinkToCartsAdmin = Link::ToCartsAdmin(); 445 8644ch14.qxd... 12:42 PM Page 446 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 446 CHAPTER 14 ■ ACCEPTING CUSTOMER ORDERS $this->mLinkToOrdersAdmin = Link::ToOrdersAdmin(); if (isset ($_SESSION['link _to_ store_front'])) $this->mLinkToStoreFront = $_SESSION['link _to_ store_front']; else $this->mLinkToStoreFront = Link::ToIndex(); $this->mLinkToLogout = Link::ToLogout(); } } ?> 5 Modify presentation/templates/admin_menu.tpl... Now, we also need to make a small change to ajax.js, to ensure that the new button isn’t handled by JavaScript code If you remember, in Chapter 13, we added the onsubmit event handler to the shopping cart form, so shopping cart actions are handled asynchronously, using AJAX, whenever possible We don’t want this to happen for the Place Order button This button must submit the form to the server, which... official documentation page at http://dev .mysql. com/ doc/ refman/5.1/en/getting-unique-id.html You read the value of LAST_INSERT_ID(), and save it to a variable named orderId Using the orderId value, you add the order_detail records by gathering information from the product and shopping_cart tables You get the list of the products and their quantities from shopping_cart, get their names and prices from. .. In the Phase III of development (see Chapter 16), we’ll move to a full professional implementation and store customer information in its own data table The field names are self-explanatory order_id is the primary key of the table total_amount stores the total value of the order created_on and shipped_on specify when the order was created and shipped (the latter supports NULL values, which just means... the handler for the click event of your “Save for later” links and Remove buttons and the handler for the submit event of the form This way, when JavaScript is available and these buttons or links are clicked, the JavaScript event handlers execute before the browser has the chance to submit the form or follow the clicked link Then you created the necessary JavaScript code that implements the event handlers:... shopping_cart_create_order stored procedure in your tshirtshop database This stored procedure gets called when the customer decides to buy the products in the shopping cart and clicks the Place Order button The role of shopping_cart_create_order is to create a new order based on the products in the customer’s shopping cart This implies adding a new record to the orders table and a number of records (one... AJAX is cool, and so is our newly AJAX-enabled site! This wasn’t a short and easy chapter, but what you’ve achieved (and learned!) will prove to be very useful in the future Of course, the range of AJAX features you can add to your web site is very wide, but right now you have the foundations implemented, and your customers will certainly appreciate the AJAX touch you’ve added to your store 8644ch14.qxd... administrator to manually check, in the administration page, which orders have been paid for and take the appropriate measures ■ Note PayPal and its competitors offer automated systems that inform your web site when a payment has been completed or canceled However, this book doesn’t investigate the intimate details of any of these payment systems—you’ll need to do your homework and study the documentation... where you can view and update order information, as shown in Figure 14 -7 443 8644ch14.qxd 1/30/08 12:42 PM Page 444 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 444 CHAPTER 14 ■ ACCEPTING CUSTOMER ORDERS Figure 14 -7 Administering order details Before creating the admin_orders and the admin_order_details componentized templates, we need to modify admin .php to load these componentized . later” links and Remove buttons and the handler for the submit event of the form. This way, when JavaScript is available and these buttons or links are clicked, the JavaScript event handlers execute. move to a full profes- sional implementation and store customer information in its own data table. The field names are self-explanatory. order_id is the primary key of the table. total_amount stores. updated to respond to AJAX requests as well.When making an asynchronous request to index .php, the AjaxRequest parameter is added to the query string so that index .php knows to react accordingly.

Ngày đăng: 12/08/2014, 10:21

TỪ KHÓA LIÊN QUAN