Code
<php><?php
/*
FILE: store.php
PURPOSE: VbzCart page-rendering classes
HISTORY:
2012-05-08 split off from store.php
if (!defined('LIBMGR')) {
require(KFP_LIB.'/libmgr.php');
}
clsLibMgr::Add('vbz.db', KFP_LIB_VBZ.'/store.php',__FILE__,__LINE__);
clsLibMgr::AddClass('clsVbzTable','vbz.db');
clsLibMgr::Add('rtext.html', KFP_LIB.'/rtext-html.php',__FILE__,__LINE__);
clsLibMgr::AddClass('clsRTDoc_HTML','rtext.html');
/*====
NOTES:
2011-02-02 This could use some rewriting. A lot of it is kind of pointless,
and other parts duplicate RichText objects.
class clsPageOutput_WHO_USES_THIS {
public $out;
private $isOdd;
public $inTbl;
private $fpTools;
private $fsLogo;
static public function SectionHeader($iTitle) {
return '
'.$iTitle.'
';
}
function __construct($ifpTools,$iLogoRel) {
$this->out = ;
$this->isOdd = false;
$this->inTbl = 0;
$this->fpTools = $ifpTools;
$this->fsLogo = $this->ImageSpec($iLogoRel);
}
/*
function Clear() {
$this->out = ;
}
function AddText($iText) {
$this->out .= $iText;
}
function SectionHdr($iTitle) { // this is specifically duplicated (where?)
$this->out .= '
'.$iTitle.'
';
return $this->out;
}
// eventually there needs to be a non-MediaWiki clsRichText, and these can go there
/*
public function TableOpen($iAttr=NULL) {
}
public function TableShut() {
}
public function TblRowOpen($iAttr=NULL,$iHdr=FALSE) {
}
public function TblRowShut() {
}
public function TblCell($iText,$iAttr=NULL) {
}
/* this duplicates RichText
function StartTable($iTitle) {
if ($iTitle) {
$this->SectionHdr($iTitle);
$this->out .= '
';
$this->inTbl++;
}
}
function RowStart($iClass=
) {
if ($iClass) {
$this->out .= '';
} else {
$this->out .= '';
}
}
function RowStop() {
$this->out .= '';
$this->isOdd = !$this->isOdd;
}
function ColAdd($iText) {
if ($this->isOdd) {
$cellOpen = '';
}
function EndTable() {
if ($this->inTbl) {
$this->out .= '
|
|
';
} else {
$cellOpen = ' | ';
}
$this->out .= $cellOpen.$iText.' |
';
$this->inTbl--;
}
return $this->out;
}
function ShowImgUnavail() {
$this->out .= '
<tbody></tbody>
<tbody></tbody>No Images Available for this item :-( |
|
';
return $this->out;
}
}
/* ===================
CLASS: clsVbzSkin
PURPOSE: Abstract skin class
Specifies all the bits that we'll want to have, but doesn't define them
Provides some basic support services, but no actual content (text or formatting)
abstract class clsVbzSkin {
protected $objDoc;
public function __construct() {
$this->objDoc = new clsRTDoc_HTML();
}
public function Doc() {
return $this->objDoc;
}
/*-----
USAGE: Normal main entry point -- should be called from index.php
*/
public function DoPage() {
try {
$this->DoPreContent();
$this->DoContent();
$this->DoPostContent();
} catch(exception $e) {
$this->DoEmailException($e);
}
}
/*----
HISTORY:
2011-03-31 added Page and Cookie to list of reported variables
*/
protected function DoEmailException(exception $e) {
$msg = $e->getMessage();
$arErr = array(
'descr' => $e->getMessage(),
'stack' => $e->getTraceAsString(),
'guest.addr' => $_SERVER['REMOTE_ADDR'],
'guest.agent' => $_SERVER['HTTP_USER_AGENT'],
'guest.ref' => NzArray($_SERVER,'HTTP_REFERER'),
'guest.page' => $_SERVER['REQUEST_URI'],
'guest.ckie' => NzArray($_SERVER,'HTTP_COOKIE'),
);
$out = $this->Message_toEmail_forException($arErr); // generate the message to email
$subj = $this->Subject_toEmail_forException($arErr);
$ok = mail(KS_TEXT_EMAIL_ADDR_ERROR,$subj,$out); // email the message
echo $this->Message_toShow_forException($msg); // display something for the guest
throw $e;
// FUTURE: log the error and whether the email was successful
}
abstract protected function Message_toEmail_forException(array $arErr);
abstract protected function Subject_toEmail_forException(array $arErr);
abstract protected function Message_toShow_forException($iMsg);
/*-----
ACTION: Displays everything *before* the main page contents
*/
protected function DoPreContent() {
$this->ParseInput();
$this->HandleInput();
$this->RenderHdrBlocks();
}
/*-----
ACTION: Displays everything *after* the main page contents
*/
protected function DoPostContent() {
$this->RenderFtrBlocks();
}
// ABSTRACT section //
/*-----
ACTION: Displays the main page contents
*/
protected abstract function DoContent();
/*-----
ACTION: Grab any expected input and interpret it
*/
protected abstract function ParseInput();
/*-----
ACTION: Take the parsed input and do any needed processing (e.g. looking up data)
*/
protected abstract function HandleInput();
/*-----
ACTION: Render any output that appears *before* the main content
*/
protected abstract function RenderHdrBlocks();
/*-----
ACTION: Render any output that appears *after* the main content
*/
protected abstract function RenderFtrBlocks();
/*-----
ACTION: Start a new section
*/
public abstract function NewSection($iName);
/*-----
ACTION: Open a table, with appropriate CSS class etc.
*/
public abstract function NewTable($iClass='content');
}
/* ===================
CLASS: clsVbzSkin_Standard
PURPOSE: Standard skin class
Will later be replaceable with other skins
abstract class clsVbzSkin_Standard extends clsVbzSkin {
private $objApp;
private $fpTools;
private $fsLogo;
public function __construct() {
parent::__construct();
$this->fpTools = KWP_TOOLS;
$this->fsLogo = KWP_LOGO_HEADER;
}
public function App(clsVbzApp $iApp=NULL) {
if (!is_null($iApp)) {
$this->objApp = $iApp;
}
return $this->objApp;
}
protected function Data() {
return $this->App()->Data();
}
public function NewSection($iTitle) {
$obj = $this->Doc()->NewSection($iTitle,'hdr-sub');
}
public function NewTable($iClass='content') {
$objDoc = $this->Doc();
$obj = $objDoc->NewTable();
$obj->ClassName($iClass);
return $obj;
}
protected function Message_toEmail_forException(array $arErr) {
$guest_ip = $arErr['guest.addr'];
$guest_br = $arErr['guest.agent'];
$guest_pg = $arErr['guest.page'];
$guest_rf = $arErr['guest.ref'];
$guest_ck = $arErr['guest.ckie'];
$out = 'Description: '.$arErr['descr'];
$out .= "\nStack trace:\n".$arErr['stack'];
$out .= <<<__END__
Client information:
- IP Addr : $guest_ip
- Browser : $guest_br
- Cur Page: $guest_pg
- Prv Page: $guest_rf
- Cookie : $guest_ck
__END__;
return $out;
}
protected function Subject_toEmail_forException(array $arErr) {
return 'error in VBZ from IP '.$arErr['guest.addr'];
}
protected function Message_toShow_forException($iMsg) {
$msg = $iMsg;
$out = <<<__END__
Ack! We seem to have a small problem here. (If it was a large problem, you wouldn't be seeing this message.)
The webmaster is being alerted about this.
Meanwhile, you might try reloading the page -- a lot of errors are transient,
which makes them hard to fix, which is why there are more of them than the other kind.
We apologize for the nuisance.
Error Message: $msg
__END__;
return $out;
}
protected function RenderHdrBlocks() {
$this->RenderHtmlStart();
$this->RenderContentHdr();
$this->DoSidebar();
}
protected function RenderFtrBlocks() {
$this->RenderContentFtr();
$this->RenderHtmlStop();
}
protected function RenderContentFtr() {
global $didPage,$fltStart;
echo '';
$this->DoSepBar();
echo '
';
$fltExecTime = microtime(true)-$fltStart;
$dat = getrusage();
$fltUserTime = $dat["ru_utime.tv_usec"]/1000000;
$strServer = $_SERVER['SERVER_SOFTWARE'];
echo $strServer.' .. ';
echo 'PHP '.phpversion().' .. Generated in '.$fltUserTime.' seconds (script execution '.$fltExecTime.' sec.) .. ';
$strWikiPg = $this->strWikiPg;
if ($strWikiPg) {
echo 'wiki: <a href="'.KWP_WIKI.kEmbeddedPagePrefix.$this->strWikiPg.'">'.$strWikiPg.'</a> .. ';
}
echo date('Y-m-d H:i:s');
echo ' |
';
echo '
';
$didPage = true;
}
protected function RenderHtmlStop() {
echo "\n</body>\n</html>";
}
// NEW METHODS for this class //
protected function DoSidebar() {
// $objCache = $this->CacheMgr();
// TO DO: these should be pulled from the [stats] table
/*
if ($objCache->dtNewest) {
$timeSidebarBuild=$objCache->dtNewest;
} else {
$timeSidebarBuild = NULL;
}
*/
$timeSidebarBuild = NULL;
$statsQtyTitlesAvail = 2245;
$statsQtyStockPieces = 1395;
$statsQtyStockItems = 753;
$statsQtyArtists = 136;
$statsQtyTopics = 1048;
//---------
echo '
';
}
protected function DoSepBar() {
echo $this->Render_HLine();
}
protected function ImageSpec($iFileName) {
return $this->fpTools.'/img'.$iFileName;
}
public function Render_HLine($iHeight=NULL) {
$htHt = is_null($iHeight)?
:('height='.$iHeight);
return '<img src="'.$this->ImageSpec('/bg/hlines/').'"'.$htHt.' alt="-----" width="100%">';
}
private function ToolbarItem($iURL,$iIcon,$iTitle,$iAlt) {
return '<a href="'.$iURL.'"><img border=0 src="'.$this->ImageSpec('/icons/'.$iIcon.'.050pxh.png').'" title="'.$iTitle.'" alt="'.$iAlt.'"></a>';
}
protected function DoToolbar() {
global $fpPages,$fwpCart;
echo $this->ToolbarItem($fpPages.'/','home',KS_STORE_NAME.' home page','home page');
echo $this->ToolbarItem($fpPages.'/search/','search','search page','search page');
echo $this->ToolbarItem($fwpCart,'cart','shopping cart','shopping cart');
echo $this->ToolbarItem(KWP_HELP_HOME,'help','help!','help');
}
// NEW METHODS for this class //
/*----
PURPOSE: Renders HTML inside <head></head> section
HISTORY:
2011-01-11 Created
*/
protected function RenderHtmlHeaderSection() {
$strTitle = KS_STORE_NAME.' - '.$this->strName;
$out = "\n<title>$strTitle</title>";
$arVars = array('sheet' => $this->strSheet);
$objStrTplt = new clsStringTemplate_array(NULL,NULL,$arVars);
$objStrTplt->MarkedValue(KHT_PAGE_STYLE);
$out .= $objStrTplt->Replace();
//$out .= KHT_PAGE_STYLE;
if (!empty($this->strName)) {
$ftName = ': '.htmlspecialchars($this->strName);
} else {
$ftName =
;
}
$strContent = KS_STORE_NAME_META.$ftName;
$out .= "\n<meta name=description content=\"$strContent\">";
return $out;
}
/*----
PURPOSE: Renders HTML up to beginning of BODY.
HISTORY:
2011-01-11 Extracted everything between <head> and </head> into RenderHtmlHeaderSection()
*/
protected function RenderHtmlStart() {
//$this->strCalcTitle = KS_STORE_NAME.' - '.$this->strName;
$out = KHT_PAGE_DOCTYPE;
$out .= "\n<html>\n<head>";
$out .= $this->RenderHtmlHeaderSection();
$out .= "\n</head>";
$out .= KHT_PAGE_BODY_TAG;
echo $out;
}
protected function RenderContentHdr() {
//$strWikiPg = $this->strWikiPg;
// begin content header
echo '
';
echo '';
// === LEFT HEADER: Title ===
echo '';
// === END LEFT HEADER ===
// === RIGHT HEADER: nav icons ===
echo '';
// === END RIGHT HEADER ===
echo "\n';
echo '<a href="'.KWP_HOME_ABS.'"><img align=left border=0 src="'.$this->fsLogo.'" title="'.KS_STORE_NAME.' home" alt="'.KS_SMALL_LOGO_ALT.'"></a>';
if ($this->strTitleContext) {
echo '<a href="/">'.KS_STORE_NAME.'</a>: '.$this->strTitleContext.' ';
}
echo ''.$this->strTitle.' | ';
$this->DoToolbar();
echo ' | \n |
";
}
}
/*%%%%
CLASS: clsVbzApp
PURPOSE: container for the chosen skin and database
*/
class clsVbzApp {
private $objSkin;
private $objData;
public function __constructor(clsVbzSkin $iSkin, clsVbzData $iData) {
$this->objSkin = $iSkin;
$this->objData = $iData;
}
public function Skin() {
return $this->objSkin;
}
public function Data() {
return $this->objData;
}
}
/* ===================
CLASS: clsVbzPage_Cat
PURPOSE: Handles display of catalog page types
TO DO: These classes still need more tidying -- see clsPageCat --
and still need a bit of work to allow user-choosable skins.
*/
abstract class clsVbzPage_Cat extends clsVbzSkin_Standard {
// helper objects
protected $db; // database - CHANGE TO PRIVATE
// query
protected $strReq; // requested page
// page definition
protected $strName; // short title: {item name} (goes into html title, prefixed with store name)
protected $strTitle; // longer, descriptive title: {"item name" by Supplier} (goes at top of page)
protected $strSheet; // name of style sheet to use (without the .css)
protected $strWikiPg; // name of wiki page to embed, if any (blank = suppress embedding)
protected $strTitleContext; // context of short title, in HTML: {Supplier: Department:} (goes above title, in small print)
protected $strHdrXtra; // any extra stuff (HTML) for the header
protected $strSideXtra; // any extra stuff for the sidebar
protected $lstTop; // stuff listed at the top of the sidebar
// calculated fields
// protected $strCalcTitle;
protected $strContText;
// flags set by wiki contents
protected $hideImgs;
public function __construct() {
parent::__construct();
$this->lstTop = new clsNavList();
}
protected function HandleInput() {
$this->strSheet = 'browse'; // default
}
/*-----
IMPLEMENTATION: Retrieves request from URL and parses it
URL data identifies page, keyed to cat_pages data
*/
protected function ParseInput() {
if (isset($_SERVER['PATH_INFO'])) {
$strReq = $_SERVER['PATH_INFO'];
} else {
$strReq =
;
}
$this->strReq = $strReq;
if (strrpos($strReq,'/')+1 < strlen($strReq)) {
$strRedir = KWP_CAT_REL.substr($strReq,1).'/';
header('Location: '.$strRedir);
exit; // retry with new URL
}
}
// DIFFERENT TYPES OF PAGES
protected function DoNotFound() {
$this->strWikiPg =
;
$this->strTitle = 'Unknown Page';
$this->strName = 'unknown title in catalog';
$this->strTitleContext = 'Tomb of the...';
$this->strHdrXtra =
;
$this->strSideXtra = '
Cat #: '.$this->strReq;
}
// UTILITY
protected function AddText($iText) {
$this->strContText .= $iText;
}
private function DoWikiContent() {
# WIKI CONTENTS
# $txtPage = GetEmbedPage('cat');
if (KF_USE_WIKI) {
$txtWiki = GetWikiPage($this->strWikiPg);
if ($txtWiki) {
if (strpos($txtWiki,'__NOIMG__') != -1) {
$txtWiki = str_replace('__NOIMG__',,$txtWiki);
$this->hideImgs = true;
}
}
if ($txtWiki) {
echo '';
}
}
}
}
/*%%%%
TODO:
* figure out why we need to have this as a separate class from clsVbzPage_Cat
* give it a better name
*/
class clsPageCat extends clsVbzPage_Cat {
private $objCatPage; // object for identifying page to display
private function Suppliers($id=NULL) {
$tbl = $this->Data()->Suppliers();
$tbl->Page($this);
if (is_null($id)) {
return $tbl;
} else {
$rc = $tbl->GetItem($id);
return $rc;
}
}
protected function RenderHdrBlocks() {
if ($this->useSkin) {
parent::RenderHdrBlocks();
}
}
protected function RenderFtrBlocks() {
if ($this->useSkin) {
parent::RenderFtrBlocks();
}
}
protected function HandleInput() {
parent::HandleInput();
$strReq = $this->strReq;
$this->objCatPage = $this->Data()->Pages()->GetItem_byKey($strReq);
$objPage = $this->objCatPage;
$this->useSkin = TRUE;
if ($this->strReq) {
if (is_object($objPage)) {
switch ($objPage->Type) {
case 'S':
$this->DoCatSupp();
break;
case 'D':
$this->DoCatDept();
break;
case 'T':
$this->DoCatTitle();
break;
case 'I':
$this->useSkin = FALSE;
$this->DoCatImage();
break;
}
} else {
$this->DoNotFound();
}
} else {
$this->DoCatHome();
}
}
public function DoContent() {
echo $this->Doc()->Render();
}
// SIDEBAR INFO for different types of pages
private function DoCatIndicia() {
$this->lstTop->Add('Section','<a href="'.KWP_CAT_REL.'">by supplier</a>');
}
private function DoSuppIndicia($iSupp,$isFinal=true) {
$this->DoCatIndicia();
if ($isFinal) {
$this->lstTop->Add('Supplier',$iSupp->Name);
$this->lstTop->Add('<a href="'.KWP_WIKI.$iSupp->Name.'">more info</a>');
} else {
$this->lstTop->Add('Supplier',$iSupp->Link());
}
}
private function DoDeptIndicia($iDept,$isFinal=true) {
$this->DoSuppIndicia($iDept->Supplier(),false);
if ($isFinal) {
$this->lstTop->Add('Dept.',$iDept->Name);
} else {
$this->lstTop->Add('Dept.',$iDept->LinkName());
}
}
private function DoTitleIndicia($iTitle) {
$this->DoDeptIndicia($iTitle->Dept(),false);
$this->lstTop->Add('Title',$iTitle->Name);
$this->lstTop->Add(' - catalog #',$iTitle->CatNum());
}
private function DoCatHome() {
$this->DoCatIndicia();
$this->strWikiPg = 'cat';
$this->strTitle = 'Catalog Home';
$this->strName = 'Catalog main page';
$this->strTitleContext = 'hello and welcome to the...';
$this->Suppliers()->DoHomePage();
$this->AddText($this->Doc()->Render());
}
private function DoCatSupp() {
$idRow = $this->objCatPage->Value('ID_Row');
$rcSupp = $this->Suppliers($idRow);
assert('is_object($rcSupp)');
$strSuppName = $rcSupp->Value('Name');
$this->DoSuppIndicia($rcSupp);
$this->strWikiPg = 'supp:'.strtoupper($rcSupp->Value('CatKey'));
$this->strTitle = $strSuppName;
$this->strName = 'listing for '.$strSuppName;
$this->strTitleContext = '<a href="'.KWP_CAT_REL.'">Suppliers</a>: '.$strSuppName.':';
$rcSupp->DoDeptsPage();
$this->AddText($this->Doc()->Render());
}
private function DoCatDept() {
CallEnter($this,__LINE__,'clsPage.DoCatDept()');
// $objDeptTbl = VbzClasses::Depts();
$objDeptTbl = $this->Depts();
$objDept = $objDeptTbl->GetItem($this->objCatPage->ID_Row);
assert('is_object($objDept)');
$objSupp = $objDept->Supplier();
assert('is_object($objSupp)');
$strDeptName = $objDept->Name;
$strSuppName = $objSupp->Name;
$strDeptLink = $objDept->LinkName();
$strSuppLink = $objSupp->Link();
$this->DoDeptIndicia($objDept);
$this->strWikiPg = 'dept:'.strtoupper($objDept->PageKey);
$this->strTitle = $strSuppName;
$this->strName = $strDeptName.' dept. of '.$strSuppName;
$this->strTitleContext = 'items <a href="'.KWP_CAT_REL.'">supplied</a> by '.$strSuppLink.'\'s '.$strDeptName.' department:';
$this->AddText($objDept->DoPage());
CallExit('clsPage.DoCatDept()');
}
private function DoCatTitle() {
CallEnter($this,__LINE__,'clsPage.DoCatTitle()');
$strPageKey = $this->objCatPage->Path;
// $objTitleTbl = VbzClasses::Titles();
$objTitleTbl = $this->Titles();
$idRow = $this->objCatPage->ID_Row;
$objTitle = $objTitleTbl->GetItem($idRow);
assert('is_object($objTitle)');
$objDept = $objTitle->Dept();
assert('is_object($objDept)');
$objSupp = $objDept->Supplier();
assert('is_object($objSupp)');
$strTitleName = $objTitle->Name;
$this->DoTitleIndicia($objTitle);
// $this->strAbbr = 'title:'.strtoupper($strCatNum);
$this->strWikiPg = 'title:'.$objTitle->CatNum();
//print 'ABBR='.$this->strAbbr;
$this->strTitle = $strTitleName;
$this->strName = $strPageKey.' "'.$strTitleName.'" from '.$objSupp->Name;
$this->strTitleContext =
'items <a href="'.KWP_CAT_REL.
'">supplied</a> by '.$objSupp->Link().'\'s '.
$objDept->LinkName().' department:';
$objTitle->hideImgs = $this->hideImgs;
$this->AddText($objTitle->DoPage());
CallExit('clsPage.DoCatTitle()');
}
private function DoCatImage() {
CallEnter($this,__LINE__,'clsPage.DoCatImage()');
// $objImageTbl = VbzClasses::Images();
$objImageTbl = $this->Images();
$objImage = $objImageTbl->GetItem($this->objCatPage->ID_Row);
$objImage->DoPage();
CallExit('clsPage.DoCatImage()');
}
}</php>