session = $session; $this->instance = 'main'; } /** * Set the current cart instance * * @param string $instance Cart instance name * @return Cart */ public function instance($instance = null) { if(empty($instance)) throw new Exceptions\ShoppingcartInstanceException; $this->instance = $instance; // Return self so the method is chainable return $this; } /** * Add a row to the cart * * @param string|Array $id Unique ID of the item|Item formated as array|Array of items * @param string $name Name of the item * @param int $qty Item qty to add to the cart * @param float $price Price of one item * @param Array $options Array of additional options, such as 'size' or 'color' */ public function add($id, $name = null, $qty = null, $price = null, Array $options = array()) { // If the first parameter is an array we need to call the add() function again if(is_array($id)) { // And if it's not only an array, but a multidimensional array, we need to // recursively call the add function if($this->is_multi($id)) { foreach($id as $item) { $options = isset($item['options']) ? $item['options'] : array(); $this->addRow($item['id'], $item['name'], $item['qty'], $item['price'], $options); } return; } $options = isset($id['options']) ? $id['options'] : array(); return $this->addRow($id['id'], $id['name'], $id['qty'], $id['price'], $options); } return $this->addRow($id, $name, $qty, $price, $options); } /** * Add multiple rows to the cart * Maps to add() function * Will probably be removed in future versions * * @param Array $items An array of items to add, use array keys corresponding to the 'add' method's parameters */ public function addBatch(Array $items) { return $this->add($items); } /** * Update the quantity of one row of the cart * * @param string $rowId The rowid of the item you want to update * @param integer|Array $attribute New quantity of the item|Array of attributes to update * @return boolean */ public function update($rowId, $attribute) { if( ! $this->hasRowId($rowId)) throw new Exceptions\ShoppingcartInvalidRowIDException; if(is_array($attribute)) { return $this->updateAttribute($rowId, $attribute); } return $this->updateQty($rowId, $attribute); } /** * Remove a row from the cart * * @param string $rowId The rowid of the item * @return boolean */ public function remove($rowId) { if( ! $this->hasRowId($rowId)) throw new Exceptions\ShoppingcartInvalidRowIDException; $cart = $this->getContent(); $cart->forget($rowId); return $this->updateCart($cart); } /** * Get a row of the cart by its ID * * @param string $rowId The ID of the row to fetch * @return CartCollection */ public function get($rowId) { $cart = $this->getContent(); return ($cart->has($rowId)) ? $cart->get($rowId) : NULL; } /** * Get the cart content * * @return CartRowCollection */ public function content() { $cart = $this->getContent(); return (empty($cart)) ? NULL : $cart; } /** * Empty the cart * * @return boolean */ public function destroy() { return $this->updateCart(NULL); } /** * Get the price total * * @return float */ public function total() { $total = 0; $cart = $this->getContent(); if(empty($cart)) { return $total; } foreach($cart AS $row) { $total += $row->subtotal; } return $total; } /** * Get the number of items in the cart * * @param boolean $totalItems Get all the items (when false, will return the number of rows) * @return int */ public function count($totalItems = true) { $cart = $this->getContent(); if( ! $totalItems) { return $cart->count(); } $count = 0; foreach($cart AS $row) { $count += $row->qty; } return $count; } /** * Search if the cart has a item * * @param Array $search An array with the item ID and optional options * @return Array|boolean */ public function search(Array $search) { foreach($this->getContent() as $item) { $found = $item->search($search); if($found) { $rows[] = $item->rowid; } } return (empty($rows)) ? false : $rows; } /** * Add row to the cart * * @param string $id Unique ID of the item * @param string $name Name of the item * @param int $qty Item qty to add to the cart * @param float $price Price of one item * @param Array $options Array of additional options, such as 'size' or 'color' */ protected function addRow($id, $name, $qty, $price, Array $options = array()) { if(empty($id) || empty($name) || empty($qty) || empty($price)) { throw new Exceptions\ShoppingcartInvalidItemException; } if( ! is_numeric($qty)) { throw new Exceptions\ShoppingcartInvalidQtyException; } if( ! is_numeric($price)) { throw new Exceptions\ShoppingcartInvalidPriceException; } $cart = $this->getContent(); $rowId = $this->generateRowId($id, $options); if($cart->has($rowId)) { $row = $cart->get($rowId); $cart = $this->updateRow($rowId, array('qty' => $row->qty + $qty)); } else { $cart = $this->createRow($rowId, $id, $name, $qty, $price, $options); } return $this->updateCart($cart); } /** * Generate a unique id for the new row * * @param string $id Unique ID of the item * @param Array $options Array of additional options, such as 'size' or 'color' * @return boolean */ protected function generateRowId($id, $options) { ksort($options); return md5($id . serialize($options)); } /** * Check if a rowid exists in the current cart instance * * @param string $id Unique ID of the item * @return boolean */ protected function hasRowId($rowId) { return $this->getContent()->has($rowId); } /** * Update the cart * * @param CartCollection $cart The new cart content * @return void */ protected function updateCart($cart) { return $this->session->put($this->getInstance(), $cart); } /** * Get the carts content, if there is no cart content set yet, return a new empty Collection * * @return Illuminate\Support\Collection */ protected function getContent() { $content = ($this->session->has($this->getInstance())) ? $this->session->get($this->getInstance()) : new CartCollection; return $content; } /** * Get the current cart instance * * @return string */ protected function getInstance() { return 'cart.' . $this->instance; } /** * Update a row if the rowId already exists * * @param string $rowId The ID of the row to update * @param integer $qty The quantity to add to the row * @return Collection */ protected function updateRow($rowId, $attributes) { $cart = $this->getContent(); $row = $cart->get($rowId); foreach($attributes as $key => $value) { if($key == 'options') { $options = $row->options->merge($value); $row->put($key, $options); } else { $row->put($key, $value); } } if( ! is_null(array_keys($attributes, array('qty', 'price')))) { $row->put('subtotal', $row->qty * $row->price); } $cart->put($rowId, $row); return $cart; } /** * Create a new row Object * * @param string $rowId The ID of the new row * @param string $id Unique ID of the item * @param string $name Name of the item * @param int $qty Item qty to add to the cart * @param float $price Price of one item * @param Array $options Array of additional options, such as 'size' or 'color' * @return Collection */ protected function createRow($rowId, $id, $name, $qty, $price, $options) { $cart = $this->getContent(); $newRow = new CartRowCollection(array( 'rowid' => $rowId, 'id' => $id, 'name' => $name, 'qty' => $qty, 'price' => $price, 'options' => new CartRowOptionsCollection($options), 'subtotal' => $qty * $price )); $cart->put($rowId, $newRow); return $cart; } /** * Update the quantity of a row * * @param string $rowId The ID of the row * @param int $qty The qty to add * @return CartCollection */ protected function updateQty($rowId, $qty) { if($qty == 0) { return $this->remove($rowId); } return $this->updateRow($rowId, array('qty' => $qty)); } /** * Update an attribute of the row * * @param string $rowId The ID of the row * @param Array $attributes An array of attributes to update * @return CartCollection */ protected function updateAttribute($rowId, $attributes) { return $this->updateRow($rowId, $attributes); } /** * Check if the array is a multidimensional array * * @param Array $array The array to check * @return boolean */ protected function is_multi(Array $array) { $first = array_shift($array); return is_array($first); } }