summaryrefslogtreecommitdiff
path: root/backend/php/src/setup/setup_library
Side-by-side diff
Diffstat (limited to 'backend/php/src/setup/setup_library') (more/less context) (ignore whitespace changes)
-rw-r--r--backend/php/src/setup/setup_library/authentication.php30
-rw-r--r--backend/php/src/setup/setup_library/class.zipfile.php212
-rw-r--r--backend/php/src/setup/setup_library/inc.footer.php6
-rw-r--r--backend/php/src/setup/setup_library/inc.header.php36
-rw-r--r--backend/php/src/setup/setup_library/setup_misc.php2357
-rw-r--r--backend/php/src/setup/setup_library/upgrade.php140
-rw-r--r--backend/php/src/setup/setup_library/xPandMenu.css55
-rw-r--r--backend/php/src/setup/setup_library/xPandMenu.js273
-rw-r--r--backend/php/src/setup/setup_library/xPandMenu.php233
9 files changed, 3342 insertions, 0 deletions
diff --git a/backend/php/src/setup/setup_library/authentication.php b/backend/php/src/setup/setup_library/authentication.php
new file mode 100644
index 0000000..6a6954a
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/authentication.php
@@ -0,0 +1,30 @@
+<?php
+if (sizeof($_POST) > 0 && $GLOBALS['configuration']['setup_password'] != "" && (!isset($_SESSION['authenticated']) || !$_SESSION['authenticated']))
+{
+ if ($_POST['setup_password'] == $GLOBALS['configuration']['setup_password'])
+ {
+ $_SESSION['authenticated'] = true;
+ }
+ $_POST = null;
+}
+if ((!isset($_SESSION['authenticated']) || !$_SESSION['authenticated']) && $GLOBALS['configuration']['setup_password'] != "")
+{
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Php Object Generator Setup <?=$GLOBALS['configuration']['versionNumber'].$GLOBALS['configuration']['revisionNumber']?></title>
+<link rel="stylesheet" href="./setup.css" type="text/css" />
+<link rel="stylesheet" type="text/css" href="./setup_library/xPandMenu.css"/>
+<div align="center">
+<form action="./index.php" method="POST"><br/>
+<img src="setup_images/mini_pog.jpg"/><br/><br/>
+<input name="setup_password" type="password" class="i"/>
+<br/><br/><input type="image" src="setup_images/generate.jpg" name="submit"/>
+</form>
+</div>
+</html>
+<?php
+exit;
+}
+?> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/class.zipfile.php b/backend/php/src/setup/setup_library/class.zipfile.php
new file mode 100644
index 0000000..4bbe779
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/class.zipfile.php
@@ -0,0 +1,212 @@
+<?php
+
+/**
+ * Class to dynamically create a zip file (archive)
+ *
+ * @author Rochak Chauhan. Extended by Joel Wan & Mark Slemko
+ */
+
+class createZip {
+ var $compressedData = array();
+ var $centralDirectory = array(); // central directory
+ var $endOfCentralDirectory = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
+ var $oldOffset = 0;
+
+ /**
+ * Function to create the directory where the file(s) will be unzipped
+ *
+ * @param $directoryName string
+ *
+ */
+
+ function addDirectory($directoryName) {
+ $directoryName = str_replace("\\", "/", $directoryName);
+
+ $feedArrayRow = "\x50\x4b\x03\x04";
+ $feedArrayRow .= "\x0a\x00";
+ $feedArrayRow .= "\x00\x00";
+ $feedArrayRow .= "\x00\x00";
+ $feedArrayRow .= "\x00\x00\x00\x00";
+
+ $feedArrayRow .= pack("V",0);
+ $feedArrayRow .= pack("V",0);
+ $feedArrayRow .= pack("V",0);
+ $feedArrayRow .= pack("v", strlen($directoryName) );
+ $feedArrayRow .= pack("v", 0 );
+ $feedArrayRow .= $directoryName;
+
+ $feedArrayRow .= pack("V",0);
+ $feedArrayRow .= pack("V",0);
+ $feedArrayRow .= pack("V",0);
+
+ $this -> compressedData[] = $feedArrayRow;
+
+ $newOffset = strlen(implode("", $this->compressedData));
+
+ $addCentralRecord = "\x50\x4b\x01\x02";
+ $addCentralRecord .="\x00\x00";
+ $addCentralRecord .="\x0a\x00";
+ $addCentralRecord .="\x00\x00";
+ $addCentralRecord .="\x00\x00";
+ $addCentralRecord .="\x00\x00\x00\x00";
+ $addCentralRecord .= pack("V",0);
+ $addCentralRecord .= pack("V",0);
+ $addCentralRecord .= pack("V",0);
+ $addCentralRecord .= pack("v", strlen($directoryName) );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $ext = "\x00\x00\x10\x00";
+ $ext = "\xff\xff\xff\xff";
+ $addCentralRecord .= pack("V", 16 );
+
+ $addCentralRecord .= pack("V", $this -> oldOffset );
+ $this -> oldOffset = $newOffset;
+
+ $addCentralRecord .= $directoryName;
+
+ $this -> centralDirectory[] = $addCentralRecord;
+ }
+
+ /**
+ * Function to add file(s) to the specified directory in the archive
+ *
+ * @param $directoryName string
+ *
+ */
+
+ function addFile($data, $directoryName) {
+
+ $directoryName = str_replace("\\", "/", $directoryName);
+
+ $feedArrayRow = "\x50\x4b\x03\x04";
+ $feedArrayRow .= "\x14\x00";
+ $feedArrayRow .= "\x00\x00";
+ $feedArrayRow .= "\x08\x00";
+ $feedArrayRow .= "\x00\x00\x00\x00";
+
+ $uncompressedLength = strlen($data);
+ $compression = crc32($data);
+ $gzCompressedData = gzcompress($data);
+ $gzCompressedData = substr( substr($gzCompressedData, 0, strlen($gzCompressedData) - 4), 2);
+ $compressedLength = strlen($gzCompressedData);
+ $feedArrayRow .= pack("V",$compression);
+ $feedArrayRow .= pack("V",$compressedLength);
+ $feedArrayRow .= pack("V",$uncompressedLength);
+ $feedArrayRow .= pack("v", strlen($directoryName) );
+ $feedArrayRow .= pack("v", 0 );
+ $feedArrayRow .= $directoryName;
+
+ $feedArrayRow .= $gzCompressedData;
+
+ $feedArrayRow .= pack("V",$compression);
+ $feedArrayRow .= pack("V",$compressedLength);
+ $feedArrayRow .= pack("V",$uncompressedLength);
+
+ $this -> compressedData[] = $feedArrayRow;
+
+ $newOffset = strlen(implode("", $this->compressedData));
+
+ $addCentralRecord = "\x50\x4b\x01\x02";
+ $addCentralRecord .="\x00\x00";
+ $addCentralRecord .="\x14\x00";
+ $addCentralRecord .="\x00\x00";
+ $addCentralRecord .="\x08\x00";
+ $addCentralRecord .="\x00\x00\x00\x00";
+ $addCentralRecord .= pack("V",$compression);
+ $addCentralRecord .= pack("V",$compressedLength);
+ $addCentralRecord .= pack("V",$uncompressedLength);
+ $addCentralRecord .= pack("v", strlen($directoryName) );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("v", 0 );
+ $addCentralRecord .= pack("V", 32 );
+
+ $addCentralRecord .= pack("V", $this -> oldOffset );
+ $this -> oldOffset = $newOffset;
+
+ $addCentralRecord .= $directoryName;
+
+ $this -> centralDirectory[] = $addCentralRecord;
+ }
+
+ /**
+ * Fucntion to return the zip file
+ *
+ * @return zipfile (archive)
+ */
+
+ function getZippedfile() {
+
+ $data = implode("", $this -> compressedData);
+ $controlDirectory = implode("", $this -> centralDirectory);
+
+ return
+ $data.
+ $controlDirectory.
+ $this -> endOfCentralDirectory.
+ pack("v", sizeof($this -> centralDirectory)).
+ pack("v", sizeof($this -> centralDirectory)).
+ pack("V", strlen($controlDirectory)).
+ pack("V", strlen($data)).
+ "\x00\x00";
+ }
+
+ /**
+ *
+ * Function to force the download of the archive as soon as it is created
+ *
+ * @param archiveName string - name of the created archive file
+ */
+
+ function forceDownload($archiveName) {
+ $headerInfo = '';
+ header("Pragma: public");
+ header("Expires: 0");
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
+ header("Cache-Control: private",false);
+ header("Content-Type: application/zip");
+ header("Content-Disposition: attachment; filename=".basename($archiveName).";" );
+ header("Content-Transfer-Encoding: binary");
+ echo $this->getZippedfile();
+
+ }
+
+ /**
+ * Generates zip file from POG package.
+ *
+ * @param multi-d array $package
+ * @param array $paths
+ */
+ function addPOGPackage($package, $paths=array())
+ {
+
+ $i = 0;
+ foreach ($package as $key=>$value)
+ {
+ $path = '';
+ foreach ($paths as $p)
+ {
+ $path .= (($path == '') ? $p : "/$p");
+ }
+ if (strpos($key, ".") == false)
+ {
+ $paths[] = $key;
+ $this->addDirectory((($path == '') ? "$key/" : "$path/$key/"));
+ $this->addPOGPackage($package[$key], &$paths);
+ }
+ else
+ {
+ $this->addFile(base64_decode($value), (($path == '') ? $key : "$path/$key"));
+ }
+ if ($i == (sizeof($package)-1))
+ {
+ array_pop($paths);
+ }
+ $i++;
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/inc.footer.php b/backend/php/src/setup/setup_library/inc.footer.php
new file mode 100644
index 0000000..d00549d
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/inc.footer.php
@@ -0,0 +1,6 @@
+<img src="./setup_images/setup_footer.jpg"/>
+<a href="http://www.phpobjectgenerator.com" title="Php Object Generator Homepage">PHP Object Generator</a> |
+<a href="http://www.phpobjectgenerator.com/plog" title="Php Weblog">POG Weblog</a> |
+<a href="http://groups.google.com/group/Php-Object-Generator" title="POG Google Group">Google group</a> |
+<a href="http://www.phpobjectgenerator.com/plog/tutorials" title="POG Tutorials">Tutorials</a> |
+<a href="mailto:pogguys@phpobjectgenerator.com" title="Contact the POG authors">Contact us</a> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/inc.header.php b/backend/php/src/setup/setup_library/inc.header.php
new file mode 100644
index 0000000..e53b36d
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/inc.header.php
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Php Object Generator Setup <?=$GLOBALS['configuration']['versionNumber'].$GLOBALS['configuration']['revisionNumber']?></title>
+<link rel="stylesheet" type="text/css" href="./setup_library/xPandMenu.css"/>
+<link rel="stylesheet" href="./setup.css" type="text/css" />
+<script src="./setup_library/xPandMenu.js"></script>
+</head>
+<body>
+<div class="header">
+<script type="text/javascript"><!--
+google_ad_client = "pub-7832108692498114";
+google_alternate_color = "FFFFFF";
+google_ad_width = 728;
+google_ad_height = 90;
+google_ad_format = "728x90_as";
+google_ad_type = "text";
+google_ad_channel ="1767526614";
+google_color_border = "FFFFFF";
+google_color_bg = "FFFFFF";
+google_color_link = "716500";
+google_color_url = "B8B8B8";
+google_color_text = "CCC078";
+//--></script>
+<script type="text/javascript"
+ src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script>
+<script type="text/javascript"><!--
+function PleaseWait(id)
+{
+ var div = document.getElementById("pleasewait"+id);
+ div.style.display = "block";
+ return false;
+}
+//--></script>
+</div> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/setup_misc.php b/backend/php/src/setup/setup_library/setup_misc.php
new file mode 100644
index 0000000..f0e4f0e
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/setup_misc.php
@@ -0,0 +1,2357 @@
+<?php
+
+
+ /**
+ * Specifies what test data is used during unit testing (step 2 of the setup process)
+ * Todo: Can be improved but satisfatory for now
+ * @return array
+ */
+ function InitializeTestValues($pog_attribute_type)
+ {
+ $DATETIME = '1997-12-15 23:50:26';
+ $DATE = '1997-12-15';
+ $TIMESTAMP = '1997-12-15 23:50:26';
+ $TIME = '23:50:26';
+ $YEAR = '1997';
+ $DECIMAL =
+ $DOUBLE =
+ $FLOAT =
+ $BIGINT =
+ $INT = '12345678';
+ $SMALLINT = '1234';
+ $MEDIUMINT = '12345';
+ $TINYINT = '1';
+ $CHAR = 'L';
+ $VARCHAR =
+ $TEXT =
+ $TINYBLOB =
+ $TINYTEXT =
+ $BLOB =
+ $MEDIUMBLOB =
+ $MEDIUMTEXT =
+ $LONGBLOB =
+ $BINARY=
+ $LONGTEXT = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry';
+ $attribute_testValues = array();
+ array_shift($pog_attribute_type); //get rid of objectid
+ foreach ($pog_attribute_type as $attribute => $property)
+ {
+ if (isset($property['db_attributes'][2]))
+ //length is specified, for e.g. if attribute = VARCHAR(255), $property[2]=255
+ {
+ $limit = explode(',', $property['db_attributes'][2]);
+ //field is limited
+ if (intval($limit[0]) > 0)
+ {
+ if (isset($limit[1]) && intval($limit[1]) > 0)
+ {
+ //decimal, enum, set
+ $attribute_testValues[$attribute] = substr(${$property['db_attributes'][1]}, 0, ceil($limit[0]*0.6)).".".substr(${$property['db_attributes'][1]}, 0, $limit[1]);
+ }
+ else
+ {
+ $attribute_testValues[$attribute] = substr(${$property['db_attributes'][1]}, 0, ceil($limit[0] * 0.6));
+ }
+ }
+ }
+ else
+ //length not specified, but we still need to account for default mysql behavior
+ //for eg, FLOAT(X), if X isn't specified, mysql defaults to (10,2).
+ {
+ if ($property['db_attributes'][1] == "FLOAT" || $property['db_attributes'][1] == "DOUBLE")
+ {
+ $attribute_testValues[$attribute] = "1234.56";
+ }
+ else if ($property['db_attributes'][1] != "HASMANY" && $property['db_attributes'][1] != "BELONGSTO" && $property['db_attributes'][1] != "JOIN")
+ {
+ $attribute_testValues[$attribute] = ${$property['db_attributes'][1]};
+ }
+ }
+ }
+ return $attribute_testValues;
+ }
+
+ /**
+ * Specifies how object attributes are rendered during scaffolding (step 3 of the setup process)
+ * Todo: Can be improved but satisfactory for now
+ * @param string $attributeName
+ * @param string $attributeType
+ * @param string $attributeValue
+ * @param int $objectId
+ * @return string $html
+ */
+ function ConvertAttributeToHtml($attributeName, $attributeProperties, $attributeValue='', $objectId='')
+ {
+ switch ($attributeProperties[1])
+ {
+ case "ENUM":
+ $enumParts = explode(',', $attributeProperties[2]);
+ $html = "<select id='".($objectId != ''?$attributeName."_".$objectId:$attributeName)."' class='s'>";
+ foreach ($enumParts as $enumPart)
+ {
+ if ($attributeValue == trim($enumPart, "\' "))
+ {
+ $html .= "<option value='".trim($enumPart, "\' ")."' selected>".trim($enumPart, "\' ")."</option>";
+ }
+ else
+ {
+ $html .= "<option value='".trim($enumPart, "\' ")."'>".trim($enumPart, "\' ")."</option>";
+ }
+ }
+ $html .= "</select>";
+ break;
+ case "HASMANY":
+ case "JOIN":
+ case "BELONGSTO":
+ $html = $attributeValue;
+ break;
+ case "MEDIUMBLOB":
+ $html = "sorry. cannot render attribute of type LONGBLOB";
+ break;
+ case "LONGBLOB":
+ $html = "sorry. cannot render attribute of type LONGBLOB";
+ break;
+ case "TEXT":
+ case "LONGTEXT":
+ case "BINARY":
+ case "MEDIUMTEXT":
+ case "TINYTEXT":
+ case "VARCHAR":
+ case "TINYBLOB":
+ case "BLOB":
+ $html = "<textarea class='t' id='".($objectId != ''?$attributeName."_".$objectId:$attributeName)."'>".($attributeValue != ''?$attributeValue:'')."</textarea>";
+ break;
+ case "DATETIME":
+ case "DATE":
+ case "TIMESTAMP":
+ case "TIME":
+ case "YEAR":
+ case "DECIMAL":
+ case "DOUBLE":
+ case "FLOAT":
+ case "BIGINT":
+ case "INT":
+ case "YEAR":
+ case "SMALLINT":
+ case "MEDIUMINT":
+ case "TINYINT":
+ case "CHAR":
+ $html = "<input class='i' id='".($objectId != ''?$attributeName."_".$objectId:$attributeName)."' value='".($attributeValue != ''?$attributeValue:'')."' type='text' />";
+ break;
+ default:
+ $html = substr($attributeValue, 0, 500);
+ if (strlen($attributeValue) > 500)
+ {
+ $html .= "...";
+ }
+ break;
+ }
+ return $html;
+ }
+
+ /**
+ * Renders an object as an Xtree Node
+ *
+ * @param unknown_type $child
+ */
+ function ConvertObjectToNode(&$instance, &$masterNode, $js, $anchor, $once = false)
+ {
+ $attributeList = array_keys(get_object_vars($instance));
+ $objectName = $className = get_class($instance);
+ $node = &$masterNode->addItem(new XNode("<span style='color:#0BAA9D'>[".$instance->{strtolower($className)."Id"}."]</span> <a href='#' onclick='ToggleElementVisibility(\"deleteConfirm_".$instance->{strtolower($objectName).'Id'}."\");return false;'><img src=\"./setup_images/button_delete.gif\" border=\"0\"/></a> <span id='deleteConfirm_".$instance->{strtolower($objectName).'Id'}."' style='display:none;width:250px;'><a href='#' class='deleteDeep' onclick='javascript:sndReq(\"DeleteDeep\", getOpenNodes(), \"$objectName\", \"".$instance->{strtolower($objectName).'Id'}."\", this.parentNode.parentNode.parentNode.parentNode.id, $js, \"$anchor\");return false;'>Delete(deep)</a> | <a href='#' class='deleteShallow' onclick='javascript:sndReq(\"Delete\", getOpenNodes(), \"$objectName\", \"".$instance->{strtolower($objectName).'Id'}."\", this.parentNode.parentNode.parentNode.parentNode.id, $js, \"$anchor\");return false;'>Delete(shallow)</a> | <a href='#' class='deleteCancel' onclick='ToggleElementVisibility(\"deleteConfirm_".$instance->{strtolower($objectName).'Id'}."\");return false;'>Cancel</a></span>", false,"setup_images/folderclose.gif","setup_images/folderopen.gif"));
+
+ //regular attributes
+ foreach($attributeList as $attribute)
+ {
+ if ($attribute != "pog_attribute_type" && $attribute!= "pog_query" )
+ {
+ if (isset($instance->pog_attribute_type[$attribute]))
+ {
+ $thisValue = ConvertAttributeToHtml($attribute, $instance->pog_attribute_type[$attribute]['db_attributes'], $instance->{$attribute}, $instance->{$attributeList[0]});
+ $subnode = &$node->addItem(new XNode("<br/>".$attribute."<span style='font-weight:normal;color:#ADA8B2;'>{".$instance->pog_attribute_type[$attribute]['db_attributes'][1]."}</span><br/>".str_replace("\0", "", $thisValue)."<br/><br/>", false,'',"setup_images/folderopen.gif"));
+ }
+ }
+ }
+
+ //parents, children and mapping
+ foreach ($instance->pog_attribute_type as $attribute_name => $attrubute_type)
+ {
+ if ($attrubute_type['db_attributes'][1] == "HASMANY" || $attrubute_type['db_attributes'][1] == "BELONGSTO" || $attrubute_type['db_attributes'][1] == "JOIN")
+ {
+ if ($attrubute_type['db_attributes'][1] == "BELONGSTO")
+ {
+ eval ('$value = $instance->'.strtolower($attribute_name).'Id;');
+ $thisValue = ConvertAttributeToHtml($attribute_name, $attrubute_type['db_attributes'], $value, '');
+ $subnode = &$node->addItem(new XNode("<br/>".$attribute_name."<span style='font-weight:normal;color:#ADA8B2;'>{".($attrubute_type['db_attributes'][1] == "HASMANY" ? "CHILD" : "PARENT")."}</span><br/>".$thisValue."<br/><br/>", false,'',"setup_images/folderopen.gif"));
+ }
+ else
+ {
+ $value = '';
+ eval('$siblingList = $instance->Get'.ucfirst(strtolower($attribute_name)).'List();');
+ if (sizeof($siblingList) > 0)
+ {
+ $myNode = &$node->addItem(new XNode("<span style='color:#4d4a4a'>[".$attribute_name."List]{Dimensions:[".sizeof($siblingList)."]}</span>", false, "setup_images/folderclose.gif","setup_images/folderopen.gif", true));
+ $child = $siblingList[0];
+ $js2 = "new Array(";
+ $attributeList = array_keys(get_object_vars($child));
+ $x=0;
+ foreach($attributeList as $attribute)
+ {
+ if ($attribute != "pog_attribute_type" && $attribute!= "pog_query")
+ {
+ if ($x != 0 && isset($child->pog_attribute_type[$attribute]))
+ {
+ $js2 .= '"'.$attribute.'",';
+ }
+ }
+ $x++;
+ }
+ $js2 = trim($js2, ",");
+ $js2 .= ")";
+
+ if (!$once)
+ {
+ foreach ($siblingList as $child)
+ {
+ /*$value .= $child->{strtolower($attribute_name)."Id"} . ",";*/
+ if ($attrubute_type['db_attributes'][1] == "JOIN")
+ {
+ ConvertObjectToNode($child, $myNode, $js2, $anchor, true);
+ }
+ else
+ {
+ ConvertObjectToNode($child, $myNode, $js2, $anchor);
+ }
+ }
+ }
+ }
+ else
+ {
+ $node->addItem(new XNode("<span style='color:#4d4a4a'>[".$attribute_name."List]{Dimensions:[0]}</span><br/><br/>", false, '',"setup_images/folderopen.gif"));
+ }
+ }
+ }
+ }
+ $subnode = &$node->addItem(new XNode("<br/><a style='float:left;' href='#' onclick='javascript:PleaseWait(\"".$instance->{strtolower($objectName).'Id'}."\"); sndReq(\"Update\", getOpenNodes(), \"$objectName\", \"".$instance->{strtolower($objectName).'Id'}."\", this.parentNode.parentNode.parentNode.parentNode.id, $js, \"$anchor\");return false;'><img src='./setup_images/button_update.gif' border='0'/></a><span id='pleasewait".$instance->{strtolower($objectName).'Id'}."' style='float:left;display:none;'><img src='./setup_images/loading.gif' style='float:left;'/></span><br/>", false,'',"folderopen.gif"));
+ }
+
+
+ /**
+ * Populates object attributes with test values
+ *
+ * @param unknown_type $object
+ * @return unknown
+ */
+ function PopulateTestValues(&$object)
+ {
+ $attributeList = array_keys(get_object_vars($object));
+ $type_value = InitializeTestValues($object->pog_attribute_type);
+
+ $objectName = get_class($object);
+ foreach($attributeList as $attribute)
+ {
+ if (isset($object->pog_attribute_type[$attribute]))
+ {
+ if (isset($type_value[$attribute]))
+ {
+ $object->{$attribute} = $type_value[$attribute];
+ }
+ else if ($object->pog_attribute_type[$attribute]['db_attributes'][0] != "OBJECT")
+ {
+ $object->{$attribute} = "1";
+ }
+ }
+ }
+ eval ("\$object -> ".strtolower($objectName)."Id = '';");
+ return $object;
+ }
+
+ /**
+ * Extracts @link from object file
+ *
+ * @param unknown_type $objectFilePath
+ * @return unknown
+ */
+ function GetAtLink($objectFilePath)
+ {
+ $link = '';
+ $content = file_get_contents($objectFilePath);
+ $contentParts = split("<b>",$content);
+ if (isset($contentParts[1]))
+ {
+ $contentParts2 = split("</b>",$contentParts[1]);
+ }
+ if (isset($contentParts2[0]))
+ {
+ $className = trim($contentParts2[0]);
+ }
+ if (isset($className))
+ {
+ $linkParts1 = split("\*\/", $contentParts[1]);
+ $linkParts2 = split("\@link", $linkParts1[0]);
+ if (isset($linkParts2[1]))
+ {
+ $link = $linkParts2[1];
+ }
+ if (isset($GLOBALS['configuration']['homepage']) && isset($link))
+ {
+ $linkParts = explode('?', $link);
+ if (isset($linkParts[1]))
+ {
+ $link = $GLOBALS['configuration']['homepage'].'/?'.$linkParts[1];
+ }
+ }
+ }
+ return $link;
+ }
+
+ /**
+ * Extracts object name from object file. Do not rely on filename.
+ *
+ * @param unknown_type $objectFilePath
+ */
+ function GetObjectName($objectFilePath)
+ {
+ $content = file_get_contents($objectFilePath);
+ $contentParts = split("<b>",$content);
+ if (isset($contentParts[1]))
+ {
+ $contentParts2 = split("</b>",$contentParts[1]);
+ }
+ if (isset($contentParts2[0]))
+ {
+ $className = trim($contentParts2[0]);
+ }
+ return $className;
+ }
+
+ /**
+ * Gets plugin name based on filename
+ *
+ * @param unknown_type $fileName
+ * @return unknown
+ */
+ function GetPluginName($fileName)
+ {
+ $fileNameParts = explode('.', $fileName);
+ if (strtolower($fileName) != "iplugin.php" && strtolower($fileNameParts[0]) == 'plugin' && strtolower($fileNameParts[2]) == 'php')
+ {
+ return $fileNameParts[1];
+ }
+ return '';
+ }
+
+ /**
+ * Adds message to error queue
+ *
+ * @param unknown_type $error
+ */
+ function AddError($error)
+ {
+ if (isset($_SESSION['errorMessages']))
+ {
+ $errorMessages = unserialize($_SESSION['errorMessages']);
+ if (array_search($error, $errorMessages) === false)
+ {
+ $errorMessages[] = $error;
+ }
+ }
+ else
+ {
+ $errorMessages = array();
+ $errorMessages[] = $error;
+ }
+ $_SESSION['errorMessages'] = serialize($errorMessages);
+ }
+
+ /**
+ * Add message to tracing queue
+ *
+ * @param unknown_type $trace
+ */
+ function AddTrace($trace)
+ {
+ if (isset($_SESSION['traceMessages']))
+ {
+ $traceMessages = unserialize($_SESSION['traceMessages']);
+ $traceMessages[] = $trace;
+ }
+ else
+ {
+ $traceMessages = array();
+ $traceMessages[] = $trace;
+ }
+ $_SESSION['traceMessages'] = serialize($traceMessages);
+ }
+
+ /**
+ * Unit tests
+ */
+
+ /**
+ * Test the base 5 CRUD methods
+ *
+ * @param unknown_type $instance
+ * @return unknown
+ */
+ function TestEssentials($instance, $optimizeAsWell = true)
+ {
+ if(TestIsMapping($instance))
+ {
+ return true;
+ }
+ $errors = 0;
+ if (!TestSave($instance))
+ {
+ $errors++;
+ }
+ if (!TestSaveNew($instance))
+ {
+ $errors++;
+ }
+ if (!TestDelete($instance))
+ {
+ $errors++;
+ }
+ if (!TestGetList($instance))
+ {
+ $errors++;
+ }
+ if (!TestDeleteList($instance))
+ {
+ $errors++;
+ }
+ if ($optimizeAsWell)
+ {
+ if (!TestOptimizeStorage(strtolower(get_class($instance))))
+ {
+ $errors++;
+ }
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param unknown_type $instance
+ * @return unknown
+ */
+ function TestRelationsPreRequisites($instance, $allObjectsList, $thisObjectName, $ignoreObjects)
+ {
+ if(TestIsMapping($instance))
+ {
+ AddTrace("\tIs Mapping (OK)");
+ return true;
+ }
+ if (TestIsSingle($instance))
+ {
+ AddTrace("\tIs single (OK)");
+ return true;
+ }
+ else
+ {
+ if (!TestParentChildLink($instance, $allObjectsList, $thisObjectName, $ignoreObjects) || !TestAssociationLink($instance, $allObjectsList, $thisObjectName, $ignoreObjects))
+ {
+ return false;
+ }
+ else
+ {
+ AddTrace("\tIs properly connected (OK)");
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Test the optional object relations methods
+ *
+ * @param unknown_type $instance
+ * @return unknown
+ */
+ function TestRelations($instance, $ignoreObjects)
+ {
+ $errors=0;
+ if (TestIsParent($instance))
+ {
+ if (!TestAddChild($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestGetChildrenList($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestDeleteDeep_Child($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestSaveDeep_Child($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestSetChildrenList($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ }
+ if (TestIsChild($instance))
+ {
+ if (!TestSetParent($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestGetParent($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ }
+ if (TestIsSibling($instance))
+ {
+ if (!TestAddSibling($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestGetSiblingList($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestSaveDeep_Sibling($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestDeleteDeep_Sibling($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ if (!TestSetSiblingList($instance, true, $ignoreObjects))
+ {
+ $errors++;
+ }
+ }
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tests whether object table already exists
+ *
+ */
+ function TestStorageExists($objectName, $databaseType = "mysql")
+ {
+ switch ($databaseType)
+ {
+ case "mysql":
+ $query = "show tables like '".strtolower($objectName)."'";
+ break;
+ case "sqlite":
+ $query = "select name FROM sqlite_master WHERE type='table' and name='".strtolower($objectName)."'";
+ break;
+ case "pgsql":
+ $query = "select table_name FROM information_schema.tables WHERE table_schema = 'public' and table_name='".strtolower($objectName)."'";
+ break;
+ case "odbc":
+ //assume mssql
+ $query = "select * from information_schema.tables where table_type = 'BASE TABLE' and table_name='".strtolower($objectName)."'";
+ break;
+ case "firebird":
+ AddError("POG Setup doesn't support automatic table detection for Firebird databases yet. Therefore, your objects/tables may be misaligned. If POG Essential tests failed, this may very well be the case. Create the tables manually and re-run setup.");
+ return true;
+ break;
+ }
+
+ $connection = Database::Connect();
+ $rows = Database::Query($query, $connection);
+ if ($rows > 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Creates the table to store objects
+ *
+ */
+ function TestCreateStorage($objectFilePath, $databaseType = "mysql")
+ {
+ if ($databaseType == "firebird")
+ {
+ AddError("POG Setup doesn't support automatic table creation for Firebird databases yet. Therefore, your objects/tables may be misaligned. If POG Essential tests failed, this may very well be the case. Create the tables manually and re-run setup.");
+ return true;
+ }
+
+ $objectName = GetObjectName($objectFilePath);
+
+ //extract sql
+ $content = file_get_contents($objectFilePath);
+ $contentParts = split("<b>",$content);
+ if (isset($contentParts[1]))
+ {
+ $contentParts2 = split("</b>",$contentParts[1]);
+ }
+ if (isset($contentParts2[0]))
+ {
+ $className = trim($contentParts2[0]);
+ }
+ if (isset($className))
+ {
+ $sqlParts = split(";",$contentParts[0]);
+ $sqlPart = split("CREATE",$sqlParts[0]);
+ $sql = "CREATE ".$sqlPart[1].";";
+
+ //execute sql
+ $connection = Database::Connect();
+ if (Database::NonQuery($sql, $connection) !== false)
+ {
+ return true;
+ }
+ }
+ AddError("Query failed: $sql");
+ return false;
+ }
+
+ /**
+ * Drops the table for the corresponding object
+ *
+ */
+ function TestDeleteStorage($object, $databaseType = "mysql")
+ {
+ $tableName = strtolower(get_class($object));
+ $connection = Database::Connect();
+ if (Database::NonQuery('drop table `'.strtolower($tableName).'`', $connection) !== false)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Executes an arbitrary query
+ *
+ * @param unknown_type $query
+ */
+ function TestExecuteQuery($query)
+ {
+ $connection = Database::Connect();
+ if ($query == "")
+ {
+ return true;
+ }
+ if (Database::NonQuery($query, $connection) !== false)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param unknown_type $object
+ * @return unknown
+ */
+ function TestAlterStorage($object, $databaseType = "mysql")
+ {
+ if ($databaseType != "mysql")
+ {
+ AddTrace("POG Setup doesn't support table automatic alteration for non-MySQL databases yet. Therefore, your objects/tables may be misaligned. If POG Essential tests failed, this may very well be the case. Drop and recreate the tables and re-run setup.");
+ return true;
+ }
+
+ //find object attributes/table columns mismatch
+ $tableName = strtolower(get_class($object));
+ $columns = array();
+
+ $query = "describe `$tableName` ";
+ $connection = Database::Connect();
+ $cursor = Database::Reader($query, $connection);
+ if ($cursor !== false)
+ {
+ while ($row = Database::Read($cursor))
+ {
+ $columns[$row["Field"]] = $row["Type"];
+ }
+
+ $attribute_types = $object -> pog_attribute_type;
+ $lowerAttributes = array();
+ foreach (array_keys($attribute_types) as $key)
+ {
+ $lowerAttributes[strtolower($key)] = $attribute_types[$key];
+ }
+
+ //columns to remove
+ $columnsToRemove = array_diff(array_keys($columns), array_keys($lowerAttributes));
+
+ //columns to add
+ $columnsToAdd = array_diff(array_keys($lowerAttributes), array_keys($columns));
+
+ //columns whose type has changed
+ $otherColumns = array_intersect(array_keys($lowerAttributes), array_keys($columns));
+
+ $columnsToModify = array();
+ foreach ($otherColumns as $otherColumn)
+ {
+ $type = strtolower($lowerAttributes[$otherColumn]['db_attributes'][1]);
+ if ($type == 'enum' || $type == 'set')
+ {
+ $enumPartsObj = explode(',', strtolower($lowerAttributes[$otherColumn]['db_attributes'][2]));
+ $parts = explode('(',$columns[$otherColumn]);
+ $parts2 = explode(')',$parts[1]);
+ $enumpartsDb = explode(',', strtolower(trim($parts2[0])));
+ foreach ($enumPartsObj as $ep)
+ {
+ if (array_search(trim($ep), $enumpartsDb) === false)
+ {
+ $type .= "(".$lowerAttributes[$otherColumn]['db_attributes'][2].")";
+ $columnsToModify[$otherColumn] = $type;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (isset($lowerAttributes[$otherColumn]['db_attributes'][2]))
+ {
+ $type .= "(".$lowerAttributes[$otherColumn]['db_attributes'][2].")";
+ }
+ if (strpos(strtolower($columns[$otherColumn]), $type) === false && $type != "hasmany" && $type != "join")
+ {
+ if ($type == "belongsto")
+ {
+ $columnsToModify[strtolower($otherColumn)] = "int";
+ }
+ else
+ {
+ $columnsToModify[$otherColumn] = $type;
+ }
+ }
+ }
+ }
+
+ $columnsToRemove2 = array();
+ foreach ($columnsToRemove as $c)
+ {
+ $columnsToRemove2[] = strtolower($c);
+ }
+
+ $columnsToRemove = $columnsToRemove2;
+
+ $columnsToAdd2 = array();
+ foreach ($columnsToAdd as $c)
+ {
+ if ($lowerAttributes[$c]['db_attributes'][1] != "HASMANY" && $lowerAttributes[$c]['db_attributes'][1] != "JOIN")
+ {
+ if ($lowerAttributes[$c]['db_attributes'][1] == "BELONGSTO")
+ {
+ $colMarkedForDeletion = array_search(strtolower($c)."id", $columnsToRemove);
+ if ($colMarkedForDeletion === false) //this is clumsy, until we think of something better
+ {
+ $columnsToAdd2[] = strtolower($c)."id int";
+ }
+ else
+ {
+ //remove entry from columnsToRemove since they are the same. Will lose data if dropped & recreated
+ array_splice($columnsToRemove, $colMarkedForDeletion, 1);
+ }
+ }
+ else
+ {
+ $columnsToAdd2[] = $c;
+ }
+ }
+ }
+
+ $common = array();
+ $common = array_intersect($columnsToAdd2, $columnsToRemove);
+
+ $columnsToAdd = array();
+ foreach ($columnsToAdd2 as $col)
+ {
+ if (array_search($col, $common) === false)
+ {
+ $columnsToAdd[] = $col;
+ }
+ }
+ $columnsToRemove2 = array();
+ foreach ($columnsToRemove as $col)
+ {
+ if (array_search($col, $common) === false)
+ {
+ $columnsToRemove2[] = $col;
+ }
+ }
+
+
+ if (sizeof($columnsToAdd) == 0 && sizeof($columnsToRemove2) == 0 && sizeof($columnsToModify) == 0)
+ {
+ return true;
+ }
+
+ //construct query
+ $query = "alter table `$tableName` ";
+
+ foreach ($columnsToRemove2 as $remove)
+ {
+ $query .= "drop column `$remove`,";
+ }
+
+ foreach ($columnsToAdd as $add)
+ {
+ $columnType = '';
+ if (isset($lowerAttributes[$add]))
+ {
+ $columnType = strtolower($lowerAttributes[$add]['db_attributes'][1]);
+ }
+ if (isset($lowerAttributes[$add]['db_attributes'][2]))
+ {
+ $columnType .= "(".$lowerAttributes[$add]['db_attributes'][2].")";
+ }
+ if ($columnType != '')
+ {
+ $query .= "add column `$add` $columnType,";
+ }
+ else
+ {
+ $query .= "add column $add,";
+ }
+ }
+
+
+ foreach (array_keys($columnsToModify) as $modify)
+ {
+ $query .= "modify `$modify` ".$columnsToModify[$modify].",";
+ }
+ $query = trim($query, ',');
+ //execute query
+
+ if (Database::NonQuery($query, $connection) !== false)
+ {
+ return true;
+ }
+ }
+ AddError("Query failed: $query");
+ return false;
+ }
+
+ /**
+ * Optimizes the table by running mysql optimize
+ *
+ * @param unknown_type $objectName
+ * @return unknown
+ */
+ function TestOptimizeStorage($objectName)
+ {
+ $connection = Database::Connect();
+ if (Database::NonQuery("optimize table `".strtolower($objectName)."`", $connection) !== false)
+ {
+ AddTrace("\tOptimizing....OK!");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Save()
+ *
+ */
+ function TestSave($object, $trace=true)
+ {
+ $className = get_class($object);
+ $object = PopulateTestValues($object);
+ $objectId = false;
+ $object->{strtolower($className)."Id"} = "";
+ $objectId = $object->Save(false);
+
+ if(!$objectId)
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave() failed");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ return false;
+ }
+ //cleanup test data
+ $query = "delete from `".strtolower($className)."` where ".strtolower($className)."id = '".$objectId."';";
+ $connection = Database::Connect();
+ Database::NonQuery($query, $connection);
+ if ($trace)
+ {
+ AddTrace("\tSave()....OK!");
+ }
+ return true;
+ }
+
+ /**
+ * Unit test for SaveNew()
+ *
+ */
+ function TestSaveNew($object, $trace = true)
+ {
+ $className = get_class($object);
+ if(!TestSave($object, false))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSaveNew() ignored");
+ }
+ return false;
+ }
+ $objectId = $object->SaveNew(false);
+ if ($objectId)
+ {
+ $query = "delete from `".strtolower($className)."` where ".strtolower($className)."Id = '".$objectId."';";
+ $connection = Database::Connect();
+ Database::NonQuery($query, $connection);
+ if ($trace)
+ {
+ AddTrace("\tSaveNew()....OK!");
+ }
+ return true;
+ }
+ if ($trace)
+ {
+ AddTrace("\tSaveNew() failed");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for GetList(). Implicitly tests Get()
+ *
+ */
+ function TestGetList($object, $trace = true)
+ {
+ if ($trace)
+ {
+ AddTrace("\tGetList()");
+ }
+ $errors = 0;
+ if (TestSave($object,false) && TestSaveNew($object, false) && TestDelete($object, false))
+ {
+ $className = get_class($object);
+ $objectList = $object->GetList(array(array(strtolower($className)."Id", ">", 0)));
+ $oldCount = count($objectList);
+ $object = PopulateTestValues($object);
+ $objectId = false;
+ $object->{strtolower($className)."Id"} = 0;
+ $objectId = $object->Save(false);
+ $objectId2 = $object->SaveNew(false);
+ $objectId3 = $object->SaveNew(false);
+
+
+ //Test Multiple Conditions
+ $objectList = $object->GetList(array(array(strtolower($className)."Id", ">=",$objectId), array(strtolower($className)."Id", "<=", $objectId+2)), strtolower($className)."Id", false, 2);
+ if (sizeof($objectList) != 2)
+ {
+ //Test Limit
+ if ($trace)
+ {
+ AddTrace("\t\tLimit failed");
+ AddError('ERROR: GetList() :sizeof(list) != \$limit\n');
+ AddError("Query failed: ".$object->pog_query);
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\t\tLimit....OK!");
+ }
+ }
+ if ($objectList[1]->{strtolower($className)."Id"} > $objectList[0]->{strtolower($className)."Id"})
+ {
+ //Test Sorting
+ if ($trace)
+ {
+ AddTrace("\t\tSorting failed");
+ AddError("ERROR: GetList() :list is not properly sorted");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\t\tSorting....OK!");
+ }
+ }
+ if ($errors == 0)
+ {
+ $objectList = $object->GetList(array(array(strtolower($className)."Id", ">=",$objectId), array(strtolower($className)."Id", "<=", $objectId+2)), strtolower($className)."Id", false, 3);
+ foreach ($objectList as $object)
+ {
+ $attributeList = array_keys(get_object_vars($object));
+ foreach ($attributeList as $attribute)
+ {
+ if (isset($object->pog_attribute_type[$attribute]))
+ {
+ if (isset($type_value[$attribute]))
+ {
+ if ($object->{$attribute} != $type_value[$attribute])
+ {
+ if($trace)
+ {
+ AddError("WARNING: Failed to retrieve attribute `$attribute`. Expecting `".$type_value[$attribute]."`; found `".$object->{$attribute}."`. Check that column `$attribute` in the `$className` table is of type `".$object->pog_attribute_type[$attribute]['db_attributes'][1]."`");
+ }
+ }
+ }
+ }
+ }
+ $object->Delete();
+ }
+ return true;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tGetList() failed");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ return false;
+ }
+ }
+ if ($trace)
+ {
+ AddTrace("\tGetList() ignored");
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Delete()
+ *
+ */
+ function TestDelete($object, $trace = true)
+ {
+ if(!TestSave($object, false))
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete() ignored");
+ }
+ return false;
+ }
+ $object = PopulateTestValues($object);
+ $object->Save(false);
+ if ($object->Delete(false))
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete()....OK!");
+ }
+ return true;
+ }
+ if ($trace)
+ {
+ AddTrace("\tDelete() failed");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ return false;
+ }
+
+ /**
+ * Unit Test for DeleteList()
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ */
+ function TestDeleteList($object, $trace = true)
+ {
+ $className = get_class($object);
+ if(!TestSave($object, false) || !TestGetList($object, false))
+ {
+ if ($trace)
+ {
+ AddTrace("\tDeleteList() ignored");
+ }
+ return false;
+ }
+
+ $object = PopulateTestValues($object);
+
+ $originalCount = GetNumberOfRecords($className);
+
+ $objectId = false;
+ $object->{strtolower($className)."Id"} = 0;
+ $objectId = $object->Save(false);
+ $objectId2 = $object->SaveNew(false);
+ $objectId3 = $object->SaveNew(false);
+
+ $className = get_class($object);
+ $object->DeleteList(array(array(strtolower($className)."Id", "=", $objectId), array("or"), array(strtolower($className)."Id", "=", $objectId2), array("or"), array(strtolower($className)."Id", "=", $objectId3)));
+
+ $newCount = GetNumberOfRecords($className);
+
+ if ($newCount == $originalCount)
+ {
+ if ($trace)
+ {
+ AddTrace("\tDeleteList()....OK!");
+ }
+ return true;
+ }
+
+ if ($trace)
+ {
+ AddTrace("\tDeleteList() failed");
+ AddError("Query failed: ".$object->pog_query);
+ }
+ return false;
+ }
+
+ /**
+ * Tests whether the object is connected at all
+ *
+ * @param unknown_type $object
+ * @param unknown_type $allObjectsList
+ */
+ function TestIsSingle($object)
+ {
+ $attribute_types = $object->pog_attribute_type;
+
+ //get all child classes
+ $childrenList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ //get all parent classes
+ $parentsList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "BELONGSTO")
+ {
+ $parentsList[] = $key;
+ }
+ }
+
+ //get all associations
+ $associationsList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $associationsList[] = $key;
+ }
+ }
+
+ if (sizeof($childrenList) == 0 && sizeof($parentsList) == 0 && sizeof($associationsList) == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tests that all parents have children and vice-versa
+ *
+ * @param unknown_type $object
+ * @param unknown_type $allObjectsList
+ * @param unknown_type $thisObjectName
+ * @return unknown
+ */
+ function TestParentChildLink($object, $allObjectsList, $thisObjectName = '', $ignoreObjects)
+ {
+ $attribute_types = $object->pog_attribute_type;
+
+ //get all child classes
+ $childrenList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ //get all parent classes
+ $parentsList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "BELONGSTO")
+ {
+ $parentsList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($childrenList as $child)
+ {
+ if (array_search($child, $allObjectsList) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $child as {Child}, which couldn't be found. Generate the $child object with reference to $thisObjectName as {Parent}");
+ }
+ else
+ {
+ //test that child refers to this object as parent
+ eval ("\$childInstance = new $child();");
+ $childAttributes = array_keys($childInstance->pog_attribute_type);
+ if (array_search($thisObjectName, $childAttributes) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $child as {Child}, but $child does not refer to $thisObjectName as {Parent}. Relations need to be reciprocal.");
+ }
+ }
+ }
+
+ foreach ($parentsList as $parent)
+ {
+ if (array_search($parent, $allObjectsList) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $parent as parent, which couldn't be found. Generate the $parent object with reference to $thisObjectName as {Child}");
+ }
+ else
+ {
+ //test that parent refers to this object as child
+ eval ("\$parentInstance = new $parent();");
+ $parentAttributes = array_keys($parentInstance->pog_attribute_type);
+ if (array_search($thisObjectName, $parentAttributes) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $parent as {Parent}, but $parent does not refer to $thisObjectName as {Child}. Relations need to be reciprocal.");
+ }
+ }
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tests that all Joins have reciprocal links
+ *
+ * @param unknown_type $object
+ * @param unknown_type $allObjectsList
+ * @param unknown_type $thisObjectName
+ */
+ function TestAssociationLink($object, $allObjectsList, $thisObjectName = '', $ignoreObjects)
+ {
+ $attribute_types = $object->pog_attribute_type;
+
+ //get all join classes
+ $associationsList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $associationsList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($associationsList as $association)
+ {
+ if (array_search($association, $allObjectsList) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $association as {SIBLING}, which couldn't be found. Generate the $association object with reference to $thisObjectName as {SIBLING}");
+ }
+ else
+ {
+ //test that association refers to this object as map
+ eval ("\$associationInstance = new $association();");
+ $associationAttributes = array_keys($associationInstance->pog_attribute_type);
+ if (array_search($thisObjectName, $associationAttributes) === false)
+ {
+ $errors++;
+ AddError("$thisObjectName refers to $association as {SIBLING}, but $association does not refer to $thisObjectName as {SIBLING}. Relations need to be reciprocal.");
+ }
+ }
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test to see if object is a parent
+ *
+ * @param unknown_type $object
+ */
+ function TestIsParent($object)
+ {
+ $attribute_types = $object->pog_attribute_type;
+ foreach ($attribute_types as $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unit test to see if object is child
+ *
+ * @param unknown_type $object
+ */
+ function TestIsChild($object)
+ {
+ $attribute_types = $object->pog_attribute_type;
+ foreach ($attribute_types as $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "BELONGSTO")
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unit test to see if object is Sibling
+ *
+ * @param unknown_type $object
+ * @return unknown
+ */
+ function TestIsSibling($object)
+ {
+ $attribute_types = $object->pog_attribute_type;
+ foreach ($attribute_types as $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unit test to see if object is a Mapping object
+ *
+ * @param unknown_type $object
+ */
+ function TestIsMapping($object)
+ {
+ $funcs = get_class_methods(get_class($object));
+ foreach ($funcs as $func)
+ {
+ if (strtolower($func) == "addmapping")
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Save($deep)
+ *
+ * @param unknown_type $object
+ */
+ function TestSaveDeep_Child($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ if (!TestAddChild($object, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave(deep) ignored");
+ AddError("Save(deep) ignored since AddChild could not be performed");
+ }
+ return false;
+ }
+ if (!TestGetChildrenList($object, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave(deep) ignored");
+ AddError("Save(deep) ignored since GetChildrenList could not be performed");
+ }
+ return false;
+ }
+ if (!TestDeleteDeep_Child($object, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave(deep) ignored");
+ AddError("Save(deep) ignored since Delete(deep) could not be performed");
+ }
+ return false;
+ }
+
+ //get all child classes
+ $childrenList = array();
+ eval("\$object = new $thisObjectName();");
+ $object = PopulateTestValues($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval("\$childInstance = new $child();");
+ $childInstance = PopulateTestValues($childInstance);
+
+ //add children
+ eval ("\$object -> Add$child(\$childInstance);");
+ }
+
+ //test
+ if (!$object->Save(true))
+ {
+ $errors++;
+ return false;
+ }
+
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval("\$childArray = \$object->Get".$child."List();");
+ if (sizeof($childArray) == 0)
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave($child) failed");
+
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave($child)....OK!");
+ }
+ }
+ }
+
+ //cleanup
+ $object->Delete(true);
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Save($deep)
+ *
+ * @param unknown_type $object
+ * @return unknown
+ */
+ function TestSaveDeep_Sibling($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ if (!TestAddSibling($object, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave(deep) ignored");
+ AddError("Save(deep) ignored since AddSibling could not be performed");
+ }
+ return false;
+ }
+ if (!TestGetSiblingList($object, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave(deep) ignored");
+ AddError("Save(deep) ignored since GetSiblingList could not be performed");
+ }
+ return false;
+ }
+
+ //get all sibling classes
+ $siblingList = array();
+ eval("\$object = new $thisObjectName();");
+ $object = PopulateTestValues($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $siblingList[] = $key;
+ }
+ }
+
+ $errors = 0;
+
+ $siblingStore = array();
+
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval("\$siblingInstance = new $sibling();");
+ $siblingStore[] = $siblingInstance;
+ $siblingInstance = PopulateTestValues($siblingInstance);
+
+ //add children
+ eval ("\$object -> Add$sibling(\$siblingInstance);");
+ }
+
+ //test
+ if (!$object->Save(true))
+ {
+ $errors++;
+ return false;
+ }
+
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval("\$siblingArray = \$object->Get".$sibling."List();");
+ if (sizeof($siblingArray) == 0)
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave($sibling) failed");
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tSave($sibling)....OK!");
+ }
+ }
+ }
+
+ //cleanup
+ $object->Delete();
+ foreach($siblingStore as $stored)
+ {
+ $stored->Delete();
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Delete($deep)
+ *
+ * @param unknown_type $object
+ */
+ function TestDeleteDeep_Child($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ if (!TestSetParent($object, false, $ignoreObjects))
+ {
+ AddTrace("\tDelete(deep) ignored");
+ return false;
+ }
+ //get all child classes
+ $childrenList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ $errors = 0;
+
+ $object = PopulateTestValues($object);
+ $objectId = $object->Save(false);
+
+
+ $childrenStore = array();
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval("\$childInstance = new $child();");
+ $childInstance = PopulateTestValues($childInstance);
+ eval("\$childInstance -> Set".$thisObjectName."(\$object);");
+ $childInstance -> Save();
+ $childrenStore[] = &$childInstance;
+ }
+
+ //test
+ if (!$object->Delete(true))
+ {
+ $errors++;
+ }
+
+ foreach ($childrenList as $child)
+ {
+ eval("\$childInstance = new $child();");
+ $parentList = $childInstance->GetList(array(array(strtolower($thisObjectName)."Id", "=", $objectId)));
+ if (sizeof($parentList) > 0)
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete($child) failed");
+ $errors++;
+ }
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete($child)....OK!");
+ }
+ }
+ }
+
+ //cleanup
+ foreach ($childrenStore as $child);
+ {
+ $child->Delete();
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for Delete($deep)
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ */
+ function TestDeleteDeep_Sibling($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ if (!TestAddSibling($object, false, $ignoreObjects) || !TestSaveDeep_Sibling($object, false, $ignoreObjects))
+ {
+ AddTrace("\tDelete(deep) ignored");
+ return false;
+ }
+ //get all sibling classes
+ $siblingList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $siblingList[] = $key;
+ }
+ }
+
+ $errors = 0;
+
+ $object = PopulateTestValues($object);
+ $object->Save(false);
+
+ $siblingStore = array();
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval("\$siblingInstance = new $sibling();");
+ $siblingInstance = PopulateTestValues($siblingInstance);
+ eval("\$siblingInstance->Add".$thisObjectName."(\$object);");
+ $siblingId = $siblingInstance->Save();
+ $siblingStore[] = $siblingId;
+ }
+
+ //test
+ if (!$object->Delete(false, true))
+ {
+ $errors++;
+ }
+
+ $x = 0;
+ foreach ($siblingList as $sibling)
+ {
+ eval("\$siblingInstance = new $sibling();");
+ $siblingLeft = $siblingInstance->GetList(array(array(strtolower($sibling)."Id", "=", $siblingStore[$x])));
+ if (sizeof($siblingLeft) > 0)
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete($sibling) failed");
+ $errors++;
+ }
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tDelete($sibling)....OK!");
+ }
+ }
+ $x++;
+ }
+
+
+ //cleanup
+ $object->Delete();
+ $x = 0;
+ foreach ($siblingList as $sibling)
+ {
+ eval("\$siblingInstance = new $sibling();");
+ if (isset($siblingStore[$x]) && $siblingStore[$x] != '')
+ {
+ eval ("\$siblingInstance->".strtolower($sibling)."Id = ".$siblingStore[$x].";");
+ $siblingInstance->Delete();
+ }
+ $x++;
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for SetParent()
+ *
+ * @param unknown_type $object
+ */
+ function TestSetParent($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ //get all parent classes
+ $parentList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "BELONGSTO")
+ {
+ $parentList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($parentList as $parent)
+ {
+ //instantiate
+ eval("\$parentInstance = new $parent();");
+
+ //save
+ $parentInstance = PopulateTestValues($parentInstance);
+ $parentInstance -> Save(false);
+
+ //set parent
+ eval ("\$object -> Set$parent(\$parentInstance);");
+
+ eval ("\$objectId = \$object->".strtolower($parent)."Id;");
+
+ eval ("\$parentId = \$parentInstance->".strtolower($parent)."Id;");
+
+ if ($objectId != $parentId)
+ {
+ if ($trace)
+ {
+ AddTrace("\tSet$parent() failed");
+ AddError("Could not set $parent as {Parent} of $thisObjectName");
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tSet$parent()....OK!");
+ }
+ }
+ //cleanup (delete parent)
+ $parentInstance -> Delete(false);
+ eval ("\$object->".strtolower($parent)."Id = '';");
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for GetParent()
+ *
+ * @param unknown_type $object
+ */
+ function TestGetParent($object, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ eval ("\$object = new $thisObjectName();");
+
+ $attribute_types = $object->pog_attribute_type;
+
+ //get all parent classes
+ $parentList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "BELONGSTO")
+ {
+ $parentList[] = $key;
+ }
+ }
+
+ $errors = 0;
+
+ foreach ($parentList as $parent)
+ {
+ /*if (TestSetParent($object, false))
+ {*/
+ //instantiate
+ eval("\$parentInstance = new $parent();");
+
+ //save
+ $parentInstance = PopulateTestValues($parentInstance);
+ $parentInstance -> Save(false);
+
+
+ //set parent
+ eval ("\$object -> Set$parent(\$parentInstance);");
+
+ eval("\$myParent = \$object->Get$parent();");
+
+ eval ("\$objectId = \$object->".strtolower($parent)."Id;");
+
+ eval ("\$parentId = \$myParent->".strtolower($parent)."Id;");
+
+ if ($objectId != $parentId)
+ {
+ AddTrace("\tGet$parent() failed");
+ AddError("Could not retrieve parent object $parent");
+ $errors++;
+ }
+ else
+ {
+ AddTrace("\tGet$parent()....OK!");
+ }
+
+ //cleanup (delete parent)
+ $parentInstance -> Delete(false);
+ /*}
+ else
+ {
+ AddTrace("\tGet$parent() ignored");
+ }*/
+ }
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for AddChild()
+ *
+ * @param unknown_type $object
+ */
+ function TestAddChild($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ eval ("\$object = new $thisObjectName();");
+ $attribute_types = $object->pog_attribute_type;
+
+ $object = PopulateTestValues($object);
+
+ //get all child classes
+ $childrenList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval ("\$childInstance = new $child();");
+ $childInstance = PopulateTestValues($childInstance);
+
+ //instantiate other
+ eval("\$childInstance2 = new $child();");
+ $childInstance2 = PopulateTestValues($childInstance2);
+
+ //add children
+ eval ("\$object -> Add$child(\$childInstance);");
+ eval ("\$object -> Add$child(\$childInstance2);");
+
+ //verify that children were added
+
+ eval ("\$children = \$object->".strtolower($child)."List;");
+
+ if (sizeof($children) != 2)
+ {
+ if ($trace)
+ {
+ AddTrace("\tAdd$child() failed");
+ AddError("Could not add child object $child");
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tAdd$child()....OK!");
+ }
+ }
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for GetChildrenList()
+ *
+ * @param unknown_type $object
+ */
+ function TestGetChildrenList($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ eval ("\$object = new $thisObjectName();");
+ $attribute_types = $object->pog_attribute_type;
+ $errors = 0;
+
+ //get all child classes
+ $childrenList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ //save shallow
+ $object = PopulateTestValues($object);
+ $object->Save(false);
+
+
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval("\$childInstance = new $child();");
+ $childInstance = PopulateTestValues($childInstance);
+
+ if (!TestSetParent($childInstance, false, $ignoreObjects))
+ {
+ AddTrace("\tGetChildrenList() ignored");
+ return false;
+ }
+ eval("\$childInstance->Set".$thisObjectName."(\$object);");
+
+ $childInstance->Save();
+
+
+
+ //try getting all children
+ eval ("\$children = \$object -> Get".$child."List();");
+ if (sizeof($children) != 1)
+ {
+ AddTrace("\tGet".$child."List() failed");
+ AddError("Could not get children list");
+ $errors++;
+ }
+
+ //cleanup
+ $childInstance->Delete();
+
+ if ($errors == 0 && $trace)
+ {
+ AddTrace("\tGet".$child."List()....OK!");
+ }
+ }
+
+ $object->Delete(false);
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit Test for SetChildrenList
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ * @return unknown
+ */
+ function TestSetChildrenList($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ if (!TestSaveDeep_Child($object, false, $ignoreObjects))
+ {
+ AddTrace("\tSetChildrenList(deep) ignored");
+ AddError("SetChildrenList ignored since SaveDeep could not be performed");
+ return false;
+ }
+
+ //get all child classes
+ $childrenList = array();
+ eval("\$object = new $thisObjectName();");
+ $object = PopulateTestValues($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "HASMANY")
+ {
+ $childrenList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ $childInstanceList = array();
+ eval("\$childInstance = new $child();");
+ eval("\$childInstance2 = new $child();");
+ $childInstance = PopulateTestValues($childInstance);
+ $childInstance2 = PopulateTestValues($childInstance2);
+
+ //add children to array
+ $childInstanceList[] = $childInstance;
+ $childInstanceList[] = $childInstance2;
+
+ eval ("\$object -> Set".$child."List(\$childInstanceList);");
+ }
+
+ //test
+ if (!$object->Save(true))
+ {
+ $errors++;
+ return false;
+ }
+
+ foreach ($childrenList as $child)
+ {
+ //instantiate
+ eval("\$childArray = \$object->Get".$child."List();");
+ if (sizeof($childArray) == 0)
+ {
+ AddTrace("\tSet($child)List failed");
+ $errors++;
+ }
+ else
+ {
+ AddTrace("\tSet($child)List....OK!");
+ }
+ }
+
+ //cleanup
+ $object->Delete(true);
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit Test for AddSibling()
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ * @return unknown
+ */
+ function TestAddSibling($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ eval ("\$object = new $thisObjectName();");
+ $attribute_types = $object->pog_attribute_type;
+
+ $object = PopulateTestValues($object);
+
+ //get all sibling classes
+ $siblingList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $siblingList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval ("\$siblingInstance = new $sibling();");
+ $siblingInstance = PopulateTestValues($siblingInstance);
+
+ //instantiate other
+ eval("\$siblingInstance2 = new $sibling();");
+ $siblingInstance2 = PopulateTestValues($siblingInstance2);
+
+ //add sibling
+ eval ("\$object -> Add$sibling(\$siblingInstance);");
+ eval ("\$object -> Add$sibling(\$siblingInstance2);");
+
+ //verify that slbings were added
+ eval ("\$siblings = \$object->".strtolower($sibling)."List;");
+
+ if (sizeof($siblings) != 2)
+ {
+ if ($trace)
+ {
+ AddTrace("\tAdd$sibling() failed");
+ AddError("Could not add sibling object $sibling");
+ }
+ $errors++;
+ }
+ else
+ {
+ if ($trace)
+ {
+ AddTrace("\tAdd$sibling()....OK!");
+ }
+ }
+ }
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for GetSiblingList()
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ * @return unknown
+ */
+ function TestGetSiblingList($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ eval ("\$object = new $thisObjectName();");
+ $attribute_types = $object->pog_attribute_type;
+ $errors = 0;
+
+ //get all sibling classes
+ $siblingList = array();
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $siblingList[] = $key;
+ }
+ }
+
+ $object = PopulateTestValues($object);
+
+ $siblingsStore = array();
+
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval("\$siblingInstance = new $sibling();");
+ $siblingsStore[] = $siblingInstance;
+ $siblingInstance = PopulateTestValues($siblingInstance);
+
+ if (!TestAddSibling($siblingInstance, false, $ignoreObjects))
+ {
+ if ($trace)
+ {
+ AddTrace("\tGetSiblingList() ignored");
+ }
+ return false;
+ }
+ eval("\$object->Add".$sibling."(\$siblingInstance);");
+
+ }
+
+ $object->Save();
+
+ foreach ($siblingList as $sibling)
+ {
+
+ //try getting all siblings
+ eval ("\$siblings = \$object -> Get".$sibling."List();");
+ if (sizeof($siblings) != 1)
+ {
+ if ($trace)
+ {
+ AddTrace("\tGet".$sibling."List() failed");
+ AddError("Could not get sibling list");
+ }
+ $errors++;
+ }
+ else if ($trace)
+ {
+ AddTrace("\tGet".$sibling."List()....OK!");
+ }
+ }
+
+ foreach ($siblingsStore as $stored)
+ {
+ $stored->Delete();
+ }
+
+ $object->Delete(false);
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unit test for SetSiblingList()
+ *
+ * @param unknown_type $object
+ * @param unknown_type $trace
+ */
+ function TestSetSiblingList($object, $trace = true, $ignoreObjects)
+ {
+ $thisObjectName = get_class($object);
+ if (!TestSaveDeep_Sibling($object, false, $ignoreObjects))
+ {
+ AddTrace("\tSetSiblingList(deep) ignored");
+ AddError("SetSiblingList ignored since SaveDeep could not be performed");
+ return false;
+ }
+
+ //get all sibling classes
+ $siblingList = array();
+ eval("\$object = new $thisObjectName();");
+ $object = PopulateTestValues($object);
+ $attribute_types = $object->pog_attribute_type;
+
+ foreach ($attribute_types as $key => $attribute_array)
+ {
+ if ($attribute_array['db_attributes'][1] == "JOIN")
+ {
+ $siblingList[] = $key;
+ }
+ }
+
+ $errors = 0;
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ $siblingInstanceList = array();
+ eval("\$siblingInstance = new $sibling();");
+ eval("\$siblingInstance2 = new $sibling();");
+ $siblingInstance = PopulateTestValues($siblingInstance);
+ $siblingInstance2 = PopulateTestValues($siblingInstance2);
+
+ //add sibling to array
+ $siblingInstanceList[] = $siblingInstance;
+ $siblingInstanceList[] = $siblingInstance2;
+
+ eval ("\$object -> Set".$sibling."List(\$siblingInstanceList);");
+ }
+
+ //test
+ if (!$object->Save(true))
+ {
+ $errors++;
+ return false;
+ }
+
+ foreach ($siblingList as $sibling)
+ {
+ //instantiate
+ eval("\$siblingArray = \$object->Get".$sibling."List();");
+ if (sizeof($siblingArray) == 0)
+ {
+ if ($trace)
+ {
+ AddTrace("\tSet($sibling)List failed");
+ }
+ $errors++;
+ }
+ else if ($trace)
+ {
+ AddTrace("\tSet($sibling)List....OK!");
+ }
+ }
+
+ //cleanup
+ $object->Delete(false, true);
+
+ if ($errors == 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Creates the mapping name
+ *
+ * @param unknown_type $objectName1
+ * @param unknown_type $objectName2
+ * @return unknown
+ */
+ function MappingName($objectName1, $objectName2)
+ {
+ $array = array($objectName1, $objectName2);
+ sort($array);
+ return implode($array)."Map";
+ }
+
+ /**
+ * Gets total no. of records;
+ */
+ function GetNumberOfRecords($objectName)
+ {
+ $sql = 'select count(*) from `'.strtolower($objectName)."`";
+ $connection = Database::Connect();
+ $cursor = Database::Reader($sql, $connection);
+ if ($cursor !== false)
+ {
+ while($row = Database::Read($cursor))
+ {
+ return $row['count(*)'];
+ }
+ }
+ return 0;
+ }
+?> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/upgrade.php b/backend/php/src/setup/setup_library/upgrade.php
new file mode 100644
index 0000000..122da58
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/upgrade.php
@@ -0,0 +1,140 @@
+<?php
+/**
+* @author Joel Wan & Mark Slemko. Designs by Jonathan Easton
+* @link http://www.phpobjectgenerator.com
+* @copyright Offered under the BSD license
+*
+* This upgrade file does the following:
+* 1. Checks if there is a new version of POG
+* 2. If there is, it reads generates newer versions of all objects in the object directory,
+* zip then and present them to the user to 'download'
+*/
+ini_set("max_execution_time", 0);
+include_once "../../configuration.php";
+include_once "class.zipfile.php";
+include_once "setup_misc.php";
+
+ /**
+ * Connects to POG SOAP server defined in configuration.php and
+ * generates new versions of all objects detected in /objects/ dir.
+ * All upgraded objects are then zipped and presented to user.
+ *
+ * @param string $path
+ */
+ function UpdateAllObjects($path)
+ {
+ $dir = opendir($path);
+ $objects = array();
+ while(($file = readdir($dir)) !== false)
+ {
+ if(strlen($file) > 4 && substr(strtolower($file), strlen($file) - 4) === '.php' && !is_dir($file) && $file != "class.database.php" && $file != "configuration.php" && $file != "setup.php" && $file != "class.pog_base.php")
+ {
+ $objects[] = $file;
+ }
+ }
+ closedir($dir);
+ $i = 0;
+ foreach($objects as $object)
+ {
+ $content = file_get_contents($path."/".$object);
+ $contentParts = split("<b>",$content);
+ if (isset($contentParts[1]))
+ {
+ $contentParts2 = split("</b>",$contentParts[1]);
+ }
+ if (isset($contentParts2[0]))
+ {
+ $className = trim($contentParts2[0]);
+ }
+ if (isset($className))
+ {
+ eval ('include_once("../../objects/class.'.strtolower($className).'.php");');
+ $instance = new $className();
+ if (!TestIsMapping($instance))
+ {
+ $objectNameList[] = $className;
+
+ $linkParts1 = split("\*\/", $contentParts[1]);
+ $linkParts2 = split("\@link", $linkParts1[0]);
+ $link = $linkParts2[1];
+ $options = false;
+ if ($GLOBALS['configuration']['proxy_host'] != false &&
+ $GLOBALS['configuration']['proxy_port'] != false &&
+ $GLOBALS['configuration']['proxy_username'] != false &&
+ $GLOBALS['configuration']['proxy_password'] != false)
+ {
+ $options = array(
+ 'proxy_host' => $GLOBALS['configuration']['proxy_host'],
+ 'proxy_port' => $GLOBALS['configuration']['proxy_port'],
+ 'proxy_login' => $GLOBALS['configuration']['proxy_username'],
+ 'proxy_password' => $GLOBALS['configuration']['proxy_password']
+ );
+ }
+ $client = new SoapClient(
+ $GLOBALS['configuration']['soap'],
+ $options) ;
+ if ($i == 0)
+ {
+ $package = unserialize($client->GeneratePackageFromLink($link));
+ }
+ else
+ {
+ $objectString = $client->GenerateObjectFromLink($link);
+ $package["objects"]["class.".strtolower($className).".php"] = $objectString;
+ }
+ }
+ }
+ $i++;
+ }
+
+
+ //upgrade mapping classes if any
+ foreach ($objectNameList as $objectName)
+ {
+ $instance = new $objectName();
+ foreach ($instance->pog_attribute_type as $key => $attribute_type)
+ {
+ if ($attribute_type['db_attributes'][1] == "JOIN")
+ {
+ $mappingString = $client->GenerateMapping($objectName, $key, (isset($GLOBALS['configuration']['pdoDriver']) ? 'php5.1' :'php5'), (isset($GLOBALS['configuration']['pdoDriver']) ? 'pdo' :'pog'), (isset($GLOBALS['configuration']['pdoDriver']) ? 'mysql' :''));
+ $package["objects"]['class.'.strtolower(MappingName($objectName, $key)).'.php'] = $mappingString;
+ }
+ }
+ }
+
+ $zipfile = new createZip();
+ $zipfile -> addPOGPackage($package);
+ $zipfile -> forceDownload("pog.".time().".zip");
+ }
+
+ /**
+ * Checks if POG generator has been updated
+ *
+ * @return unknown
+ */
+ function UpdateAvailable()
+ {
+ $client = new SoapClient($GLOBALS['configuration']['soap']);
+ $generatorVersion = base64_decode($client -> GetGeneratorVersion());
+ if ($generatorVersion != $GLOBALS['configuration']['versionNumber'].$GLOBALS['configuration']['revisionNumber'])
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (UpdateAvailable())
+ {
+ UpdateAllObjects("../../objects/");
+ }
+ else
+ {
+ echo "<script>
+ alert('All POG objects are already up to date');
+ window.close();
+ </script>";
+ }
+?> \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/xPandMenu.css b/backend/php/src/setup/setup_library/xPandMenu.css
new file mode 100644
index 0000000..744debe
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/xPandMenu.css
@@ -0,0 +1,55 @@
+#container {
+ width:500px;
+ background-color:#E7E9EE;
+}
+.Xtree, .XtreeRoot {
+ list-style-type:none;
+ margin:15px 20px;
+}
+.Xtree {
+ /* Indentation of a sub-item compared to its parent */
+ padding-left:25px;
+ margin-left:3px;
+ border-left:1px dotted #998D05;
+ width:100%;
+}
+.Xnode {
+ /* Top and bottom space for a node item */
+ margin-top:-3px;margin-bottom:3px;
+ /* Height of the node item */
+ height:20px;
+ /* Node background color */
+ background:#E7E9EE;
+ /* Font specifications for a node */
+ font-weight:bold;
+ font-size:10px;
+ cursor:pointer;
+ vertical-align:middle;
+ width:100%;
+}
+.Xnode img{ vertical-align:middle; }
+.Xleaf {
+ /* Top and bottom space for a leaf item */
+ margin-top:-10px;margin-bottom:1px;
+ /* Height of the leag item */
+ /* Leaf background color */
+ /* Font specifications for a leaf */
+ font-weight:normal;
+ font-size:10px;
+ padding:2px;
+}
+.Xnode a {
+ text-decoration:none;
+}
+.Xnode a:hover {
+ color:red;
+ text-decoration:underline;
+}
+.Xleaf a {
+ text-decoration:none;
+}
+.Xleaf a:hover {
+ color:red;
+ text-decoration:none;
+ background:#eee;
+} \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/xPandMenu.js b/backend/php/src/setup/setup_library/xPandMenu.js
new file mode 100644
index 0000000..7f9a632
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/xPandMenu.js
@@ -0,0 +1,273 @@
+/********************************
+* xPandMenu MULTI-LEVEL class
+*********************************
+* Javascript file
+*********************************
+* Patrick Brosset
+* patrickbrosset@gmail.com
+*********************************
+* 02/2005
+*********************************/
+
+
+// Show / hide a sub-menu
+function xMenuShowHide(obj)
+{
+
+ if(obj.style.display == 'none'){
+ obj.style.display = 'block';
+ }else{
+ obj.style.display = 'none';
+ }
+
+}
+
+
+// Toggle expanded / collapsed versions of items' images
+function xSwapImg(imgDiv,srcImg,srcAltImg){
+
+ /* Update by Christian Vallee <cv@valtechnologie.com>
+ ==> No need to specify absolute URL for images anymore, this feature will find it on its own */
+
+ // looking for the images' root URL based on the current image
+ var str = imgDiv.src;
+ var pos = str.search(srcImg);
+ // if the URL root wasn't found using the first image, try with the alternative one
+ if ( pos == -1 ) { pos = str.search(srcAltImg); }
+ // extracting the URL root
+ var root = str.substring(0,pos);
+ // adding the root the image path supplied
+ srcImg = root.concat(srcImg);
+ srcAltImg = root.concat(srcAltImg);
+
+ /* End Update */
+
+ if(imgDiv.src == srcImg){
+ imgDiv.src = srcAltImg;
+ }else{
+ imgDiv.src = srcImg;
+ }
+
+}
+
+
+// Restore the menu state when the page loads
+function xRestoreState()
+{
+ //restore list state
+ var name = "xMenuState";
+ var start = document.cookie.indexOf(name+"=");
+ if(start != -1)
+ {
+ var len = start+name.length+1;
+ if ((!start) && (name != document.cookie.substring(0,name.length))) return null;
+ if (start == -1) return null;
+ var end = document.cookie.indexOf(";",len);
+ if (end == -1) end = document.cookie.length;
+ var value = unescape(document.cookie.substring(len,end));
+ var values = value.split("|");
+ for(i=0;i<values.length-1;i++)
+ {
+ var couple = values[i].split(":");
+ document.getElementById(couple[0]).style.display = couple[1];
+ }
+ }
+ //restore img state
+ name = "xMenuStateImg";
+ start = document.cookie.indexOf(name+"=");
+ if(start != -1)
+ {
+ var len = start+name.length+1;
+ if ((!start) && (name != document.cookie.substring(0,name.length))) return null;
+ if (start == -1) return null;
+ var end = document.cookie.indexOf(";",len);
+ if (end == -1) end = document.cookie.length;
+ var value = unescape(document.cookie.substring(len,end));
+ var values = value.split("[]");
+ for(i=0;i<values.length-1;i++)
+ {
+ var couple = values[i].split(">>");
+ var imgs = couple[1].split(",");
+ for(var il in imgs)
+ {
+ document.getElementById(imgs[il]).src = couple[0];
+ }
+ }
+ }
+}
+
+//Get the ids of all open nodes
+function getOpenNodes()
+{
+ value = new Array();
+ var myLists = document.getElementsByTagName("UL");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].className == "Xtree" && myLists[i].style.display == "block") value += myLists[i].id + "-";
+ }
+ return value;
+}
+
+// Save the menu state when the page unloads
+function xSaveState()
+{
+ //Save list state
+ var value = "";
+ var myLists = document.getElementsByTagName("UL");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].className == "Xtree") value += myLists[i].id + ":" + myLists[i].style.display + "|";
+ }
+ document.cookie = "xMenuState=" + escape(value) + ";";
+ //save img state
+ value = new Array();
+ myLists = document.getElementsByTagName("IMG");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].id.substring(0,4) == "Ximg")
+ {
+ if(value[myLists[i].src]){value[myLists[i].src] += "," + myLists[i].id;}
+ else{value[myLists[i].src] = myLists[i].id;}
+ }
+ }
+ var str = "";
+ for(var imgPath in value)
+ {
+ str += imgPath + ">>" + value[imgPath] + "[]";
+ }
+ var cook = str.substring(0,str.length-2);
+ document.cookie = "xMenuStateImg=" + escape(cook) + ";";
+}
+
+function createRequestObject()
+{
+ var ro;
+ if (window.XMLHttpRequest)
+ {
+ ro = new XMLHttpRequest();
+ }
+ else
+ {
+ ro = new ActiveXObject('MSXML2.XMLHTTP.3.0');
+ }
+ return ro;
+}
+
+var http = createRequestObject();
+
+function refTree(offset, limit, objectName)
+{
+ http = createRequestObject();
+ var req = './rpc.php?action=Refresh&offset='+offset+'&limit='+limit+'&objectname='+objectName;
+ http.open('get', req);
+ http.onreadystatechange = handleResponse;
+ http.send(null);
+}
+
+function sndReq(action, openNodes, objectName, objectId, currentNode, attributes, anchor)
+{
+
+
+ http = createRequestObject();
+ var req = './rpc.php?action='+action+'&opennodes='+openNodes+'&objectname='+objectName+'&objectid='+objectId+'&currentnode='+currentNode+'&anchor='+anchor;
+ if (action == "Add")
+ {
+ for (i=0; i<attributes.length; i++)
+ {
+ thisId = attributes[i];
+ var thisInput = document.getElementById(thisId);
+ if (thisInput != null)
+ {
+ if (thisInput.type == "checkbox")
+ {
+ if (thisInput.checked)
+ {
+ req += "&" + thisId + "=" + thisInput.value;
+ }
+ }
+ else
+ {
+ req += "&" + thisId + "=" + thisInput.value;
+ }
+ }
+ }
+ }
+ else if (action == "Update")
+ {
+ for (i=0; i<attributes.length; i++)
+ {
+ thisId = attributes[i];
+ var thisInput = document.getElementById(thisId+"_"+objectId);
+ if (thisInput.type == "checkbox")
+ {
+ if (thisInput.checked)
+ {
+ req += "&" + thisId + "=" + thisInput.value;
+ }
+ }
+ else
+ {
+ req += "&" + thisId + "=" + thisInput.value;
+ }
+ }
+ }
+ http.open('get', req);
+ http.onreadystatechange = handleResponse;
+ http.send(null);
+}
+
+function handleResponse()
+{
+ if(http.readyState == 4)
+ {
+ var response = http.responseText;
+ document.getElementById('container').innerHTML = response;
+ }
+}
+
+function expandAll()
+{
+ var myLists = document.getElementsByTagName("UL");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].className == "Xtree" && myLists[i].style.display == "none") myLists[i].style.display = "block";
+ }
+ myLists = document.getElementsByTagName("IMG");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].id.substring(0,4) == "Ximg")
+ {
+ myLists[i].src = "setup_images/folderopen.gif";
+ }
+ }
+}
+
+function collapseAll()
+{
+ var myLists = document.getElementsByTagName("UL");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].className == "Xtree" && myLists[i].style.display == "block") myLists[i].style.display = "none";
+ }
+ myLists = document.getElementsByTagName("IMG");
+ for(i=0;i<myLists.length;i++)
+ {
+ if(myLists[i].id.substring(0,4) == "Ximg")
+ {
+ myLists[i].src = "setup_images/folderclose.gif";
+ }
+ }
+}
+
+function ToggleElementVisibility(elementId)
+{
+ var element = document.getElementById(elementId);
+ if (element.style.display != 'none')
+ {
+ element.style.display = 'none';
+ }
+ else
+ {
+ element.style.display = 'inline';
+ }
+} \ No newline at end of file
diff --git a/backend/php/src/setup/setup_library/xPandMenu.php b/backend/php/src/setup/setup_library/xPandMenu.php
new file mode 100644
index 0000000..d9c7d07
--- a/dev/null
+++ b/backend/php/src/setup/setup_library/xPandMenu.php
@@ -0,0 +1,233 @@
+<?php
+
+/********************************
+* xPandMenu MULTI-LEVEL class
+*********************************
+* Creates a tree-view menu.
+* The menu can be as deep as needed
+* The menu items are organised in HTML unordered lists
+* Container nodes can be expanded/collapsed thanks to Javascript actions
+*********************************
+* Patrick Brosset
+* patrickbrosset@gmail.com
+*********************************
+* 02/2005
+*********************************/
+
+
+
+// Path to default image files (directories and documents icons) -- (use absolute URL)
+define('NODE_DEFAULT_IMG','http://project.zoe.co.nz/patrick/xpand/multi/images/folder_win.gif');
+define('LEAF_DEFAULT_IMG','http://project.zoe.co.nz/patrick/xpand/multi/images/document_win.gif');
+define('NODE_DEFAULT_ALT_IMG','http://project.zoe.co.nz/patrick/xpand/multi/images/folder_win_o.gif');
+define('LEAF_DEFAULT_ALT_IMG','http://project.zoe.co.nz/patrick/xpand/multi/images/document_win_o.gif');
+
+// Reference to the File class for saving and loading the generated menu
+//include_once 'File.php';
+
+
+
+// Xmenu class
+class XMenu
+{
+
+
+ // Sub-nodes contained in this menu (references to Xnode objects)
+ var $items = array();
+
+ // Keeps track of the HTML code indent to use (formatting of UL and LI)
+ var $indent;
+
+ // Is it the first node ?
+ var $first;
+
+ // Used for assigning unique IDs to HTML elements (for the javascript function)
+ var $treeCount;
+
+ // Same for images
+ var $imgCount;
+
+ // Contains the generated HTML code
+ var $output;
+
+ // Contains the nodes to expand when generating tree
+ var $visibleNodes = array("1");
+
+
+
+ // Constructor
+ function XMenu()
+ {
+ $this->indent = 0;
+ $this->first = true;
+ $this->treeCount = 0;
+ $this->imgCount = 0;
+ $this->output = "";
+ }
+
+
+
+ // addItem, adds a child to this menu
+ // Takes a XNode object reference as argument
+ function &addItem(&$node)
+ {
+ $this->items[] = &$node;
+ return $this->items[count($this->items) - 1];
+ }
+
+
+
+ // generateTree, generates the HTML code (UL list) for the dynamic tree-view
+ function generateTree($root = false)
+ {
+ if(!$root) $root = $this;
+
+ if($this->first){
+ $this->output .= $this->codeIndent()."<ul id=\"XRoot\" class=\"XtreeRoot\">\n";
+ $this->first = false;
+ }else{
+ if (array_search($this->treeCount, $this->visibleNodes) !== false)
+ {
+ $this->output .= $this->codeIndent()."<ul id=\"Xtree".$this->treeCount."\" class=\"Xtree\" style=\"display:block;\">\n";
+ }
+ else
+ {
+ $this->output .= $this->codeIndent()."<ul id=\"Xtree".$this->treeCount."\" class=\"Xtree\" style=\"display:none;\">\n";
+ }
+ }
+ $this->treeCount ++;
+ foreach($root->items as $myChild){
+ $this->imgCount ++;
+ if($myChild->img){
+ if($myChild->alt_img){
+ $img_js = "xSwapImg(document.getElementById('Ximg".$this->imgCount."'),'".$myChild->img."','".$myChild->alt_img."');";
+ }else{
+ $img_js = "";
+ }
+ if (array_search($this->treeCount, $this->visibleNodes) !== false)
+ {
+ $img = "<img onClick=\"".$img_js."xMenuShowHide(document.getElementById('Xtree".$this->treeCount."'));\" id=\"Ximg".$this->imgCount."\" src=\"".$myChild->alt_img."\" border=\"0\">&nbsp;&nbsp;";
+ }
+ else
+ {
+ $img = "<img onClick=\"".$img_js."xMenuShowHide(document.getElementById('Xtree".$this->treeCount."'));\" id=\"Ximg".$this->imgCount."\" src=\"".$myChild->img."\" border=\"0\">&nbsp;&nbsp;";
+ }
+ }else{
+ $img = "";$img_js = "";
+ }
+ if($myChild->link){
+ $href_open = "<a href=\"".$myChild->link."\">";
+ $href_close = "</a>";
+ }else{
+ $href_open = "";
+ $href_close = "";
+ }
+ if(count($myChild->items) != 0){
+ $this->output .= $this->codeIndent()."<li class=\"Xnode\" id=\"Xnode".$this->treeCount."\"><div>".$href_open.$img.$myChild->name.$href_close."</div></li>\n";
+ $this->indent ++;
+ $this->generateTree($myChild);
+ }else{
+ $this->output .= $this->codeIndent()."<li class=\"Xleaf\"><div onClick=\"".$img_js."\">".$href_open.$img.$myChild->name.$href_close."</div></li>\n";
+ }
+ }
+ $this->output .= $this->codeIndent()."</ul>\n";
+ $this->indent --;
+
+ return $this->output;
+ }
+
+
+
+ // saveTree and restoreTree - thanks to Niels Fanoe (niels.f@noee.dk) for giving me the idea
+
+ // saveTree, save the generated HTML code to a file for future use without generating again
+ function saveTree($filename = "xMenuCache.html")
+ {
+ $file = new File();
+ $file->write($this->output,$filename);
+ $file->printError();
+ return $filename;
+ }
+
+
+
+ // restoreTree, returns the previously generated HTML code stored in a file
+ // Call this method STATICALLY for easier use: XMenu::restoreTree("xPandMenuCode.html");
+ function restoreTree($filename = "xMenuCache.html")
+ {
+ $file = new File();
+ $menu = $file->read($filename);
+ $error = $file->getError();
+ if(!empty($error)) return false;
+ else return $menu;
+ }
+
+
+
+ // codeIndent, only used to create a nice and readable HTML code (indents the UL and LI tags)
+ function codeIndent()
+ {
+ $str = "";
+ for($i=0;$i<$this->indent;$i++){
+ $str .= " ";
+ }
+ return $str;
+ }
+
+
+}
+
+
+
+
+// XNode class: A node item in the menu
+class XNode
+{
+
+
+ // Name assigned to this node (Text shown on the item)
+ var $name;
+
+ // Link for the item (if any)
+ var $link;
+
+ // Sub-items of this node
+ var $items = array();
+
+ // Absolute URL of this node's icon
+ var $img;
+
+ // Absolute URL of this node's icon (alternate, used for expanded and collapsed states)
+ var $alt_img;
+
+
+
+ // constructor
+ // $name: text shown for this item
+ // $link: where does this item links to when clicked (optional)
+ // $img and $alt_img: images displayed next to this item (absolute paths to images must be used)
+ function XNode($name,$link = false,$img = LEAF_DEFAULT_IMG,$alt_img = LEAF_DEFAULT_ALT_IMG)
+ {
+ $this->name = $name;
+ $this->link = $link;
+ $this->img = $img;
+ $this->alt_img = $alt_img;
+ }
+
+
+
+ // addItem, adds a subnode under this node
+ // Takes a XNode object reference as argument
+ function &addItem(&$node)
+ {
+ if($this->img == LEAF_DEFAULT_IMG){$this->img = NODE_DEFAULT_IMG;}
+ if($this->alt_img == LEAF_DEFAULT_ALT_IMG){$this->alt_img = NODE_DEFAULT_ALT_IMG;}
+ $this->items[] = &$node;
+ return $this->items[count($this->items) - 1];
+ }
+
+
+
+}
+
+?> \ No newline at end of file