/**
  * Add a product to the shopping cart via its ID number.
  *
  * @param Item Product Object you wish to add
  * @param Quantity number of this item to add
  * @param Customise array of custom options for this product, needs to be a
  *        multi dimensional array with each item of format:
  *          -  "Title" => (str)"Item title"
  *          -  "Value" => (str)"Item Value"
  *          -  "ModifyPrice" => (float)"Modification to price"
  */
 public function add(Product $add_item, $quantity = 1, $customise = array())
 {
     $added = false;
     $config = SiteConfig::current_site_config();
     // Make a string to match id's against ones already in the cart
     $product_key = $customise ? (int) $add_item->ID . ':' . base64_encode(serialize($customise)) : (int) $add_item->ID;
     // Check if the add call is trying to add an item already in the cart,
     // if so update the current quantity
     foreach ($this->items as $item) {
         // If an instance of this is already in the shopping basket, increase
         if ($item->Key == $product_key) {
             $this->update($item->Key, $item->Quantity + $quantity);
             $added = true;
         }
     }
     // If no update was sucessfull, update records
     if (!$added) {
         $custom_data = new ArrayList();
         $price = $add_item->Price;
         (double) ($tax_rate = $config->TaxRate);
         foreach ($customise as $custom_item) {
             $custom_data->add(new ArrayData(array('Title' => ucwords(str_replace(array('-', '_'), ' ', $custom_item["Title"])), 'Value' => $custom_item["Value"], 'ModifyPrice' => $custom_item['ModifyPrice'])));
             // If a customisation modifies price, adjust the price
             $price = (double) $price + (double) $custom_item['ModifyPrice'];
         }
         // Now, caclulate tax based on the new modified price and tax rate
         if ($tax_rate > 0) {
             (double) ($tax = $price / 100 * $tax_rate);
         } else {
             (double) ($tax = 0);
         }
         $item_to_add = ArrayData::create(array('Key' => $product_key, 'ProductID' => $add_item->ID, 'Title' => $add_item->Title, 'SKU' => $add_item->SKU, 'Description' => $add_item->Description, 'Weight' => $add_item->Weight, 'Price' => number_format($price, 2), 'Tax' => number_format($tax, 2), 'Customised' => $custom_data, 'Image' => $add_item->Images()->first(), 'Quantity' => $quantity));
         $this->extend("onBeforeAdd", $item_to_add);
         $this->items->add($item_to_add);
         $this->extend("onAfterAdd");
     }
 }
echo "Getting data for SKU=100...<br>";
$myProduct->SetSKU(100);
$myProduct->FetchData();
echo $myProduct->Name() . "<br>";
echo $myProduct->Description() . "<br>";
echo $myProduct->SKU() . "<br>";
echo $myProduct->Quantity() . "<br>";
echo $myProduct->Price() . "<br>";
echo $myProduct->Url() . "<br>";
echo "Is One Of A Kind: " . $myProduct->IsOneOfAKind() . "<br>";
echo "Success!<br><br>";
echo "Checking images for SKU=102...<br>";
$myProduct->SetSKU(102);
$myProduct->FetchData();
echo "Is One Of A Kind: " . $myProduct->IsOneOfAKind() . "<br>";
echo "Image count is: " . count($myProduct->Images()) . "<br>";
echo "First image URL is: " . $myProduct->Image()->Url() . "<br><br>";
echo "Checking images for SKU=109...<br>";
$myProduct->SetSKU(109);
$myProduct->FetchData();
echo "Is One Of A Kind: " . $myProduct->IsOneOfAKind() . "<br>";
echo "Image count is: " . count($myProduct->Images()) . "<br>";
echo "First image URL is: " . $myProduct->Image()->Url() . "<br><br>";
echo "Getting data for Url=hoop-earrings...<br>";
$myProduct->SetSKU(105);
$myProduct->FetchData();
echo "Is One Of A Kind: " . $myProduct->IsOneOfAKind() . "<br>";
echo $myProduct->Name() . "<br>";
echo $myProduct->Description() . "<br>";
echo $myProduct->SKU() . "<br>";
echo $myProduct->Quantity() . "<br>";