Enhancing the User Experience [ 128 ] $somethingToFilter = true; // build the query $sql .= " AND "; $assocs = implode( " AND ", $this->filterDirect ); $sql .= $assocs; } if( $somethingToFilter ) { // since we have some filter requests, store the query. $this->filterSQL = $sql; } } And secondly, we look at a function to build our SQL statement. /** * Add SQL chunks to our filter arrays, to help build our query, * based on actual filter requests in the URL * @param String $filterType the reference of the attribute type we * are filtering by * @param int $filterValue the ID of the attribute value * @return void */ private function addToFilter( $filterType, $filterValue ) { if( $this->filterTypes[ $filterType ] ['ProductContainedAttribute'] == 1 ) { $lower = $this->filterValues[ $filterValue ]['lowerValue']; $upper = $this->filterValues[ $filterValue ]['upperValue']; $sql = " p.{$filterType} >= {$lower} AND p.{$filterType} < {$upper}"; $this->filterDirect[] = $sql; } else { $this->filterCount++; $sql = " pfaa.attribute={$filterValue} "; $this->filterAssociations[] = $sql; } } This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 5 [ 129 ] Displaying filtered products Assuming we call our filterProducts() method within the products controller at some point, we can lter our products list quite easily. In our "products list" page, for instance, we can simply detect if the lter SQL eld is empty; if it is not, we can replace the list query with the lter query. Of course, we should also swap our template, to indicate that the results are a ltered subset. private function listProducts() { if( $this->filterSQL == '' ) { $sql = "SELECT p.price as product_price, v.name as product_name, c.path as product_path FROM content c, content_versions v, content_types_products p WHERE p.content_version=v.ID AND v.ID=c.current_revision AND c.active=1 "; } else { $sql = $this->filterSQL; } $cache = $this->registry->getObject('db')->cacheQuery( $sql ); $this->registry->getObject('template')->getPage()-> addTag( 'products', array( 'SQL', $cache ) ); $this->registry->getObject('template')-> buildFromTemplates('header.tpl.php', 'list-products.tpl.php', 'footer.tpl.php'); $this->generateFilterOptions(); } Remember, we must rst call our filterProducts method, so I've added this to the switch statement within the controller's constructor. $urlBits = $this->registry->getURLBits(); $this->filterProducts( $urlBits ); This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Enhancing the User Experience [ 130 ] If we have lters in place with respect to price and weight (which are based off the products table), they would look like this: If we click on one of the options, the products list would update to show products matching that criterion. Improving product filtering As with everything, there is always room for improvement. For the lter feature, potential improvements include: Displaying the number of products matching a lter next to it. Pagination—limiting the number of products displayed to the initial Y results, allowing the customer to move to the next set of results, so they are not overwhelmed with products. Updating this number to account for lters already in place (that is, if there are 100 brand X products and we lter the price to < $5, there may only be 20 matching brand X products, and the number should update to reect this). Filter options with no matching products could be hidden, to prevent the customer from clicking them, and nding that it made no change. Providing wish lists Wish lists allow customers to maintain a list of products that they would like to purchase at some point, or that they would like others to purchase for them as a gift. • • • • This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 5 [ 131 ] Creating the structure To effectively maintain wish lists for customers, we need to keep a record of: The product the customer desires The quantity of the product If they are a logged-in customer, their user ID If they are not a logged-in customer, some way to identify their wish-list products for the duration of their visit to the site The date they added the products to their wish list The priority of the product in their wish lists; that is, if they really want the product, or if it is something they wouldn't mind having Let's translate that into a suitable database table that our framework can interact with: Field Type Description ID Integer (Primary Key, Auto Increment) A reference for the database Product Integer The product the user wishes to purchase Quantity Integer The number of them the user would like Date added Datetime The date they added the product to their wish list Priority Integer Relative to other products in their wish list, and how important is this one Session ID Varcharr The user's session ID (so they don't need to be logged in) IP Address Varchar The user's IP address (so they don't need to be logged in) By combining the session ID and IP address of the customer, along with the timestamp of when they added the product to their wish list, we can maintain a record of their wish list for the duration of their visit. Of course, they would need to register, or log in, before leaving the site, for their wish list to be permanently saved. This also introduces an element of maintenance to this feature, as once a customer who has not logged in closes their session, their wish-list data cannot be retrieved, so we would need to implement some garbage collection functions to prune this table. • • • • • • This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Enhancing the User Experience [ 132 ] The following SQL represents this table: CREATE TABLE `wish_list_products` ( `ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `product` INT NOT NULL, `quantity` INT NOT NULL, `user` INT NOT NULL, `dateadded` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `priority` INT NOT NULL, `sessionID` VARCHAR( 50 ) NOT NULL, `IPAddress` VARCHAR( 50 ) NOT NULL, INDEX ( `product` ) ) ENGINE = INNODB COMMENT = 'Wish list products' ALTER TABLE `wish_list_products` ADD FOREIGN KEY ( `product` ) REFERENCES `book4`.`content` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE; Saving wishes Now that we have a structure in place for storing wish-list products, we need to have a process available to save them into the database. This involves a link or button placed on the product view, and either some modications to our product controller, or a wish-list controller, to save the wish. As wish lists will have their own controller and model for viewing and managing the lists, we may as well add the functionality into the wish-list controller. So we will need: a controller a link in our product view Wish-list controller The controller needs to detect if the user is logged in or not; if they are, then it should add products to the user's wish list; otherwise, it should be added to a session-based wish list, which lasts for the duration of the user's session. • • This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 . $this->registry->getObject('template')-> buildFromTemplates('header.tpl .php& apos;, 'list-products.tpl .php& apos;, 'footer.tpl .php& apos;); $this->generateFilterOptions(); } Remember, we. copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 5 [ 129 ] Displaying filtered products Assuming we call our filterProducts(). copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 5 [ 131 ] Creating the structure To effectively maintain wish lists for customers,