Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ecommerce_cart.inc
1 <?php
17 require_once SQ_PACKAGES_PATH.'/cms/listing_engine/listing_engine.inc';
18 require_once SQ_PACKAGES_PATH.'/ecommerce/lib/ecommerce_cart_processor.inc';
19 
20 define('SQ_CART_PRESET_QUANTITY', 'Quantity');
21 define('SQ_CART_PRESET_REMOVE', 'Remove');
22 
23 
38 {
39 
40 
46  var $_cart = NULL;
47 
48 
53  var $insufficient_quantities = FALSE;
54 
55 
60  var $insufficient_quantity_assets = NULL;
61 
62 
71  function __construct($assetid=0)
72  {
73  parent::__construct($assetid);
74 
75  }//end constructor
76 
77 
86  function _createBodycopies()
87  {
88  $GLOBALS['SQ_SYSTEM']->am->includeAsset('bodycopy');
89  $asset = new Bodycopy();
90  $copy_link = Array('asset' => &$this, 'value' => 'page_contents' ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
91  $asset->setAttrValue('name', 'Page Contents');
92  return $asset->create($copy_link);
93 
94  }//end _createBodycopies()
95 
96 
103  function &_getCart()
104  {
105  if (is_null($this->_cart)) {
106  $cart = new Ecommerce_Cart_Processor($this->attr('ecommerce_checkout_id'));
107 
108  if ($this->attr('use_local_cart')) {
109  $cart->setCartContainer($_SESSION['sq_local_cart_contents']['cart_contents']);
110  }
111 
112  $this->_cart = $cart;
113  }
114 
115  return $this->_cart;
116 
117  }//end _getCart()
118 
119 
138  function getAssetList()
139  {
140  $cart =& $this->_getCart();
141  $cart_contents = $cart->getCart();
142 
143  $asset_list = Array();
144 
145  $group_by = $this->attr('group_by');
146 
147  foreach ($cart_contents as $product_assetid => $product_info) {
148  $product_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($product_assetid);
149  if (!empty($product_asset)) {
150  if ($group_by == 'letter') {
151  $asset_list[$product_assetid] = Array( 0 => Array(
152  'type_code' => $product_asset->type(),
153  'first_letter' => substr($product_asset->attr('name'), 0, 1),
154  )
155  );
156  } else {
157  $asset_list[$product_assetid] = Array( 0 => Array(
158  'type_code' => $product_asset->type()
159  )
160  );
161  }
162  }
163  }
164 
165  if (empty($asset_list)) $asset_list = '';
166 
167  return $asset_list;
168 
169  }//end getAssetList()
170 
171 
179  function _getAllowedLinks()
180  {
181  $page_links = parent::_getAllowedLinks();
182  $page_links[SQ_LINK_TYPE_1]['folder'] = Array('card' => 'M');
183  $page_links[SQ_LINK_TYPE_1]['product'] = Array('card' => 'M');
184  $page_links[SQ_LINK_TYPE_2]['bodycopy'] = Array('card' => 'M');
185  return $page_links;
186 
187  }//end _getAllowedLinks()
188 
189 
200  protected function _getName($short_name=FALSE, $contextid=NULL)
201  {
202  // No context specified, using the current context
203  if ($contextid === NULL) {
204  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
205  }//end if
206 
207  // Obtain the attribute value for Name from the specified Context
208  $attr = ($short_name) ? 'short_name' : 'name';
209  $values = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName($attr, $this->type(), Array($this->id), $contextid);
210  if (empty($values) === TRUE) {
211  return parent::_getName($short_name, $contextid);
212  } else {
213  return $values[$this->id];
214  }
215 
216  }//end _getName()
217 
218 
225  function printFrontend()
226  {
227  // Tie the process and following paint together using db2 in order to
228  // avoid possible replication slowdown on db1
229  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
230 
231  $this->processAssetSelections();
232  parent::printFrontend();
233 
234  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
235 
236  }//end printFrontend()
237 
238 
245  function getRootNodes()
246  {
247  return Array();
248 
249  }//end getRootNodes()
250 
251 
258  function printContents()
259  {
260  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'page_contents');
261  if (empty($bodycopy_link)) return FALSE;
262 
263  $format_bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_link['minorid'], $bodycopy_link['minor_type_code']);
264  if (is_null($format_bodycopy)) return FALSE;
265 
266  require_once SQ_FUDGE_PATH.'/general/text.inc';
267  $keywords = $format_bodycopy->getKeywords();
268  $replacements = Array();
269 
270  if (!in_array('asset_listing', $keywords)) {
271  // there is no asset listing keyword in the contents, so we dont
272  // need to do all the extra processing for the listing
273  $format_bodycopy->printBody();
274  return;
275  }
276 
277  // the children here will refer to the contents of this cart
278  $children = $this->getAssetList();
279  $num_kids = count($children);
280  $this->filterAssetList($children);
281 
282  // the list is sorted and positions set, now we can split to groups
283  if ($this->attr('group_by') == 'grouped') {
284  $this->groupAssetsRecursively($this->attr('asset_grouping'), $children, $children);
285  $this->sortGroups($this->attr('asset_grouping'), $children, $children);
286  }
287 
288  foreach ($keywords as $word) {
289  $replacements[$word] = $this->getKeywordReplacement($word);
290  }
291 
292  // get any extra keyword replacements from this asset
293  $replacements = $this->getContentsKeywordReplacements($keywords) + $replacements;
294 
295  if (!empty($this->_tmp['cart_updated'])) {
296  $replacements['cart_updated'] = $this->attr('cart_updated_text');
297  } else {
298  $replacements['cart_updated'] = '';
299  }
300 
301  $num_per_page = $this->_getNumPerPage();
302 
303  $asset_result_page_var = 'result_'.$this->id.'_result_page';
304  $generic_result_page_var = 'result_page';
305 
306  // have [assetid]_result_page take precedence over result_page
307  $result_page = 1;
308  if (isset($_REQUEST[$generic_result_page_var])) {
309  $result_page = (int)$_REQUEST[$generic_result_page_var];
310  }
311  if (isset($_REQUEST[$asset_result_page_var])) {
312  $result_page = (int)$_REQUEST[$asset_result_page_var];
313  }
314 
315  if ($result_page <= 0) $result_page = 1;
316 
317  // get our page chunk here
318  if (empty($children)) {
319  $replacements['asset_listing'] = $this->attr('no_items_text');
320  $replacements['next_page'] = '';
321  $replacements['previous_page'] = '';
322  $replacements['total_pages'] = 1;
323 
324  // page list is one page
325  $replacements['page_list'] = '1';
326  $global_contents = $replacements['asset_listing'];
327  $num_assets_showing = 0;
328  $num_kids = 0;
329  ?>
330  <script type="text/javascript">
331  <!--
332  select_list = [];
333  //-->
334  </script>
335  <?php
336  } else {
337  $todo =& $this->getChunk($children, $replacements, Array(), $result_page, $num_per_page);
338  $num_assets_showing = count($todo);
339 
340  ob_start();
341  $this->printAssetList($todo);
342  $global_contents = ob_get_contents();
343  ob_end_clean();
344  }
345 
346  // if we have any blank keywords, replace them with nothing
347  $global_contents = preg_replace('|%[^%\W]+%|', '', $global_contents);
348 
349  // cart must pass on to an ecommerce checkout
350  $checkout_id = $this->attr('ecommerce_checkout_id');
351  $checkout_cart_button = '';
352  $checkout_cart_href = '';
353  if (!empty($checkout_id) && !empty($children)) {
354  if (!$GLOBALS['SQ_SYSTEM']->am->assetExists($checkout_id)) {
355  trigger_localised_error('ECOM003', E_USER_WARNING, $checkout_id);
356  } else {
357  $checkout_cart_href = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($checkout_id);
358  ob_start();
359  ?><input type="button" onclick="location.href = '<?php echo addslashes($checkout_cart_href); ?>'" value="<?php echo $this->attr('checkout_text'); ?>" /><?php
360  $checkout_cart_button = ob_get_contents();
361  ob_end_clean();
362  }
363  }
364 
365 
366  // pagination
367 
368  if ($num_per_page > 0) {
369  $this->registerFormField('result_page');
370  hidden_field('result_page', $result_page);
371  }
372 
373  // line below see above
374  $replacements['checkout_cart_button'] = $checkout_cart_button;
375  $replacements['checkout_cart_href'] = $checkout_cart_href;
376 
377 
378  if (in_array('cart_update_button', $keywords)) {
379  $replacements['cart_update_button'] = $this->getSubmitButtonKeywordReplacement();
380  }
381  $replacements['asset_listing'] = $global_contents;
382  $replacements['asset_count'] = $num_kids;
383  $replacements['page_asset_count'] = $num_assets_showing;
384  $replacements['page_number'] = $result_page;
385  $replacements['first_asset_position'] = $num_per_page * ($result_page - 1) + 1;
386  $replacements['last_asset_position'] = min($num_kids, $num_per_page * $result_page);
387  $replacements['root_nodes'] = implode(',', $this->getRootNodes());
388 
389  $replacements['select_all_js_code'] = $this->getSelectAllJSCodeKeywordReplacement();
390 
391  // print the contents of page - replacing the global keywords
392  $format_bodycopy->setKeywordReplacements($replacements);
393 
394  ob_start();
395  if (!in_array('select_all_js_code', $keywords)) {
396  // there is no asset listing keyword in the contents, so we dont
397  // need to do all the extra processing for the listing
399  }
400  $format_bodycopy->printBody();
401  ob_end_flush();
402 
403  }//end printContents()
404 
405 
416  function getAssetSelectionValue($selection_name, $assetid)
417  {
418  $cart =& $this->_getCart();
419  $cart_contents = $cart->getCart();
420 
421  $selections = $this->attr('asset_selections');
422 
423  // if the hardcoded asset selection 'Quantity'
424  if ($selection_name == 'Quantity' && isset($cart_contents[$assetid]['quantity'])) {
425  return $cart_contents[$assetid]['quantity'];
426  }
427 
428  // fallback
429  return 0;
430 
431  }//end getAssetSelectionValue()
432 
433 
453  function _printAsset($assetid, $list_position, $keywords=Array())
454  {
455  ob_start();
456  parent::_printAsset($assetid, $list_position, $keywords);
457  $element_contents = ob_get_contents();
458  ob_end_clean();
459 
460  // summon the quantities
461  $cart =& $this->_getCart();
462  $cart_contents = $cart->getCart();
463 
464  $element_replacements = Array(
465  'product_quantity' => $cart_contents[$assetid]['quantity'],
466  );
467  $sub_total = $cart_contents[$assetid]['quantity'] * $cart_contents[$assetid]['price'];
468  $element_replacements['product_total'] = sprintf("%.{$this->attr('float_precision')}f", $sub_total);
469  $element_contents = replace_keywords($element_contents, $element_replacements);
470 
471  echo $element_contents;
472 
473  }//end _printAsset()
474 
475 
488  {
489  // We are only replacing them with their own replacement so they can be
490  // cached out like this, then score and result number can be added later
491  return Array(
492  'product_quantity' => '%product_quantity%',
493  'product_total' => '%product_total%',
494  );
495 
496  }//end getExtendedAssetKeywordReplacements()
497 
498 
508  {
509  $cart =& $this->_getCart();
510  $cart_contents = $cart->getCart();
511 
512  $parameter_map = $this->getAttribute('parameter_map');
513  $this->_tmp['cart_updated'] = FALSE;
514 
515  $add_items = $parameter_map->getParameterValue('add_item');
516  if (!empty($add_items)) {
517  foreach ($add_items as $assetid => $quantity) {
518  if (empty($assetid) || !strlen($quantity)) {
519  continue;
520  }
521 
522  if (isset($cart_contents[$assetid]['quantity'])) {
523  // we updated the quantity for the product
524  $amount = $cart_contents[$assetid]['quantity'];
525  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
526  if ($asset instanceof Donation) {
527  //if the asset is a Donation, remove the existing amount to use the update amount only. Do not confuse the users how much he has donated
528  $amount = 0;
529  }
530 
531  if ($cart->updateItem($assetid, $this->_validateItemUpdate(SQ_CART_PRESET_QUANTITY, $amount+$quantity, $assetid))) {
532  $this->_tmp['cart_updated'] = TRUE;
533  }
534 
535  } else if ($this->_validateItemUpdate(SQ_CART_PRESET_QUANTITY, $quantity, $assetid) == $quantity) {
536  // only add if it's not going to break our Quantity selection
537  if ($cart->addItem($assetid, $quantity)) {
538  $this->_tmp['cart_updated'] = TRUE;
539  }
540  }
541  }
542  }
543 
544  // internal, preset asset selections
545  // quantity (update)
546  if (isset($_REQUEST[SQ_CART_PRESET_QUANTITY])) {
547  $quantity = $_REQUEST[SQ_CART_PRESET_QUANTITY];
548  if (is_array($quantity)) {
549  // checkbox, textbox, or drop-down
550  $asset_list = $this->getAssetList();
551  foreach ($asset_list as $assetid => $type_code) {
552  $amount = 0;
553  if (isset($quantity[$assetid])) {
554  $amount = $quantity[$assetid];
555  }
556  if ($cart->updateItem($assetid, $this->_validateItemUpdate(SQ_CART_PRESET_QUANTITY, $amount, $assetid))) {
557  $this->_tmp['cart_updated'] = TRUE;
558  }
559  }
560  } else {
561  // radio
562  if ($cart->updateItem($quantity, $this->_validateItemUpdate(SQ_CART_PRESET_QUANTITY, 1, $assetid))) {
563  $this->_tmp['cart_updated'] = TRUE;
564  }
565  }
566  }
567 
568  // delete
569  if (isset($_REQUEST[SQ_CART_PRESET_REMOVE])) {
570  $remove = $_REQUEST[SQ_CART_PRESET_REMOVE];
571  if (is_array($remove)) {
572  // checkbox, textbox, or drop-down
573  foreach ($remove as $assetid => $amount) {
574  if ($cart->removeItem($assetid)) {
575  $this->_tmp['cart_updated'] = TRUE;
576  }
577  }
578  } else {
579  // radio
580  if ($cart->removeItem($remove)) {
581  $this->_tmp['cart_updated'] = TRUE;
582  }
583  }
584  }
585 
586  return TRUE;
587 
588  }//end processAssetSelections()
589 
590 
605  function _validateItemUpdate($selection_name, $quantity, $assetid)
606  {
607  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
608  if ($asset instanceof Donation) {
609  return $quantity;
610  }
611 
612  $selections = $this->attr('asset_selections');
613  $final_quantity = $quantity;
614 
615  // ensure we have enough items to add to the cart
616  $checkout_id = $this->attr('ecommerce_checkout_id');
617  if (!empty($checkout_id)) {
618  if (!$GLOBALS['SQ_SYSTEM']->am->assetExists($checkout_id)) {
619  trigger_localised_error('ECOM003', E_USER_WARNING, $checkout_id);
620  } else {
621  $checkout_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($checkout_id);
622  if ($checkout_asset->attr('enforce_quantities')) {
623  // determine which to use: metadata field or attribute name
624  $source = $checkout_asset->attr('quantity_selector');
625  switch ($source) {
626  case 'metadata':
627  $quantity_field = $checkout_asset->attr('quantity_field');
628  if (!empty($quantity_field)) {
629  $mm =& $GLOBALS['SQ_SYSTEM']->getMetadataManager();
630  $available_quantity = $mm->getMetadataValueByAssetid($assetid, $quantity_field);
631  if ($quantity > $available_quantity) {
632  $this->insufficient_quantities = TRUE;
633  // add name of asset to error list for displaying on frontend
634  $this->insufficient_quantity_assets[] = $asset->name;
635  $final_quantity = $available_quantity;
636  } else {
637  $this->insufficient_quantities = FALSE;
638  }
639  }
640  break;
641 
642  case 'attribute':
643  $quantity_attribute = $checkout_asset->attr('quantity_attribute');
644  if (!empty($quantity_attribute)) {
645  $available_quantity = $asset->attr($quantity_attribute);
646  if ($quantity > $available_quantity) {
647  $this->insufficient_quantities = TRUE;
648  // add name of asset to error list for displaying on frontend
649  $this->insufficient_quantity_assets[] = $asset->name;
650  $final_quantity = $available_quantity;
651  } else {
652  $this->insufficient_quantities = FALSE;
653  }
654  }
655  break;
656  }
657  if (is_array($this->insufficient_quantity_assets)) {
658  $this->insufficient_quantity_assets = array_unique($this->insufficient_quantity_assets);
659  }
660  }
661  }//end else
662  }//end if
663 
664  if (empty($selections[$selection_name]['options'])) {
665  return $final_quantity;
666  }
667  $options = $selections[$selection_name]['options'];
668  $restrict_range = FALSE;
669 
670  // allow_negative?
671  if (isset($options['allow_negative']) && !$options['allow_negative']) {
672  $restrict_range = TRUE;
673  $min = 0;
674 
675  // will always succeed
676  $max = NULL;
677  }
678 
679  // if restrict_range is turned on
680  if (isset($options['restrict_range']) && !empty($options['restrict_range']['enable'])) {
681  $restrict_range = TRUE;
682 
683  $defaults = $this->getAssetSelectionDefaults();
684  $min = array_get_index($options['restrict_range'], 'min', $defaults['options']['restrict_range']['min']);
685  $max = array_get_index($options['restrict_range'], 'max', $defaults['options']['restrict_range']['max']);
686  }
687 
688  // if this is a radio button or checkbox
689  if ($selections[$selection_name]['type'] == 'radio') {
690  $restrict_range = TRUE;
691  $min = 0;
692  $max = 1;
693  }
694 
695  if ($restrict_range) {
696  if ($quantity < $min) {
697  $final_quantity = $min;
698  } else if (!is_null($max) && $quantity > $max) {
699  $final_quantity = $max;
700  }
701  }
702 
703  return $final_quantity;
704 
705  }//end _validateItemUpdate()
706 
707 
722  {
723  $keywords = parent::getAvailableKeywords();
724 
725  $keywords['product_count'] = translate('ecom_cart_keyword_product_count');
726  $keywords['total_value'] = translate('ecom_cart_keyword_total_value');
727 
728  return $keywords;
729 
730  }//end getAvailableKeywords()
731 
732 
742  function onRequestKeywords(&$broadcaster, $vars=Array())
743  {
744  if (!isset($vars['keywords'])) return;
745  if (!($broadcaster instanceof Content_Type)) return;
746  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'bodycopy', TRUE);
747 
748  // the broadcaster could be our page contents bodycopy, in which case
749  // we want to supply our own keyword replacements
750  $page_contents_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'page_contents');
751  if (!empty($page_contents_link)) {
752  if (isset($parents[$page_contents_link['minorid']])) {
753  $vars['keywords'] += $this->getContentsKeywords();
754  return;
755  }
756  }
757 
758  // type folder links
759  $folder =& $this->getFolder();
760  $type_formats = Array();
761  if (!is_null($folder)) {
762  $type_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($folder->id, SQ_LINK_TYPE_2, 'bodycopy');
763  foreach ($type_links as $link_info) {
764  if (isset($parents[$link_info['minorid']])) {
765  $type_formats[] = $link_info['value'];
766  }
767  }
768  }
769 
770  $keywords = Array();
771  if (count($type_formats) > 0) {
772  $keywords['product_quantity'] = translate('ecom_cart_keyword_product_quantity');
773  $keywords['product_total'] = translate('ecom_cart_keyword_product_total');
774  }
775 
776  $vars['keywords'] = array_merge($vars['keywords'], $keywords);
777 
778  // if it's not the page contents bodycopy, it's something that we've
779  // inherited from the listing engine, so pass it on
780  parent::onRequestKeywords($broadcaster, $vars);
781 
782  }//end onRequestKeywords()
783 
784 
799  {
800  $keywords = parent::_getContentsKeywords();
801  $GLOBALS['SQ_SYSTEM']->lm->includeAssetStrings('page_asset_listing');
802 
803  $keywords += Array(
804  'cart_updated' => translate('ecom_cart_keyword_cart_updated'),
805  'product_count' => translate('ecom_cart_keyword_product_count'),
806  'total_value' => translate('ecom_cart_keyword_total_value'),
807  'cart_update_button' => translate('ecom_cart_keyword_cart_update_button'),
808  'checkout_cart_button' => translate('ecom_cart_keyword_checkout_cart_button'),
809  'checkout_cart_href' => translate('ecom_cart_keyword_checkout_cart_href'),
810  'insufficient_quantity_message' => translate('ecom_cart_keyword_insufficient_quantity_message'),
811  'asset_listing' => translate('cms_listing_asset_listing'),
812  'previous_page' => translate('cms_listing_previous_page_link'),
813  'next_page' => translate('cms_listing_next_page_link'),
814  'page_list' => translate('cms_listing_page_list'),
815  'page_number' => translate('cms_listing_page_number'),
816  'asset_count' => translate('cms_listing_asset_count'),
817  'page_asset_count' => translate('cms_listing_page_asset_count'),
818  'first_asset_position' => translate('cms_listing_first_asset_position'),
819  'last_asset_position' => translate('cms_listing_last_asset_position'),
820  );
821 
822  return $keywords;
823 
824  }//end getContentsKeywords()
825 
826 
834  {
835  if ($this->insufficient_quantities) {
836  $checkout_id = $this->attr('ecommerce_checkout_id');
837  if (!empty($checkout_id)) {
838  if (!$GLOBALS['SQ_SYSTEM']->am->assetExists($checkout_id)) {
839  trigger_localised_error('ECOM003', E_USER_WARNING, $checkout_id);
840  } else {
841  $checkout_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($checkout_id);
842  ob_start();
843  echo $checkout_asset->attr('quantity_message_cart');
844  echo '<ul>';
845  foreach ($this->insufficient_quantity_assets as $asset_name) {
846  echo '<li>';
847  echo $asset_name;
848  echo '</li>';
849  }
850  echo '</ul>';
851  return ob_get_clean();
852  }
853  }
854  }
855 
856  }//end getInsufficientQuantityMessageKeywordReplacement()
857 
858 
866  {
867  $cart =& $this->_getCart();
868 
869  return (string)$cart->getCount();
870 
871  }//end getProductCountKeywordReplacement()
872 
873 
881  {
882  $cart =& $this->_getCart();
883 
884  return sprintf("%.{$this->attr('float_precision')}f", $cart->getTotal());
885 
886  }//end getTotalValueKeywordReplacement()
887 
888 
896  {
897  return 'post';
898 
899  }//end _getFormSubmitMethod()
900 
901 
902 }//end class
903 
904 ?>