* @license PHP License * @package WB * @subpackage base */ WBClass::load('WBShop' , 'WBShop_Config'); /** * Shopping Cart * * Manage multiple shopping carts for each user. Logged in users may load, store etc. carts, * Anonymous user have onle ony cart in session. * * @todo respect namespace * @version 0.5.0 * @package WB * @subpackage base */ class WBShop_Cart extends WBStdClass { /** * Shop config * @var WBShop_Config */ private $sc; /** * Database access * @var WBDatasource_Table */ private $table; /** * user's id to work on behalf of * @var string */ private $uid = '0'; /** * id of current cart * @var string */ private $id = '__new'; /** * current cart * @var array */ private $cart = array(); /** * List of unsaved columns in cart * @param array */ private $cartDirty = array(); /** * list of items in cart * @var array */ private $item = null; /** * session storage * @var patSession_Storage */ private $sess; /** * @const session identifier for cart */ const SESS_CART = 'WBShop_Cart:cart'; /** * @const session identifier for cart items */ const SESS_ITEM = 'WBShop_Cart:item'; /** * cart filter * @var WBShop_Cart_Filter_Composite */ private $filter; /** * Cart config * @var WBConfig */ private $config; const CART_MODE_USER = 'user'; const CART_MODE_ADMIN = 'admin'; /** * Namespace for cart items * * Optional namespace to group cart items. Namespace will be used as a second identifier-column * besides the article-id * @var string */ private $namespace = ''; /** * Current cart mode * * Decide wheather to show other users carts * * @var string */ private $cartMode = self::CART_MODE_USER; /** * constructor * * Instantiate table object */ public function __construct($params = array()) { $params = array_merge( array( 'mode' => self::CART_MODE_USER ), $params ); $this->sc = WBShop_Config::singleton(); $this->table = WBClass::create('WBDatasource_Table'); $this->sess = WBClass::create('patSession'); $this->config = WBClass::create('WBConfig'); $this->config->load('shop/cart/config'); $this->cartMode = self::CART_MODE_USER; switch ($params['mode']) { case self::CART_MODE_ADMIN: $this->cartMode = self::CART_MODE_ADMIN; break; case self::CART_MODE_USER: default: break; } $this->startFilter(); } /** * Initialize empty cart * * Start with empty cart, but prefill some variables */ private function initCart() { if (empty($this->cart)) { $this->raw2cart(array()); } } /** * Cart configuration * * @return WBConfig */ public function getConfig() { return $this->config; } /** * Start cart filter(s) * * Create composite filter. Start all configured filter and set parameters. * Finally attach filter to composite. * * @throws WBException_Config */ private function startFilter() { // composite filter $this->filter = WBClass::create('WBShop_Cart_Filter_Composite'); // config of actual worker filters $filter = $this->config->get('cart/filter', array()); if (!is_array($filter) || empty($filter)) { return; } // start filter foreach ($filter as $f) { if (!is_array($f)) { WBClass::load('WBException_Config'); throw new WBException_Config('Invalid filter config!', 1, __CLASS__); } // create filter $o = WBClass::create('WBShop_Cart_Filter_' . $f['name']); if (!$o) { WBClass::load('WBException_Config'); throw new WBException_Config('Could not start filter: ' . $f['name'], 2, __CLASS__); } // configure filter if (is_array($f['params'])) { $o->setParams($f['params']); } // attach filter $this->filter->add($o); } } /** * set current cart user * * @param string $uid * @return WBShop_Cart */ public function setUser($uid) { $this->uid = $uid; $this->initCart(); $this->cart[$this->table->getIdentifier(WBShop::TABLE_USER)] = $uid; return $this; } /** * Get User's id of current cart * * @return string */ public function getUser() { $this->initCart(); return $this->cart[$this->table->getIdentifier(WBShop::TABLE_USER)]; } /** * Set namespace * * @param string */ public function setNamespace($ns = '') { $this->namespace = $ns; } /** * Get list of user's shopping carts * * Fetch user's carts with status. Optionally exclude one cart * * @param array $status * @param string $exclude * @return array */ public function getList($status = array('saved', 'active'), $exclude = null) { if (!$this->uid) { return array(); } $primary = $this->table->getIdentifier(WBShop::TABLE_CART); $clause = array(); $clause[] = array( 'field' => 'status', 'relation' => 'in', 'value' => $status ); if ($exclude) { $clause[] = array( 'field' => $primary, 'relation' => 'not', 'value' => $exclude ); } $uid = $this->uid; if (self::CART_MODE_ADMIN == $this->cartMode) { $uid = NULL; } // Jount items to fetch quantity $options = array(); $options['column'] = array(); $options['column'][] = '*'; $options['column'][] = array( 'table' => WBShop::TABLE_CARTITEM, 'field' => $primary, 'function' => 'count', 'as' => 'items' ); $options['column'][] = array( 'table' => WBShop::TABLE_CARTITEM, 'field' => 'quantity', 'function' => 'sum', 'as' => 'items_quantity' ); $options['join'] = array(); $options['join'][] = array( 'left' => 'left', 'table' => WBShop::TABLE_CARTITEM, 'using' => $primary ); $options['groupby'] = array(); $options['groupby'][] = array( 'field' => $primary ); return $this->table->get(WBShop::TABLE_CART, null, $uid, $clause, $options); } /** * Load active shopping cart * * Try to load active cart of current user. In case there is no current user, load empty * cart. * * @return WBShop_Cart */ public function loadActive() { $this->item = null; // load cart from session if ($this->sess->has(self::SESS_CART)) { $this->raw2cart(array($this->sess->get(self::SESS_CART))); $this->cart['status'] = 'active'; if ($this->uid) { $this->moveFromSession2Db(); } return $this; } // there is no user if (!$this->uid) { $this->raw2cart(array()); $this->cart['status'] = 'active'; return $this; } $clause = array(); $clause[] = array( 'field' => 'status', 'value' => 'active' ); $list = $this->table->get(WBShop::TABLE_CART, null, $this->uid, $clause); $this->raw2cart($list); $this->cart['status'] = 'active'; return $this; } /** * Load cart by id * * Try to load user's cart by cart id. * * @return WBShop_Cart * @param string $id * @param bool $public */ public function load($id, $public = false) { $this->item = null; $clause = array(); if ($public) { // load public cart $clause[] = array( 'field' => 'public', 'value' => 1 ); } else if (!$this->uid) { // there is no user $list = array(); if ($this->sess->has(self::SESS_CART)) { $list = array($this->sess->get(self::SESS_CART)); } $this->raw2cart($list); return $this; } else if (self::CART_MODE_ADMIN != $this->cartMode) { // add user id to clause $uPrimary = $this->table->getIdentifier(WBShop::TABLE_USER); $clause[] = array( 'field' => $uPrimary, 'value' => $this->uid ); } $list = $this->table->get(WBShop::TABLE_CART, $id, null, $clause); $this->raw2cart($list); return $this; } /** * Update cart's status * * Requires logged in user. * * @param string $status * @return bool true on success */ public function setStatus($status) { if (empty($status)) { return false; } if ('session' == $this->id) { $this->moveFromSession2Db(); } if (!$this->id || 'session' == $this->id || '__new' == $this->id) { return false; } $config = $this->config->get('cart/status/set/' . $status, array()); if (empty($config)) { return false; } // can do anything in admin-mode, still, there must be some kind of status-config if (self::CART_MODE_ADMIN == $this->cartMode) { if (!$this->updateStatus($status, array($this->cart['status']))) { return false; } if ('active' == $status) { $uid = $this->cart[$this->table->getIdentifier(WBShop::TABLE_USER)]; $this->deactivateOthers($this->id, $uid); } return true; } // user is required WBClass::load('WBUser'); $user = WBUser::getCurrent(); // required user if (isset($config['requiredgroup']) && !$user->isInGroup($config['requiredgroup'])) { return false; } // normalize array if (!isset($config['old'])) { $config['old'] = array(); } if (!is_array($config['old'])) { $config['old'] = array($config['old']); } if (!$this->updateStatus($status, $config['old'])) { return false; } if ('active' == $status) { $this->deactivateOthers($this->id, $this->uid); } return true; } /** * Get Status Form Name * * Select config for to-be-set-status and get form's name. If there is not form configured for the * status, an empty string will be returned * * @param string $status * @return string */ public function getRequiredForm($status) { return $this->config->get('cart/status/set/' . $status . '/form', ''); } /** * Merge other cart with this one * * Current cart's status must be "saved" * Append title and note to origins' title and note. * Set cart as public of both carts were public before. * * @todo Reconsider wheather to merge attributes instead of overriding them * @param WBShop_Cart * @return WBShop_Cart */ public function merge($cart) { $this->initCart(); $required = array( 'saved', 'active' ); if (!$this->updateStatus('saved', $required)) { $ex = array( 'code' => 1, 'class' => __CLASS__, 'msg' => 'Status "saved" / "active" required to merge into cart.' ); throw WBClass::create('WBException_Call', $ex); } $this->setTitle($this->getTitle() . ' ' . $cart->getTitle()); $this->setNote($this->getNote() . ' ' . $cart->getNote()); $this->setPublic($this->getPublic() & $cart->getPublic()); // override attributes $save = array(); $atts = $cart->get(); foreach ($this->filter->getMergeableCartAttributes() as $k) { if (!isset($atts[$k])) { continue; } $save[$k] = $atts[$k]; } $this->setAttributes($save); $src = $cart->getItems(); $des = $this->getItems(); $iPrimary = $this->table->getIdentifier($this->sc->getItemTable()); foreach ($src as $s) { $found = false; foreach ($des as $d) { // respect namespace if ($d['namespace'] != $s['namespace']) { continue; } if ($d[$iPrimary] == $s[$iPrimary]) { $found = true; $comment = $d['comment'] . $s['comment']; $this->setNamespace($s['namespace']); $this->set($s[$iPrimary], $d['quantity'] + $s['quantity'], $d['comment'] . $s['comment']); $save = array(); foreach ($this->filter->getMergeableItemAttributes() as $k) { if (!isset($s[$k])) { continue; } $save[$k] = $s[$k]; } $this->setItemAttributes($s[$iPrimary], $save); break; } } if ($found) { continue; } $this->setNamespace($s['namespace']); $this->set($s[$iPrimary], $s['quantity'], $s['comment']); $this->setItemAttributes($s[$iPrimary], $s); } return $this; } /** * Sat carts title attribute * * @param string $title * @return WBShop_Cart */ public function setTitle($title = '') { if (!$this->id) { return $this; } $this->initCart(); $this->cart['title'] = trim($title); $this->cartDirty['title'] = 1; return $this; } /** * Get cart's title string * * @return string */ public function getTitle() { $this->initCart(); return $this->cart['title']; } /** * Sat carts note attribute * * @param string $note * @return WBShop_Cart */ public function setNote($note = '') { if (!$this->id) { return $this; } $this->initCart(); $this->cart['note'] = trim($note); $this->cartDirty['note'] = 1; return $this; } /** * Get cart's note string * * @return string */ public function getNote() { $this->initCart(); return $this->cart['note']; } /** * Mark cart as public * * @param bool $public * @return WBShop_Cart */ public function setPublic($public = true) { if (!$this->id) { return $this; } $this->initCart(); $this->cart['public'] = intval($public); $this->cartDirty['public'] = 1; return $this; } /** * Tell whether cart is public * * @return bool */ public function getPublic() { $this->initCart(); return $this->cart['public']; } /** * Set cart's custom attributes * * @param array $data * @return WBShop_Cart */ public function setAttributes($data) { $this->initCart(); $primary = $this->table->getIdentifier(WBShop::TABLE_CART); $uPrimary = $this->table->getIdentifier(WBShop::TABLE_USER); $invalid = array( $primary, 'id', 'title', 'note', 'public', 'created', 'changed', 'status', $uPrimary ); foreach ($data as $k => $v) { if (in_array($k, $invalid)) { unset($data[$k]); continue; } if ($this->cart[$k] == $v) { unset($data[$k]); continue; } $this->cartDirty[$k] = 1; } $this->cart = array_merge($this->cart, $data); return $this; } /** * Set item's custom attributes * * @param string $item article id * @param array $data * @return WBShop_Cart */ public function setItemAttributes($item, $data) { $this->initCart(); $this->loadItems(); if (empty($this->item)) { return $this; } $primary = $this->table->getIdentifier(WBShop::TABLE_CART); $iPrimary = $this->table->getIdentifier($this->sc->getItemTable()); $invalid = array( $primary, $iPrimary, 'quantity', 'namespace', 'comment', 'created' ); foreach ($data as $k => $v) { if (in_array($k, $invalid)) { unset($data[$k]); } } foreach ($this->item as &$i) { // find article if ($i[$iPrimary] != $item) { continue; } // respect namespace if ($i['namespace'] != $this->namespace) { continue; } $i = array_merge($i, $data); if (!isset($i['__action'])) { $i['__action'] = '__update'; } break; } return $this; } /** * Delete cart * * Remove current cart. * * @return WBShop_Cart */ public function delete() { if (!$this->id) { return $this; } $reqiured = array( 'active', 'saved', 'shared', 'quoted', 'postponed', 'ordered' ); if (!$this->updateStatus('', $reqiured)) { return $this; } $cart = $this->get(); $cart['id'] = $this->id; $this->table->delete(WBShop::TABLE_CART, $this->id); $this->item = null; $this->cart = array(); $this->id = null; WBClass::load('WBEvent'); WBEvent::trigger('shop:cart:delete', 'Deleted shopping cart', $cart); return $this; } /** * Notify using Event-System * * Trigger event accoring to configuration in cart config. Resepect cart mode "user" * or "admin" to select available events. This protects against unauthorised usage. * * @see cart config: cart/notification * @param string $event */ public function notify($event) { if (empty($event)) { return; } if ('session' == $this->id || '__new' == $this->id) { return; } // check configuration $not = $this->config->get('cart/notification/' . $this->cartMode); if (empty($not) || !is_array($not)) { return; } // trigger event, if configured if (!isset($not[$event])) { return; } if (!isset($not[$event]['trigger'])) { return; } $cart = $this->cart; $cart['id'] = $this->id; WBClass::load('WBEvent'); WBEvent::trigger($not[$event]['trigger'], 'Notify shopping cart', $cart); } /** * Deactivate all other carts * * Set all carts to "saved" and spare the one with given id * * @param string $id * @param string $uid (user id) */ private function deactivateOthers($id, $uid) { $save = array( 'status' => 'saved' ); $clause = array(); $clause[] = array( 'field' => $this->table->getIdentifier(WBShop::TABLE_CART), 'relation' => 'not', 'value' => $id ); $clause[] = array( 'field' => $this->table->getIdentifier(WBShop::TABLE_USER), 'value' => $uid ); $clause[] = array( 'field' => 'status', 'value' => 'active' ); $this->table->save(WBShop::TABLE_CART, null, $save, $clause); } /** * Add article to cart * * Either add item or change quantity and or comment * * @param string $item article id * @param int $quantity * @param string $comment * @return WBShop_Cart */ public function add($item, $quantity = 1, $comment = '') { if (0 >= $quantity) { return $this; } if (!$this->isChangeable()) { return $this; } $this->loadItems(); $primary = $this->table->getIdentifier($this->sc->getItemTable()); // there are not items yet if (!is_array($this->item)) { return $this->set($item, $quantity, $comment); } // try to update existing item foreach ($this->item as &$i) { // find article if ($i[$primary] != $item) { continue; } // respect namespace if ($i['namespace'] != $this->namespace) { continue; } $quantity += $i['quantity']; $comment = $i['comment'] . $comment; return $this->set($item, $quantity, $comment); } // add new item return $this->set($item, $quantity, $comment); } /** * set article in cart * * Either add item or update quantity or comment * * @param string $item article id * @param int $quantity * @param string $comment * @return WBShop_Cart */ public function set($item, $quantity = 1, $comment = null) { if (!$this->isChangeable()) { return $this; } $this->loadItems(); $primary = $this->table->getIdentifier($this->sc->getItemTable()); if (is_array($this->item)) { foreach ($this->item as &$i) { // find article if ($i[$primary] != $item) { continue; } // respect namespace if ($i['namespace'] != $this->namespace) { continue; } $i['quantity'] = $quantity; if ($comment !== NULL) { $i['comment'] = $comment; } $i['__action'] = '__update'; if (1 > $i['quantity']) { $i['__action'] = '__delete'; } return $this; } } else { $this->item = array(); } $this->item[] = array( $primary => $item, 'quantity' => $quantity, 'comment' => $comment, 'namespace' => $this->namespace, '__action' => '__new' ); return $this; } /** * Remove item from cart * * @var string $item article id * @return WBShop_Cart */ public function remove($item) { if (!$this->isChangeable()) { return $this; } $this->loadItems(); $primary = $this->table->getIdentifier($this->sc->getItemTable()); if (!is_array($this->item)) { return $this; } foreach ($this->item as &$i) { // find article if ($i[$primary] != $item) { continue; } // respect namespace if ($i['namespace'] != $this->namespace) { continue; } $i['__action'] = '__delete'; return $this; } } /** * Save cart and all items * * Store current cart as well as all cart items in database. * @return WBShop_Cart */ public function save() { $this->initCart(); if ('session' == $this->id) { $this->saveInSession(); return $this; } $this->saveInDatabase(); // apply filter $this->filter->onCartLoad($this->cart); if (!is_array($this->item)) { return $this; } foreach ($this->item as &$i) { $this->filter->onItemLoad($i, $this->cart); } return $this; } /** * Store cart and items in session * * This is for anonymouse users */ private function saveInSession() { // save cart items $cPrimary = $this->table->getIdentifier(WBShop::TABLE_CART); $cart = $this->cart; $cart['id'] = 'session'; $cart[$cPrimary] = 'session'; $cart['status'] = 'active'; $this->filter->onCartSave($cart); $this->sess->set(self::SESS_CART, $cart); if (!$this->item) { $this->item = array(); } foreach ($this->item as $i => &$item) { if (!isset($item['__action'])) { continue; } switch ($item['__action']) { case '__update': case '__new': unset($item['__action']); $this->filter->onItemSave($item, $this->cart); break; case '__delete': unset($this->item[$i]); break; default: // this should never happen break; } } $this->item = array_values($this->item); $this->sess->set(self::SESS_ITEM, $this->item); } /** * Store cart and items in database * * Allow to move cart from session to database */ private function saveInDatabase() { $iPrimary = $this->table->getIdentifier($this->sc->getItemTable()); $cPrimary = $this->table->getIdentifier(WBShop::TABLE_CART); $uPrimary = $this->table->getIdentifier(WBShop::TABLE_USER); // save cart $save = $this->cart; $this->filter->onCartSave($save); $saveable = array( 'title', 'note', 'public', 'status', 'created', 'changed', $uPrimary ); $saveAll = false; if ('__new' == $this->id) { $saveAll = true; } $saveable = array_merge($saveable, $this->filter->getSaveableCartAttributes()); foreach ($save as $k => $v) { if (!$saveAll && !isset($this->cartDirty[$k])) { unset($save[$k]); continue; } if (in_array($k, $saveable)) { continue; } unset($save[$k]); } $this->cartDirty = array(); if (!empty($save)) { $this->id = $this->table->save(WBShop::TABLE_CART, $this->id, $save); } // save cart items $insert = array(); $delete = array(); if (!$this->item) { return; } $saveable = array( 'created', 'quantity', 'comment', 'namespace', $cPrimary, $iPrimary ); $saveable = array_merge($saveable, $this->filter->getSaveableItemAttributes()); foreach ($this->item as $i => &$item) { if ($saveAll) { $item['__action'] = '__new'; } if (!isset($item['__action'])) { continue; } switch ($item['__action']) { case '__new': $item[$cPrimary] = $this->id; $save = array(); $tmp = $item; $this->filter->onItemSave($tmp, $this->cart); foreach ($saveable as $k) { if (isset($tmp[$k])) { $save[$k] = $tmp[$k]; } else { $save[$k] = ''; $item[$k] = ''; } } $insert[] = $save; unset($item['__action']); break; case '__update': $clause = array(); $clause[] = array( 'field' => $iPrimary, 'value' => $item[$iPrimary] ); $clause[] = array( 'field' => 'namespace', 'value' => $item['namespace'] ); $clause[] = array( 'field' => $cPrimary, 'value' => $this->id ); $save = array(); $tmp = $item; $this->filter->onItemSave($tmp, $this->cart); foreach ($tmp as $k => $v) { if (in_array($k, $saveable)) { $save[$k] = $v; } } unset($item['__action']); $this->table->save(WBShop::TABLE_CARTITEM, null, $save, $clause); break; case '__delete': unset($item['__action']); $delete[] = array( 'type' => 'complex', 'bond' => 'AND', 'clause' => array( array( 'field' => $iPrimary, 'value' => $item[$iPrimary] ), array( 'field' => 'namespace', 'value' => $item['namespace'] ) ) ); unset($this->item[$i]); break; default: // this should never happen break; } } $this->item = array_values($this->item); if (!empty($delete)) { $clause = array(); $clause[] = array( 'field' => $cPrimary, 'value' => $this->id ); $clause[] = array( 'type' => 'complex', 'bond' => 'OR', 'clause' => $delete ); $this->table->delete(WBShop::TABLE_CARTITEM, null, null, $clause); } if( !empty($insert)) { $this->table->save(WBShop::TABLE_CARTITEM, '__new', $insert); } } /** * Move active cart from session to database * * Whenever a user is logs in, move the session based cart to databse * @param string $status */ private function moveFromSession2Db() { // move from session to DB if ('session' != $this->id) { return; } // prepare cart items $this->loadItems(); if (is_array($this->item)) { foreach ($this->item as &$item) { if (!isset($item['__action'])) { $item['__action'] = '__new'; } } } // prepare cart $this->id = '__new'; $uPrimary = $this->table->getIdentifier(WBShop::TABLE_USER); $this->cart[$uPrimary] = $this->uid; if (empty($this->uid)) { $this->cart[$uPrimary] = 0; } $this->cart['status'] = 'active'; // save active cart and deactivate others $this->saveInDatabase(); if ($this->uid) { $this->deactivateOthers($this->id, $this->uid); } // remove records from session $this->sess->clear(self::SESS_CART); $this->sess->clear(self::SESS_ITEM); } /** * Get id * * Get id of current cart */ public function getId() { $this->initCart(); return $this->id; } /** * Get cart data * * Get summarized information on current cart * * @return array */ public function get() { $this->initCart(); $this->loadItems(); $quantity = 0; if (is_array($this->item)) { foreach ($this->item as $i) { $quantity += $i['quantity']; } } $cart = $this->cart; $cart['id'] = $this->id; $cart['items'] = count($this->item); $cart['items_quantity'] = $quantity; return $cart; } /** * Fetch items in cart * * @return array $list of items */ public function getItems() { $this->initCart(); $list = array(); $this->loadItems(); if (!is_array($this->item)) { return $list; } foreach ($this->item as $i) { if (isset($i['__action']) && '__delete' == $i['__action']) { continue; } $list[] = $i; } return $list; } /** * Helper method to update status * * Check for old status and update record in database. In case * new status is empty, there will bo not update, just the check. * * @param string $new status * @param array $required old status * @return bool true on success */ private function updateStatus($new, $required) { $this->initCart(); if (!$this->id) { return false; } if (!in_array($this->cart['status'], $required)) { return false; } if (empty($new) || $this->cart['status'] == $new) { return true; } $save = array( 'status' => $new ); $this->table->save(WBShop::TABLE_CART, $this->id, $save); $this->cart['status'] = $new; $cart = $this->cart; $cart['id'] = $this->id; WBClass::load('WBEvent'); WBEvent::trigger('shop:cart:status:changed:' . $new, 'Changed status of shopping cart', $cart); return true; } /** * convert database result to cart * * @param array $list */ private function raw2cart($list) { $primary = $this->table->getIdentifier(WBShop::TABLE_CART); $uPrimary = $this->table->getIdentifier(WBShop::TABLE_USER); if (1 != count($list)) { $list = array( array( $primary => '__new', 'id' => '__new', 'title' => '', 'note' => '', 'public' => 0, 'created' => gmdate('Y-m-d H:i:s'), 'changed' => gmdate('Y-m-d H:i:s'), 'status' => 'saved', $uPrimary => $this->uid ) ); // prefill foreach ($this->filter->getSaveableCartAttributes() as $att) { if (isset($list[0][$att])) { continue; } $list[0][$att] = ''; } if (!$this->uid) { $list[0][$primary] = 'session'; } } $this->id = $list[0][$primary]; unset($list[0][$primary]); unset($list[0]['id']); $this->cart = $list[0]; $this->filter->onCartLoad($this->cart); } /** * load cart items * * Load list of items either from database or session */ private function loadItems() { if ($this->item) { return; } if ('session' == $this->id) { $this->item = $this->sess->get(self::SESS_ITEM); } else if ('__new' == $this->id) { $this->item = array(); } else { $this->item = $this->table->get(WBShop::TABLE_CARTITEM, null, $this->id); } if (!is_array($this->item)) { $this->item = array(); } foreach ($this->item as &$i) { $this->filter->onItemLoad($i, $this->cart); } } /** * Tell wheather items in cart may be changed * * @return bool */ private function isChangeable() { $allowed = array( 'active', 'saved', 'shared', 'quoted', 'shared', 'postponed' ); return in_array($this->cart['status'], $allowed); } }