VbzCart/code/files/cart.php

Code
<?php /* PURPOSE: shopping cart stuff -- base HISTORY: 2012-04-17 extracted from shop.php

clsLibMgr::Add('vbz.cart-data',	KFP_LIB_VBZ.'/cart-data.php',__FILE__,__LINE__); clsLibMgr::AddClass('clsCartVars', 'vbz.cart-data'); clsLibMgr::Add('vbz.pages',	KFP_LIB_VBZ.'/pages.php',__FILE__,__LINE__); clsLibMgr::AddClass('clsVbzSkin_Standard','vbz.pages');

class clsPageCart extends clsVbzSkin_Standard { protected $objSess; protected $objCart;

/*     ACTION: Cart does not use URL data; all info passed via POST. So this implementation does nothing (but must be defined	so class is not abstract). */   protected function ParseInput {}

// process functions public function DoPreContent { $this->inCkout = FALSE;	// (2011-04-01) not sure why this is sometimes not getting set parent::DoPreContent; }   /*      INPUT: $iCaller is for debugging and is discarded; caller should pass __METHOD__ as the argument. */   public function GetObjects($iCaller) { $objSessions = $this->Sessions; $this->objSess = $objSessions->GetCurrent;	// get whatever session is currently applicable (existing or new) $this->objCart = $this->objSess->CartObj; $this->objCart->objSess = $this->objSess;	// used for logging }   public function Cart($iObj=NULL) { if (!is_null($iObj)) { $this->objCart = $iObj; }	return $this->objCart; }   protected function HandleInput { $this->GetObjects(__METHOD__); $this->objCart->CheckData;	// check for any form data (added items, recalculations, etc.)

$this->strSheet	= 'cart';	// cart stylesheet has a few different things in it

$this->strWikiPg	= ''; $this->strTitle	= 'Shopping Cart';	// Displayed title (page header) $this->strName	= 'shopping cart';	// HTML title $this->strTitleContext	= 'this is your'; // 'Tomb of the...'; $this->strHdrXtra	= ''; $this->strSideXtra	= ''; //'Cat #: '.$this->strReq; $this->strSheet	= KSQ_PAGE_CART;	// default }   protected function DoContent { echo $this->objCart->Render; } } // ShopCart class clsShopCarts extends clsTable { const TableName='shop_cart';

public function __construct($iDB) { parent::__construct($iDB); $this->Name(self::TableName); $this->KeyName('ID'); $this->ClassSng('clsShopCart'); $this->ActionKey('cart'); } } class clsShopCart extends clsDataSet { protected $objShipZone; protected $objCartData; private $arDataItem; protected $objOrder;

protected $hasDetails;	// customer details have been loaded? /*   protected $objDataTree; protected $objAddrShip; protected $objAddrCard; protected $objContDest; protected $objContCust; protected $objShip; protected $objCust;

public function __construct(clsDatabase $iDB=NULL, $iRes=NULL, array $iRow=NULL) { parent::__construct($iDB,$iRes,$iRow); $this->objShipZone = new clsShipZone; $this->objCartData = NULL; $this->hasDetails = FALSE; }   public function InitNew($iSess) { $this->ID = 0; $this->WhenCreated = NULL;	// not created until saved $this->WhenViewed = NULL; $this->WhenUpdated = NULL; $this->WhenOrdered = NULL; $this->ID_Sess = $iSess; $this->ID_Order = NULL; $this->ID_Cust = NULL; }   /*====      BLOCK: EVENT HANDLING HISTORY: 2011-03-27 copied from VbzAdminCustCard to VbzAdminCart Then moved from VbzAdminCart to clsShopCart */   protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function StartEvent(array $iArgs) { return $this->Log->StartEvent($iArgs); }   public function FinishEvent(array $iArgs=NULL) { return $this->Log->FinishEvent($iArgs); }   public function EventListing { return $this->Log->EventListing; }   // specialized event logging (deprecated) public function LogEvent($iCode,$iDescr,$iUser=NULL) { global $vgUserName;

$strUser = is_null($iUser)?$vgUserName:$iUser; $this->objDB->CartLog->Add($this,$iCode,$iDescr,$strUser); }   //====    /*      HISTORY: 2010-12-31 Created so placed orders do not get "stuck" in user's browser 2011-02-07 Doesn't work; same cart still comes up (though at least it generates a new order...	 but it pulls up all the same contact info) 2011-03-27 Changed flag from ID_Order to WhenOrdered OR WhenVoided, because we don't want to have to clear ID_Order anymore. Carts should retain their order ID. */   public function IsLocked { return $this->IsOrdered || $this->IsVoided; }   /*      RETURNS: TRUE if the cart has been converted to an order USED BY: $this->IsLocked and (something)->IsUsable HISTORY: 2011-03-27 written for improved handling of cart status at checkout */   public function IsOrdered { return !(is_null($this->WhenOrdered)); }   /*      RETURNS: TRUE if the cart has been discarded (voided) USED BY: $this->IsLocked and (something)->IsUsable HISTORY: 2011-03-27 written for improved handling of cart status at checkout */   public function IsVoided { return !(is_null($this->WhenVoided)); }   public function CartData { if (is_null($this->objCartData)) { $this->objCartData = new clsCartVars($this->Engine); $this->objCartData->LoadCart($this->KeyValue); }	return $this->objCartData; } /* // == GENERAL DATA UTILITY FUNCTIONS public function GetDataItem($iType) { global $sql;	// for debugging

if (isset($this->arDataItem[$iType])) { return $this->arDataItem[$iType]; } else { $sqlType = $this->objDB->SafeParam($iType); $sql = 'SELECT Val FROM '.KST_CART_DATA.' WHERE (ID_Cart='.$this->ID.') AND (Type="'.$sqlType.'");'; $objItem = $this->objDB->DataSet($sql); if ($objItem->HasRows) { $objItem->FirstRow; return $objItem->Val; } else { return NULL; }	}   }    public function PutDataItem($iType,$iVal,$iForce=FALSE) { global $sql;	// for debugging

$sqlType = $this->objDB->SafeParam($iType); $sqlFilt = '(ID_Cart='.$this->ID.') AND (Type="'.$iType.'")'; if ($iVal == '') { if ($iForce) { // delete the entry $sql = 'DELETE FROM '.KST_CART_DATA.' WHERE '.$sqlFilt; $ok = $this->objDB->Exec($sql); return $ok; } else { return FALSE; }	 } else { $sqlVal = $this->objDB->SafeParam($iVal); // check to see if item exists (UPDATE) or not (INSERT): $objRows = $this->objDB->DataSet('SELECT Val FROM '.KST_CART_DATA.' WHERE '.$sqlFilt); $qrows = $objRows->RowCount; if ($qrows == 0) { $sql = 'INSERT INTO '.KST_CART_DATA.' (ID_Cart,Type,Val) VALUES('.$this->ID.','.$iType.',"'.$sqlVal.'");'; $ok = $this->objDB->Exec($sql); } elseif ($qrows == 1) { $sql = 'UPDATE '.KST_CART_DATA.' SET Val="'.$sqlVal.'" WHERE '.$sqlFilt.';'; $ok = $this->objDB->Exec($sql); } else { // the db should never let this happen since ID_Cart+Type is the primary key, but leaving in as a sanity check for now. $this->objDB->LogEvent('cart.data.write','type='.$iType.' val='.$sqlVal,$qrows.' rows match: too many','DUP',TRUE,TRUE); $ok = FALSE; }	     return $ok; }   }    public function DataItem($iType,$iVal=NULL,$iForce=FALSE) { if ($this->HasCart) { if (is_null($iVal)) { return $this->GetDataItem($iType); } else { return $this->PutDataItem($iType,$iVal,$iForce); }	} else { return NULL; }   } // == STATUS public function HasCart { return $this->IsCreated;	// may use different criteria later on   } public function HasSession { $ok = FALSE; if ($this->HasField('ID_Sess')) { if ($this->ID_Sess>0) { $ok = TRUE; }	}	return $ok; }   public function Session { if ($this->HasSession) { $objSessions = $this->objDB->Sessions; $objSess = $objSessions->GetItem($this->ID_Sess); return $objSess; } else { return NULL; }   }    // DEPRECATED - use OrderObj public function Order { return $this->OrderObj; }   /*      RETURNS: Order object */   public function OrderObj { $doGet = TRUE; if (isset($this->objOrder)) { if ($this->objOrder->ID == $this->ID_Order) { $doGet = FALSE; }	}	if ($doGet) { $this->objOrder = $this->objDB->Orders->GetItem($this->ID_Order); }	return $this->objOrder; }   public function HasLines { $objLines = $this->GetLines; if (is_null($objLines)) { return FALSE; } else { return $objLines->hasRows; }   }    public function LineCount { if ($this->HasLines) { return $this->objLines->RowCount; } else { return 0; }   }    public function GetLines($iRefresh=TRUE) { if ($iRefresh || (!isset($this->objLines))) { if ($this->IsCreated) { //$this->objLines = $this->objDB->CartLines->GetData('(ID_Cart='.$this->ID.') AND (Qty>0)','clsShopCartLine'); $this->objLines = $this->objDB->CartLines->GetData('(ID_Cart='.$this->ID.') AND (Qty>0)'); } else { $this->objLines = NULL; }	}	return $this->objLines; }   public function IsCreated { return ($this->ID > 0); //return !is_null($this->ID); //return $this->hasField('ID') || isset($this->ID) }   /*      RETURNS: TRUE iff customer has any known email addresses public function HasEmail { $isShipCard = $this->DataItem(KSI_SHIP_IS_CARD); $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF); // $objCart->ContCustObj->Email->Value if ($isShipSelf) { return $this->ContCustObj->HasEmail; }   public function EmailObj { } // == FORM HANDLING STUFF public function CheckData { // check for buttons $doCheckout = isset($_POST['finish']); $isCart = (isset($_POST['recalc']) || $doCheckout); $isZoneSet = FALSE; // check for specific actions if (isset($_GET['action'])) { $strDo = $_GET['action']; switch ($strDo) { case 'del': $intItem = 0+$_GET['item']; $this->GetLines; $this->objLines->Update(array('Qty'=>0),'ID_Item='.$intItem); $this->LogEvent('del','deleting from cart: ID '.$intItem); break; case 'delcart'; $this->LogEvent('clr','voiding cart'); $this->ID = -1; $this->objSess->DropCart; break; }	} else { foreach ($_POST as $key => $val) { // check for added items: if (substr($key,0,4) == 'qty-') { if (($val != '') && ($val != 0)) { $sqlCatNum = $this->objDB->SafeParam(substr($key,4)); if ($isCart) { // zero out all items, so only items in visible cart will be retained: $this->ZeroAll; }			$this->AddItem($sqlCatNum,$val); }		} elseif ($key == KSF_SHIP_ZONE) { //		   $custShipZone	= $this->GetFormItem(KSF_SHIP_ZONE); $custShipZone	= $val; $this->DataItem(KSI_SHIP_ZONE,$custShipZone); $this->objShipZone->Abbr($custShipZone); $isZoneSet = TRUE; }	   }	}	if (!$isZoneSet) { // reload the shipping zone if we don't already know it	   $this->objShipZone->Abbr($this->CartData->ShipZone); }	if ($doCheckout) { $this->LogEvent('ck1','going to checkout'); $objSess = $this->Session; //http_redirect(KWP_CHKOUT,array(KS_VBZCART_SESSION_KEY => $objSess->SessKey)); //http_redirect(KWP_CHKOUT.'?'.KS_VBZCART_SESSION_KEY.'='.$objSess->SessKey); http_redirect(KWP_CHKOUT); //	   http_redirect('https://ssl.vbz.net/phpinfo.php'); $this->LogEvent('ck2','sent redirect to checkout'); }   }    public function ZeroAll { $this->Update(array('Qty'=>0),'ID_Cart='.$this->ID); }   public function AddItem($iCatNum,$iQty) { $this->Build;	// make sure there's a record for the cart, get ID	$objCartLines = $this->objDB->CartLines; $objCartLines->Add($this->ID,$iCatNum,$iQty); $this->LogEvent('add','adding to cart: cat# '.$iCatNum.' qty '.$iQty); }   /*-      ACTION: * make sure there is a cart record * update the quantity, if there is one */   public function Build { $id = $this->ID; if (empty($id)) { $this->Create; }   }    public function Create { $sql = 'INSERT INTO `'.clsShopCarts::TableName.'` (WhenCreated,ID_Sess)'. 'VALUES(NOW,'.$this->ID_Sess.');'; $this->objDB->Exec($sql); $this->ID = $this->objDB->NewID('carts.create'); $objSess = $this->objDB->Sessions->GetCurrent; if (!is_object($objSess->Table)) { throw new exception('Session object has no table for Cart ID='.$this->Value('ID')); }	$objSess->SetCart($this->ID); }   public function RenderHdr { $out = "\n".''; $out .= "\n  "; $out .= "\n"; $out .= "\n \n"; return $out; }   public function RenderFtr { return KHT_CART_FTR; }   /*      ACTION: Render the receipt in HTML Shows the order as generated from *cart* data, not what's in the order record. ...except for the order number. HISTORY: 2011-03-27 adapting this from clsOrder::RenderReceipt */   public function RenderReceipt { $out = NULL;

$objCart = $this; $objOrd = $this->OrderObj;

// load contact data assert('is_object($objOrd);'); if (($objOrd->ID == 0) || ($objCart->ID == 0)) { throw new exception('Receipt has missing object: Order ID='.$this->Value('ID_Order').', Cart ID='.$objCart->KeyValue); }	$objCart->GetDetailObjs; $objPay = $objCart->PersonCustObj->Payment; $objAddrCard = $objCart->AddrCardObj; // the next line is a kluge which only works as long as payment is always ccard // it's also not clear why GetDetailObjs isn't loading it properly $objPay->Node('addr', $objAddrCard);

$arVars = array(	 'ord.num'	=> $objOrd->Number,	  'timestamp'	=> date(KF_RCPT_TIMESTAMP),	  'cart.id'	=> $objCart->ID,	  'cart.detail'	=> $objCart->RenderConfirm,	  'ship.name'	=> $objCart->AddrShipObj->Name->Value,	  'ship.addr'	=> $objCart->AddrShipObj->AsText("\n "),	  'pay.name'	=> $objPay->Addr->Name->Value,	  'pay.spec'	=> $objPay->SafeDisplay,	  'email.short'	=> 'orders-'.date('Y').'@vbz.net'	  ); $objStrTplt = new clsStringTemplate_array(NULL,NULL,$arVars); $objStrTplt->MarkedValue(KHT_RCPT_TPLT); $out = ''; $out .= $objStrTplt->Replace; return $out; }   /*-      ACTION: Renders the order contents as plaintext, suitable for emailing */   public function RenderOrder_Text { /* NOT USED HERE $isShipCard = $this->DataItem(KSI_SHIP_IS_CARD); $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF); // copy any needed constants over to variables for parsing: $ksShipMsg	= KSF_SHIP_MESSAGE; $ksfCustCardNum = KSF_CUST_CARD_NUM; $ksfCustCardExp = KSF_CUST_CARD_EXP;

// get non-address field data: $strCardNum = $this->DataItem(KSI_CUST_CARD_NUM); $strCardExp = $this->DataItem(KSI_CUST_CARD_EXP); $strCustShipMsg = $this->DataItem(KSI_SHIP_MESSAGE); $ftCustShipMsg = wordwrap($strCustShipMsg);

$out = ''; $out .= "ITEMS ORDERED:\n";

$out .= $this->RenderCore_Text;

$this->doFixedCard = TRUE; $this->doFixedSelf = TRUE; $this->doFixedName = TRUE; $this->htmlBeforeAddress = ''; $this->htmlBeforeContact = '';

$out .= "\n\nSHIP TO:\n"; $out .= ' '.$this->AddrShipObj->Name->Value."\n"; $out .= ' '.$this->AddrShipObj->AsText("\n  "); $out .= "\n"; $out .= "\n Email: ".$this->ContDestObj->Email->Value; $out .= "\n Phone: ".$this->ContDestObj->Phone->Value; $out .= "\n\n "; if (empty($strCustShipMsg)) { $out .= "(No special instructions)"; } else { $out .= "Special Instructions:\n$ftCustShipMsg"; }	$out .= "\n\nPAYMENT:\n ".clsCustCards::SafeDescr_Long($strCardNum,$strCardExp)."\n"; $out .= ' '.$this->AddrCardObj->Name->Value."\n"; $out .= ' '.$this->AddrCardObj->AsText("\n  "); $out .= "\n"; $out .= "\n Email: ".$this->ContCustObj->Email->Value; $out .= "\n Phone: ".$this->ContCustObj->Phone->Value; return $out; }   public function RenderCore($iAsForm) { $strZone = $this->objShipZone->Abbr; $shipMinCost = 0;

$out = ' ' .' cat # ' .' description ' .' price each ' .' per-item s/h ea. ' .' qty. '	 .' purchase line total ' .' per-item s/h line total ' .' totals ' .' pkg s/h min. ' .' ';

$rsLine = $this->objLines; while ($rsLine->NextRow) { if ($iAsForm) { $out .= $rsLine->RenderForm($this); } else { $out .= $rsLine->RenderHtml($this); }	   if ($shipMinCost < $rsLine->ShipPkgDest) { $shipMinCost = $rsLine->ShipPkgDest; }	   $intQty = $rsLine->Qty; $this->CostTotalItem += $rsLine->CostItemQty; $this->CostTotalShip += $rsLine->CostShipQty; } // save official totals for order creation: // TO DO: are CostTotalItem and CostTotalShip referenced anywhere else? Make them local if not. //	But if they are, then why isn't shipMinCost also a field? $this->DataItem(KSI_ITEM_TOTAL,$this->CostTotalItem); $this->DataItem(KSI_PER_ITEM_TOTAL,$this->CostTotalShip); $this->DataItem(KSI_PER_PKG_TOTAL,$shipMinCost);

$strTotalMerch = FormatMoney($this->CostTotalItem); $strItemsShip = FormatMoney($this->CostTotalShip); $strTotalItems = FormatMoney($this->CostTotalItem + $this->CostTotalShip); $strShipZone = $this->objShipZone->Text; $strShipDesc = $strShipZone.' s/h package cost:'; $strShipPkg = FormatMoney($shipMinCost); $strTotalDesc = 'order total if shipping to '.$strShipZone.':'; $strOrdTotal = FormatMoney($this->CostTotalItem + $this->CostTotalShip + $shipMinCost);

$objSess = $this->Session; if ($iAsForm) { $htDelAll = ' [remove all] '; $htFirstTot = " $htDelAll totals: "; $htZoneCombo = 'Shipping destination: '.$this->objShipZone->ComboBox; } else { $htFirstTot = 'totals: '; $htZoneCombo = 'Shipping costs shown assume shipment to '.$this->objShipZone->Text.' address.'; }	$out .= <<<__END__ $htFirstTot $strTotalMerch $strItemsShip $strTotalItems &dArr; $strShipDesc $strShipPkg &crarr; $strTotalDesc $strOrdTotal $htZoneCombo __END__; $this->LogEvent('disp','displaying cart, zone '.$this->objShipZone->Abbr.' total $'.$strOrdTotal); return $out; }   /*-      RETURNS: The contents of the cart as text. Includes column headers and totals. USED BY: does anything actually use this, or was it intended for the email confirmation? */   public function RenderCore_Text { $abbrShipZone = $this->DataItem(KSI_SHIP_ZONE); $this->objShipZone->Abbr($abbrShipZone);

$shipMinCost = 0;

$strLineFmt = '%-16s |%6.2f |%6.2f |%4d |%7.2f |%10.2f |%13.2f';

if ($this->HasRows) { $hdr = "\n".sprintf('%-17s|%6s|%5s|%5s|%7s|%10s|%13s'	     ,'cat #'	      ,' $ ea. '	      ,' $ s/h '	      ,' qty '	      ,' $ sale '	      ,' $ s/h tot '	      ,' $ LINE TOTAL'); $out = $hdr; $out .= "\n".str_repeat('-',strlen($hdr)); $objLines = $this->GetLines; $dlrSaleTot = 0;	// total sale before shipping $dlrPItmTot = 0;	// per-item shipping total $dlrPPkgMax = 0;	// per-pkg shipping total while ($objLines->NextRow) { $objItem = $objLines->Item; $dlrShipItm = $objItem->ShipPriceItem($abbrShipZone); $dlrShipPkg = $objItem->ShipPricePkg($abbrShipZone);

$out .= $objLines->RenderText($this,$strLineFmt); if ($dlrPPkgMax < $dlrShipPkg) { $dlrPPkgMax = $dlrShipPkg; }		$intQty = $objLines->Qty; $dlrSaleTot += $objLines->PriceItem; $dlrPItmTot += $dlrShipItm*$intQty; }	   $out .= "\n".str_repeat('=',strlen($hdr));

$ftTotalMerch = sprintf('%6.2f',FormatMoney($dlrSaleTot)); $ftItemsShip = sprintf('%6.2f',FormatMoney($dlrPItmTot)); $ftTotalItems = sprintf('%6.2f',FormatMoney($dlrSaleTot + $dlrPItmTot)); $ftShipPkg = sprintf('%6.2f',FormatMoney($dlrPPkgMax)); //$ftTotalDesc = 'order total for shipping to '.$ftShipZone.':'; $ftOrdTotal = sprintf('%6.2f',FormatMoney($dlrSaleTot + $dlrPItmTot + $dlrPPkgMax));

// these items don't depend on cart contents, but there's no point in calculating them if the cart is empty: $ftShipZone = $this->objShipZone->Text; $ftShipDesc = $ftShipZone.' s/h package cost:';

//$objSess = $this->Session;

$ftZone = $this->objShipZone->Text; //$ftZone = $this->objShipZone->Abbr; //$ftZone = $abbrShipZone;

$out .= "\n" ."\n *         Sale: $ftTotalMerch" ."\n * S/H -" ."\n * per item sum: $ftItemsShip" ."\n * per  package: $ftShipPkg" ."\n========================" ."\n==== FINAL TOTAL: $ftOrdTotal" ."\n\nShipping Zone: $ftZone"; } else { $out = "\nSorry, we seem to have goofed: this cart appears to have no items in it."; $out .= "\nThe webmaster is being alerted to the problem."; }	return $out; }   public function Render { // return rendering of current contents of cart $ok = FALSE; if ($this->ID) { if ($this->HasLines) { $ok = TRUE; }	}

if ($ok) { $out = $this->RenderHdr; $out .= $this->RenderCore(TRUE); $out .= $this->RenderFtr; } else { if ($this->IsCreated) { if (is_null($this->objLines)) { $out = " Internal error - cart data not available! "; $this->LogEvent('disp',"can't display cart - no data!"); $this->objDB->Events->LogEvent('cart.render','','cart data unavailable','cdna',TRUE,TRUE); } else { $out = " Your cart is empty. "; $this->LogEvent('disp','displaying cart - empty; zone '.$this->objShipZone->Abbr); }	   } else { $out = " You have not put anything in your cart yet. "; $this->LogEvent('disp','displaying cart - nothing yet; zone '.$this->objShipZone->Abbr); }	}	return $out; }   /*    PURPOSE: Render cart for order confirmation page (read-only, no form controls) */   public function RenderConfirm { if ($this->HasLines) { $out = $this->RenderCore(FALSE); } else { // log error - you shouldn't be able to get to this point with an empty cart $txtParams = 'Cart ID='.$this->ID.' Order ID='.$this->ID_Order; $this->objDB->LogEvent('cart.renderconf',$txtParams,'cart empty at confirmation','cec',TRUE,TRUE);	// also sends email alert $out = ' INTERNAL ERROR : cart data has become separated from browser. The webmaster has been notified.'; }	return $out; } /*========== CUSTOMER DATA AMALGAMATION /*   public function AddrShipObj { if (empty($this->objAddrShip)) { $arFields = array(	     'name'	=> $this->SpawnName(KSI_ADDR_SHIP_NAME	,KSF_ADDR_SHIP_NAME),	      'street'	=> new clsCartField($this, KSI_ADDR_SHIP_STREET, KSF_ADDR_SHIP_STREET),	      'city'	=> new clsCartField($this, KSI_ADDR_SHIP_CITY	,KSF_ADDR_SHIP_CITY),	      'state'	=> new clsCartField($this, KSI_ADDR_SHIP_STATE	,KSF_ADDR_SHIP_STATE),	      'zip'	=> new clsCartField($this, KSI_ADDR_SHIP_ZIP	,KSF_ADDR_SHIP_ZIP),	      'country'	=> new clsCartField($this, KSI_ADDR_SHIP_COUNTRY,KSF_ADDR_SHIP_COUNTRY),	      'instruc'	=> new clsCartField($this, KSI_SHIP_MESSAGE	,KSF_SHIP_MESSAGE)	      ); $this->objAddrShip = $this->SpawnAddress($arFields); }	return $this->objAddrShip; }   public function AddrCardObj { if (empty($this->objAddrCard)) { $arFields = array(	     'name'	=> $this->SpawnName(KSI_ADDR_CARD_NAME	,KSF_CUST_CARD_NAME),	      'street'	=> new clsCartField($this, KSI_ADDR_CARD_STREET	,KSF_CUST_CARD_STREET),	      'city'	=> new clsCartField($this, KSI_ADDR_CARD_CITY	,KSF_CUST_CARD_CITY),	      'state'	=> new clsCartField($this, KSI_ADDR_CARD_STATE	,KSF_CUST_CARD_STATE),	      'zip'	=> new clsCartField($this, KSI_ADDR_CARD_ZIP	,KSF_CUST_CARD_ZIP),	      'country'	=> new clsCartField($this, KSI_ADDR_CARD_COUNTRY,KSF_CUST_CARD_COUNTRY),	      'instruc'	=> new clsCartField($this, NULL			,NULL)	      ); $this->objAddrCard = $this->SpawnAddress($arFields); }	return $this->objAddrCard; }   public function ContDestObj { if (empty($this->objContDest)) { $arFields = array(	     'email'	=> $this->SpawnEmail(KSI_CUST_SHIP_EMAIL	,KSF_CUST_SHIP_EMAIL),	      'phone'	=> $this->SpawnPhone(KSI_CUST_SHIP_PHONE	,KSF_CUST_SHIP_PHONE)	      ); $this->objContDest = $this->SpawnContact($arFields);	// blank object for rendering }	return $this->objContDest; }   public function ContCustObj_raw { if (empty($this->objContCust)) { $arFields = array(	     'email'	=> $this->SpawnEmail(KSI_CUST_PAY_EMAIL	,KSF_CUST_PAY_EMAIL),	      'phone'	=> $this->SpawnPhone(KSI_CUST_PAY_PHONE	,KSF_CUST_PAY_PHONE)	      ); $this->objContCust = $this->SpawnContact($arFields); }	return $this->objContCust; }   /*      RETURNS: Contact information for the customer. If the "shipping to myself" box was checked, then it returns the shipping contact information instead, since this is presumed to be the customer's contact information as well. */ /*   public function ContCustObj { //$isShipCard = $this->DataItem(KSI_SHIP_IS_CARD); $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF); if ($isShipSelf) { return $this->ContDestObj; } else { return $this->ContCustObj_raw; }   }    /*      METHOD: SpawnPerson ACTION: creates clsPerson object or descendant This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-29 created */ /*   public function SpawnPerson($iName,$iDescr) { return new clsPerson($iName,$iDescr); }   /*      METHOD: SpawnPayment ACTION: creates clsPayment object or descendant This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-29 created */ /*   public function SpawnPayment($iNodes=NULL) { return new clsPayment($iNodes); }   /*      METHOD: SpawnAddress ACTION: creates clsCartAddr object or descendant This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-29 created */ /*   public function SpawnAddress($iNodes=NULL) { return new clsCartAddr($iNodes); }   /*      METHOD: SpawnContact ACTION: creates clsCartContact object or descendant This lets us stub off admin functionality here and extend it later. The extra functionality may not actually be needed for this, but I went and created it anyway. (2011-12-15: yes, it was needed.) HISTORY: 2011-11-29 created */ /*   public function SpawnContact($iNodes=NULL) { return new clsCartContact($iNodes); }   /*      METHOD: SpawnEmail ACTION: creates object for handling cart email address data This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-29 created */ /*   public function SpawnEmail($iIndex, $iCtrlName) { return new clsCartField($this, $iIndex, $iCtrlName); }   /*      METHOD: SpawnPhone ACTION: creates object for handling cart phone number data This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-29 created */ /*   public function SpawnPhone($iIndex, $iCtrlName) { return new clsCartField($this, $iIndex, $iCtrlName); } /*	   $objDataTree->Node('person.ship',$this->objShip); $objDataTree->Node('person.cust',$this->objCust);
 * 1) get information for that destination type:

/*     METHOD: SpawnName ACTION: creates object for handling person-name data This lets us stub off admin functionality here and extend it later. HISTORY: 2011-11-30 created */ /*   public function SpawnName($iIndex, $iCtrlName) { return new clsCartField($this, $iIndex, $iCtrlName); }   /*      METHOD: clsShopCart->PersonCustObj USED BY: clsShopCart->GetDetailObjs, clsOrder->RenderReceipt HISTORY: 2010-09-12 Extracted from clsShopCart->GetDetailObjs so it can be used by clsOrder->RenderReceipt 2011-11-29 Now using SpawnPayment and SpawnPerson instead of creating directly with "new" */ /*   public function PersonCustObj { if (empty($this->objCust)) { $arFields = array(	     'num'		=> new clsCartField($this, KSI_CUST_CARD_NUM,	KSF_CUST_CARD_NUM),	      'exp'		=> new clsCartField($this, KSI_CUST_CARD_EXP,	KSF_CUST_CARD_EXP)	      ); $objPayment = $this->SpawnPayment($arFields); $this->objCust = $this->SpawnPerson('person.cust','buyer'); $this->objCust->Node('payment', $objPayment);	// the buyer always has the credit card }	return $this->objCust; }   /*-      METHOD: clsShopCart->GetDetailObjs FUTURE: rename to GetDataTree HISTORY: 2010-09-12 borrowed (to be moved?) from clsPageCkout 2011-11-27 the version in clsPageCkout has now been commented out 2011-11-29 using SpawnPerson instead of new clsPerson */ /*   public function GetDetailObjs { if (!$this->hasDetails) { $objAddrShip = $this->AddrShipObj; $objAddrCard = $this->AddrCardObj; $objContDest = $this->ContDestObj; $objContCust = $this->ContCustObj;

$objDataTree = new clsContactRoot($this->Engine);

$this->objShip = $this->SpawnPerson('person.ship','recipient'); $this->objCust = $this->PersonCustObj;

$objDataTree->NodeAdd($this->objShip); $objDataTree->NodeAdd($this->objCust); //echo $objDataTree->DumpHTML; die; $this->objDataTree = $objDataTree;

$objPayment = $this->objCust->Payment; if (is_null($objPayment)) { echo 'objCust is class '.get_class($this->objCust).' '; echo $this->objCust->DumpHTML; throw new exception('coding error'); }

$this->objShip->Node('contact', $objContDest);	// shipping information is always specified

$objContDest->Addr = $objAddrShip;	// shipping address

$this->custShipIsCard	= $this->DataItem(KSI_SHIP_IS_CARD); $this->custShipToSelf	= $this->DataItem(KSI_SHIP_TO_SELF);

if ($this->custShipIsCard) { $objPayment->Node('addr', $objAddrShip);	// use shipping address for card } else { $objPayment->Node('addr', $objAddrCard);	// use separate address for card }

$this->objShip->Node('name', $objAddrShip->NameNode);

// (2011-12-25) this section is tricky... it puts some of the key branches into the tree: if ($this->custShipToSelf) { // don't use separate person data; re-use buyer contact info plus shipping address

$this->objShip->Node('payment', $objPayment);	// the only buyer field the recipient doesn't have //$objContDest->Node('addr', $objAddrShip);			// shipping address $this->objShip->Node('contact', $objContDest); $objContDest->Node('addr', $objAddrShip);

$this->objCust = $this->objShip; } else { // buyer and recipient are different

$this->objShip->Node('contact', $objContDest); $objContDest->Node('addr', $objAddrShip);

$this->objCust->Node('contact', $objContCust); $this->objCust->Node('name', $objAddrCard->NameNode); }	   $this->hasDetails = TRUE; }	return $this->objDataTree; }   /*      ASSUMES: GetDetailObjs has been called */ /*   public function WhoCust { return $this->objCust; }   /*      ASSUMES: GetDetailObjs has been called */ /*   public function WhoShip { return $this->objShip; } }