Enhancing the User Experience [ 148 ] It is back! Once the product is back in stock, we need to then alert those customers that the product which they were interested in is back in stock, and that they can proceed to make their purchase. This isn't something we can implement now, as we don't have an administrative interface in place yet. However, we can discuss what is involved in doing this: 1. The administrator alters the stock level. 2. Customers interested in that product are looked up. 3. E-mails for each of those customers are generated with relevant details, such as their name and the name of the product being automatically inserted. 4. E-mails are sent to the customers. The database contains a processed eld, so once an e-mail is sent, we can set the processed value to 1, and then once we have alerted all of our customers, we can delete those records. This covers us in the unlikely event that all the new stock sells out while we are e-mailing customers, and a new customer completes the notication form. Giving power to customers There are two very powerful social-oriented features, which we can implement into our framework. Product ratings Product ratings are quite simple to add to our framework: we simply need to record a series of ratings between one and ve, and display the average of these on the product view. We can enhance the view by making the rating system a clickable image, where the customer can click on the number of stars they wish to give the product and their rating is saved. There are a few minor considerations that need to be taken into account. However, if the logged-in customer has already rated a product, we should then update their rating. If the customer is not logged in, we must record some information about them such as their IP address and the date and time of the rating. This way we prevent duplicate ratings from the same customer. 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 [ 149 ] From a database perspective, we would need to capture the following information: ID (Integer, Primary Key, Auto Increment) ContentID (Integer) Rating (Integer) User ID (Integer) Timestamp (datetime) Session ID (Varchar) IP Address (Varchar) The following SQL represents that table in our database: CREATE TABLE `content_ratings` ( `ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `contentID` INT NOT NULL , `rating` INT NOT NULL , `userID` INT NOT NULL , `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `sessionID` VARCHAR( 255 ) NOT NULL , `IPAddress` VARCHAR( 50 ) NOT NULL ) ENGINE = INNODB; Saving a rating When a rating is made, we need to check to see if the current user has already rated that content element; if they have, then we must update that rating. For users who are not logged in, we should use their session name and IP address to lookup a potential rating from the past 30 days; if a rating is found, that should be updated. Saving the rating should be made simple by processing values from the URL. This way, we can have a graphic of ve stars or hearts, which when clicked, contain a link to the corresponding number of stars, to save the suitable rating. As ratings and reviews (comments) will not be content specic, we will need a separate controller for these. To return the customer to the page they were on previously, we could investigate looking up the referring page, and then redirecting the user to that page once their rating has been saved. The constructor of the controller needs to parse the URL bits to extract the content ID and the rating value, ensure that the rating is within allowed limits, and then call the saveRating function, which either inserts or updates a rating as appropriate. • • • • • • • 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 [ 150 ] To check if the user has rated the product already, we query the database; depending on if the user is logged in, this query is different. For users who are not logged in, we assume users with the same IP address and session data within the past 30 days were the current users. private function saveRating( $contentID, $rating ) { if( $this->regisry->getObject('authenticate')->isLoggedIn() ) { $u = $this->registry->getObject('authenticate')->getUserID(); $sql = "SELECT ID FROM content_ratings WHERE contentID={$contentID} AND userID={$u}"; } else { $when = strtotime("-30 days"); $when = date( 'Y-m-d h:i:s', $when ); $s = session_id(); $ip = $_SERVER['REMOTE_ADDR']; $sql = "SELECT ID FROM content_ratings WHERE content_id={$contentID} AND userID=0 AND sessionID='{$s}' AND IPAddress='{$ip}' AND timestamp > '{$when}'"; } $this->registry->getObject('db')->executeQuery( $sql ); If the product has already been rated, we update the rating. if( $this->regisry->getObject('db')->numRows() == 1 ) { // update $data = $this->registry->getObject('db')->getRows(); $update = array(); $update['rating'] = $rating; $update['timestamp'] = date('Y-m-d h:i:s'); $this->registry->getObject('db')-> updateRecords( 'content_ratings', $update, 'ID=' . $data['ID']); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Rating changed'); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Your rating has been changed'); $this->registry->getObject('template')-> buildFromTemplates('header.tpl.php', 'message.tpl.php', 'footer.tpl.php'); } 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 [ 151 ] Otherwise, we insert a new record in the ratings table. else { // insert $rating = array(); $rating['rating'] = $rating; $rating['contentID'] = $contentID; $rating['sessionID'] = session_id(); $rating['userID'] = ( $this->registry-> getObject('authenticate')->isLoggedIn() == true ) ? $this->registry->getObject('authenticate')->getUserID() : 0; $rating['IPAddress'] = $_SERVER['REMOTE_ADDR']; $this->registry->getObject('db')-> insertRecords( 'content_ratings', $rating ); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Rating saved'); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Your rating has been saved'); $this->registry->getObject('template')-> buildFromTemplates('header.tpl.php', 'message.tpl.php', 'footer.tpl.php'); } } Viewing ratings To display the ratings, we need to alter the content or products query to also perform a subquery, which averages out the rating. ( SELECT sum(rating)/count(*) FROM content_ratings WHERE contentID=c.ID ) AS rating Improving the user interface for ratings Displaying ratings as nice graphics, which display both the current rating and allow the user to select their own rating from them, are chapters in themselves. There are a number of Internet tutorials that document this process; you may nd them useful: http://www.komodomedia.com/blog/2005/08/creating-a-star-rater- using-css/ http://www.search-this.com/2007/05/23/css-the-star-matrix-pre- loaded/ • • 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 [ 152 ] Product reviews Product reviews can work as a simple comment form for the products, taking the name and e-mail address of the customer, as well as their review. Product reviews can be represented in the same way that we would represent comments on pages or blog entries, and because we have set up our database to store pages, products, and other types of content with a reference to a single database table, we can reference our reviews or comments to any content type. From a database perspective, a table with the following elds would sufce: Field Type Description ID Integer (Auto Increment, Primary Key) Review ID Content Integer The content entity the user is reviewing Customer name Varchar The customer Customer email Varchar The customer's e-mail address Review Longtext The customer's review IPAddress Varchar The user's IP address Date Added Timestamp The date they added the review Approved Boolean If the review is approved and shown on the site The following SQL code represents that table in our database: CREATE TABLE `content_comments` ( `ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `content` INT NOT NULL, `authorName` VARCHAR( 50 ) NOT NULL, `authorEmail` VARCHAR( 50 ) NOT NULL, `comment` LONGTEXT NOT NULL, `IPAddress` VARCHAR( 40 ) NOT NULL, `dateadded` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `approved` BOOL NOT NULL, INDEX ( `content` ) ) ENGINE = INNODB COMMENT = 'Content comments - also for product reviews'; ALTER TABLE `content_comments` ADD FOREIGN KEY ( `content` ) REFERENCES `book4`.`content` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE ; This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 . buildFromTemplates('header.tpl .php& apos;, 'message.tpl .php& apos;, 'footer.tpl .php& apos;); } This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy. `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `sessionID` VARCHAR( 255 ) NOT NULL , `IPAddress` VARCHAR( 50 ) NOT NULL ) ENGINE = INNODB; Saving a rating When a rating is made, we need. $this->registry->getObject('template')-> buildFromTemplates('header.tpl .php& apos;, 'message.tpl .php& apos;, 'footer.tpl .php& apos;); } } Viewing ratings To display the ratings, we need to