CS637 Homework 5 Objects, Unit Testing, Session Variables, HTTP Headers

Due Mon., Apr. 30 in class, on paper, plus two projects on topcat by midnight.

  1. PHP Objects, Unit Testing. Set up a project for ch14_guitar_shop in Netbeans. Copy ch24_guitar_shop/cart/* to your ch14_guitar_shop/cart, replacing the stub index.php that is there. First we want to add a Cart class to model. The procedural version of cart.php from chapter 24 with simplified function names and without the function implementations is available in cart.php in the class home (you can copy it to your current directory on topcat with cp /data/htdocs/cs637/cart.php .).  Turn it into a class Cart. Use an associative array $itemQty as a property of Cart to hold the contents of the cart (in skeletal form), with key product_id, value quantity ordered. Create an empty array in the cart constructor, and code the methods. As an example, addItem($product_id, $quantity) is implemented simply by $this->itemQty[$product_id] = $quantity. Although you might be tempted to use Product objects instead of product_ids to represent the cart contents, remember that the cart will be a session object and so should not have unnecessary objects: the full Product is easily obtained from the database using the product_id.

    Show your cart.php code in your homework paper. Write a little command-line test program TestCart1.php (also in the model directory in your project) that creates a Cart object, adds 2 units of product 1 and 3 units of product 2, then calls productCount (should be 2) and itemCount (should be 5). Then it updates product 2 to have quantity 1 and repeats the two count calls. TestCart1.php needs to require only cart.php in the same directory. Show TestCart1.php and a typescript of a run in your homework paper. Run it by cd'ing to the model directory and using the command  php TestCart1.php. This is a case of unit testing because we are testing outside the whole application, concentrating on one class. Note that when all the sources are in one directory, Netbeans can provide auto-completion on object properties and methods. It is possible but difficult to set this up when using code in multiple directories. Just pause a little after typing "->" and see a pop-up list of possible completions to choose from.

  2. PHP Objects, Unit Testing with a Mock. To be more convenient to its callers, the Cart can fill out the details on the items in the cart for the caller (without holding them in the session data). Each item has a product_id, name, unit_price, quantity, and line_price in use in ch24_guitar_shop/cart/cart_view.php, which you have copied to the project's cart directory in problem 1. Create an Item class (item.php in model) with these properties (you can modify the names a little if you want). Note that Netbeans can generate the getters and setters for you: right-click the source and choose Insert Code.  Add a method getItems() to Cart that returns an array of Items representing the cart's current contents. In getItems, you start from info in itemQty, and, for each product_id there, create an Item object, using the database to fill out the name, unit_price, etc. Then put the Item object in a growing array.  See related code in ch24_guitar_shop/model/cart.php, but note your are building an ordinary array of objects here, not an associative array. Use $discount_percent = 30. Also add method getSubtotal() for Cart, like cart_subtotal() of ch24's cart.php.

    Write TestCart2.php and mock_product_db.php to test this. TestCart2.php should set up the basic cart as the first part of TestCart1, and then call at least getSubtotal. mock_product_db.php has class ProductDB, but it is a fake one. See https://en.wikipedia.org/wiki/Mock_object for more info on mocks. The mock ProductDB class has only one method getProduct($product_id) that tests product_id for values 1 and 2 and returns a Product object for one of these values, new Product($category, 'strat', 'Stratocaster', 700) for product id 1 or new Product($category, 'sg', 'SG', 2500) for product id 2. Show the .php files and a run of your test in your homework paper. The subtotal should be 2*700+3*2500 = 6230. You will need requires for 5 php files in TestCart2.php, luckily all in the model directory. Show your new methods for cart.php, your mock ProductDB code, and your run of TestCart2.php in your homework paper.

  3. PHP Objects, System Testing. Convert the two files in directory cart (the ones copied from ch24_guitar_shop/cart) to work with your Cart class. In the controller, regardless of the $action value, you need to check if there is a cart object in the session, and create a new one if necessary. The the various calls for cart action need to be fixed. Additionally, before or after add_item is called in index.php, the code needs to set   $_SESSION['last_category_id'] and $_SESSION['last_category_name'] for use by the cart_view.php (for this and later request cycles). This requires calling ProductDB::get_product($product_id) to find details on this product and its category. Similarly fix up cart_view.php. Deliver this project to your directory under /var/www/html/cs637 on topcat, specifically, to /var/www/html/cs637/username/ch14_guitar_shop. In your homework paper, explain any problems you had and say whether you were successful in getting this to work properly. We may examine and test the projects on topcat or just verify they are there.

  4. More on session variables. In the slides for Chapter 12, there is a sketch of how to modify the numberguess (zip) example (index.php and related files in the subdirectory named "fixed", with the REDIRECT to the success page) to use a session variable to avoid showing the user name in the browser address bar.  Do the indicated modifications and install the result at /var/www/html/cs637/username/numberguess. In your homework paper, show your index.php and numberguess_success.php contents.

  5. HTTP Headers and Status Codes. You need to master this for the Web Services project. See the recent slides on HTTP(6pp).
    a. Use Chrome to browse to the pizza1 solution available at http://topcat.cs.umb.edu/cs637/eoneil/pizza1/.  Right click and select "inspect element", or Control-click on Apple. Select the Network tab. Then refresh the page. Because the network tab is selected, this time Chrome will capture all the headers, etc. You should see three requests generated for this page access: pizza1/, main.css, and pizzapie.jpg. Click on pizza1/, and on the right you will see the headers, etc.
    For each request, record these important headers. For Cookie, just note if you found PHPSESSID.: Here is the first one (details could be different):

    Request Method: GET
    Request headers:

    1. Accept:
    2. Accept-Language:
    3. Cookie: PHPSESSID not found (pizza1 needs no session tracking,
    4.  but you may see PHPSESSID if you were recently using numberguess or cart)
    5. Response headers:

    6. Content-Length:
    7. Content-Type:
    8. If you see a response code of 304 for pizzapie.jpg and the lack of Content-Length (or content, look at Response tab), don't be dismayed. The image has a "conditional get" with a last-modified date (See If-Modified-Since request header), and since it hasn't been modified, the content is not returned.  The browser has the content already.

    b. Order a pizza from pizza1, with the Network tab still open, and similarly report on the 4 requests involved in displaying the "student welcome" page just after the order. 
    c. Explain why (in the report for b.) there are two different requests to pizza/index.php: the first is from the form submission, but what is the second from?