Location: PHPKode > projects > Dark Hart Portal > darkportal/template.xml.php
<?php
/**
* Theme
*
* The theme contains all the zones, blocks and elements needed to compose
* a HTML template of the interface to display. When the display method is called, 
* all the various items are parsed and composed to create the final HTML result.
*
* @version  0.3
* @author   Fred Hirsch
* @copyright  Dark Hart Design  2001, 2002
* @package CORE
*/

class Theme {
  var $id;
  var $tconfig = array();
  var $dbtable = array();
  var $tmeta = array();
  var $elements;
  var $blocks;
  var $b_order;    
  var $zones;
  var $data = array();
  var $zoneID;
  var $blockID;
  var $blockAppend;
  var $name;
  var $content;
  var $parsed_text;
  var $debug;

/**
* Theme Constructor
*
* Creates the theme object and performs the initialization to load the config
* and meta data loading. A new template object is also generated in this step.
*
* @param  integer $theme The id number for the theme to create.
* @return VOID
*/
  function Theme($theme = '') {
    global $dbh, $config, $dbtable;

    $this->setupXMLParser();
    $this->id = $theme;
    $this->dbtable = $dbtable;

    // Performing theme initialization steps.
    empty ($this->tconfig) ? $this->getThemeConfig() : '';
    $this->getThemeMeta();

    $this->debug = 1;
    $this->initTheme();

    $this->assign('config', $config);
  }

  function setupXMLParser() { 
    $this->parser = xml_parser_create();
    xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 1);
    xml_set_element_handler($this->parser, "XMLStartElement", "XMLEndElement");
    xml_set_character_data_handler($this->parser, "XMLCharacterData");
    xml_set_processing_instruction_handler($this->parser, "XMLPIHandler");
    xml_set_default_handler($this->parser, "XMLDefaultHandler");
    xml_set_external_entity_ref_handler($this->parser, "XMLExtEntityRefHandler");
  }

  function XMLStartElement($parser, $name, $attribs) {
  }
  function XMLEndElement($parser, $name) {
  }
  function XMLCharacterData($parser, $data) {
  }
  function XMLPIHandler($parser, $target, $data) {
  }
  function XMLDefaultHandler($parser, $data) {
  }
  function XMLExtEntityRefHandler($parser, $openEntityNames, $base, $systemID, $publicID) {
  }  
/**
* Get Theme Configuration
*
* Loads the theme configuration from the database. This currently relies on
* a theme config to be setup during a theme addition or copy. We need to
* create interfaces for changing the theme config.
*
* @return VOID
*/
  function getThemeConfig() {
    global $dbh;

    list($dbt, $dbc) = array_values($this->dbtable[theme_config]);
    $tid_q = $dbh->qstr($this->id);
    $sql = "select $dbc[name], $dbc[value] from $dbt where $dbc[theme] in ($tid_q, '')";
    $result = $dbh->Execute($sql) or trigger_error("Theme configuration load failed.", FATAL);
    
    while(list($name, $value) = $result->fields) {
      $this->tconfig[$name] = $value;
      $result->MoveNext();
    }
  }

/**
* Get Theme MetaData
*
* Theme meta data is inserted into META HTML headers in the portal interface
* code. This helps to solidify the portal in search engine queries. This will
* eventually be expanded to allow meta data based on block level meta-data.
*
* @return VOID
*/
  function getThemeMeta() {
    global $dbh;

    list($dbt,$dbc) = array_values($this->dbtable[theme_meta]);
    $tid_q = $dbh->qstr($this->id);
    $sql = "select $dbc[name], $dbc[value] from $dbt where ($dbc[theme] = $tid_q or $dbc[theme] = '0')";
    $result = $dbh->Execute($sql) or trigger_error('Theme meta data load failed.', FATAL);
    while (list($name, $value) = $result->fields) {
      $this->tmeta[$name] = $value;
      $result->MoveNext();
    }
  }

/**
* Display Theme
*
* Displays the theme by causing the template to self-parse its contents.
* This is done block by block, element by element and then organized into
* the theme by zones. 
*
* @return String Output of parsed HTML from the template parsing.
*/
  function &display() {
    global $error;
    
    $this->getMetaElement();
    $this->assign('error', $error);
    $this->parse();
    $output .= $this->getparse();
    return $output;
  }
  
/**
* Initialize Template
* 
* Initialization of the template first removes any data from the current zone, block
* and element arrays. The template core content is then loaded and the Elements and
* Zones are loaded. Elements are loaded first to ensure that any recursion issues are
* met before the blocks might be dynamically loaded.
*
* @return VOID
* @see getTemplate, getElements, getZones
*/
  function initTheme() {
    unset ($this->zones);
    unset ($this->blocks);
    unset ($this->b_order);
    unset ($this->elements);
    
    list($this->name,$this->content) = $this->getTemplate();
    $this->parsed_text = '';
    $this->getElements();
    $this->getZones();
  }

/**
* Get Template
*
* Pulls the name and content from the database theme table and returns 
* an array containing the theme name and raw content information. This raw
* content should only contain basic HTML elements and the zone layout using
* <[zone]> tags.
*
* @return Array The database result set of the theme information.
*/

  function &getTemplate() {
    global $dbh;

    list($dbt, $dbc) = array_values($this->dbtable[theme]);
    $tid_q = $dbh->qstr($this->id);
    $sql = "select $dbc[name], $dbc[content] from $dbt where $dbc[id] = $tid_q";
    $result = $dbh->Execute($sql) or trigger_error('Could not load theme.');
    return $result->fields;
  }
  
/**
* Get Zones
*
* Loads the zones for the theme based on how the zones are defined in the 
* database. This operation is independent of the zone definition in the theme
* content. After the zones are loaded, all blocks are then loaded into the blocks
* array. In previous versions, multiple database calls were made for each zone.
* Now all blocks are loaded in a single call.
*
* @return VOID
* @see getBlocks
*/
  function getZones() {
    global $dbh;

    list($dbt, $dbc) = array_values($this->dbtable[zone]);
    $tid_q = $dbh->qstr($this->id);
    $sql = <<<END_SQL
      SELECT $dbc[id], $dbc[name], $dbc[content] from $dbt
      where $dbc[theme] in ($tid_q, 0) 
      and $dbc[active] = 1
END_SQL;
    $result = $dbh->Execute($sql) or trigger_error("Could not load zones for theme. ", FATAL);
    while ($data = $result->fields) {
      $this->zones[$data[name]] = $data;
      $this->zones[$data[id]] =& $this->zones[$data[name]];
      $result->MoveNext();
      $zone_list[$data[name]] = array(name => $data[name], id => $data[id]);
      $zone_list[$data[id]] = array(name => $data[name], id => $data[id]);
    }
    (sizeof($zone_list) > 0) ? $this->getBlocks($zone_list) : '';
  }

/**
* Get Blocks
* 
* Loads the blocks based on a list of zones provided by the getZones method. This
* method loads blocks on two levels. It first will load all the blocks needed to
* build the interface using its operation. It will then load any user specific 
* blocks which were configured in the user's preferences.
* Note that there are several "default" block types which need to be consolidated.
* global block types should be universal in type of interface and operation. This
* universal type should also be added to the block editors.
*
* @param Array $zones Contains all information needed to build the zone list for loading the blocks.
* @return VOID
* @see getZones
*/
  function getBlocks($zones) {
    global $dbh;
    global $gui;
    global $userinfo;
    global $config;
    while (list($k,$v) = each($zones)) {
      $zones_q[] = $dbh->qstr($k);
    }
    $zone_list = implode (', ', $zones_q);
    
    // New interface selection building
    $interfaces = array("'_ALL_'", "'default'");
    $itypes = explode(".", $gui->interface);
    for($i = 0; $i < sizeof($itypes); $i++) {
      $current .= ($i == 0) ? $itypes[$i] : "." . $itypes[$i];
      $interfaces[] = $dbh->qstr($current);
    }
    $interface_list = implode (', ', $interfaces);
            
    // First, pull the default and interface/operation specific blocks.
    list($dbt, $dbc) = array_values($this->dbtable[block]);
    $tid_q = $dbh->qstr($this->id);
    $tid_parent_q = $dbh->qstr($this->tconfig[parent_theme]);
    $tid_base_q = $dbh->qstr($config[base_theme]);
    $oper_q = $dbh->qstr($gui->operation);    

    $sql = <<<END_SQL
select $dbc[id], $dbc[title], $dbc[content], $dbc[code], $dbc[zone], $dbc[interface], $dbc[multi]
from $dbt
where $dbc[theme] in ($tid_q, $tid_parent_q, $tid_base_q)
and $dbc[zone] in ($zone_list)
and $dbc[interface] in ($interface_list) 
and $dbc[operation] in ($oper_q, '_ALL_')
order by ord
END_SQL;

    $result = $dbh->Execute($sql) or trigger_error("Block load failed for theme.");
    while( $data = $result->fields){
      $this->zoneID = $zones[$data[zone]][id];
      $this->blocks[$data[id]] = $data;
      $this->b_order[$zones[$data[zone]][name]][] =& $this->blocks[$data[id]];
      $done_blocks[$data[id]] = true;
/** 
* We need to check if the block needs to perform any special work to get its
* data from the interface. We do this by defining a method in the interface
* with the same name as the zone. If this exists, we will run the method and 
* return here. The parent Interface class contains stub methods for the core
* interface zone names. These are overriden in the child local class to allow
* special data or data processing to occur before the block content and data
* elements are added.
*/
      if (($data[interface] == $gui->interface) && method_exists($gui, $zones[$data[zone]][name])) {
      	$this->blockID = $data[id];
      	$gui->{$zones[$data[zone]][name]}($this);
      } 
      $result->MoveNext();
    }

// Then pull the user interface blocks.
    if (isset($userinfo[id]) && $userinfo[id] > 0) {
      list($u_dbt, $u_dbc) = array_values($this->dbtable[user_block]);
      $gid_list = join(",", $userinfo[groups]);
      $uid_q = $dbh->qstr($userinfo[id]);
      
      $sql = <<<END_SQL
select $dbc[id], $dbc[title], $dbc[content], $dbc[code], $dbc[zone], $dbc[ord]
from $dbt, $u_dbt
where ($u_dbc[bid] = $dbc[id] or $dbc[grp] in ($gid_list)) 
    and ($u_dbc[uid] = $uid_q) 
    and $dbc[zone] in ($zone_list)
    and ($dbc[user_block] = 1)  
order by $dbc[ord]
END_SQL;
      $result = $dbh->Execute($sql) or trigger_error('Could not load user defined blocks.');
/**
* At this time, we do not special parsing on user blocks to add dynamic code
* functionality as done on the core/interface blocks above.
*/
      while( $data = $result->fields){
      	if (empty($done_blocks[$data[id]])) {
      	  $this->blocks[$data[id]] = $data;
      	  $this->b_order[$zones[$data[zone]][name]][] =& $this->blocks[$data[id]];
      	  $done_blocks[$data[id]] = true;
      	  $result->MoveNext();
      	}
      	$result->MoveNext();
      } 
    } 
  }

/**
* Get Elements 
*
* We load the elements before any other portions of the template are loaded.
* This step is important, as it allows us to ensure that no other elements are
* required (recursively) and that the elements can be added to a dynamic block
* which is parsed on the fly rather than at display time.
*
* @return VOID
*/
  function getElements() {
    global $dbh;
    global $gui;
        
    $interfaces = array("''", "'default'");
    $itypes = explode(".", $gui->interface);
    for($i = 0; $i < sizeof($itypes); $i++) {
      $current .= ($i == 0) ? $itypes[$i] : "." . $itypes[$i];
      $interfaces[] = $gui->command->db_quote($current);
    }
    $interface_list = implode (', ', $interfaces);
    list($dbt, $dbc) = array_values($this->dbtable[element]);
    $plugin_q = $dbh->qstr($gui->plugin);
    $sql = <<<END_SQL
select $dbc[id], $dbc[name], $dbc[content], $dbc[code], $dbc[plugin]
from $dbt
where $dbc[plugin] in ('default', $plugin_q) 
and $dbc[interface] in ($interface_list)
END_SQL;
    $result = $dbh->Execute($sql) or trigger_error("Cannot load elements for plugin.", FATAL);
    while ($data = $result->fields) {
      $this->elements[$data[name]] = $data;
      $this->elements[$data[id]] =& $this->elements[$data[name]];
      $result->MoveNext();
    }
  }

/**
* Parse Template Content
*
* The template parsing procedure starts with the element parsing and then moves
* outward through the blocks, zones and finally core template to render the fully
* parsed HTML. Each content type has its own template specific tag which is used
* to indicate the location and content to be placed in the theme.
* Once the basic elements of the template are parsed individually, the parse engine 
* makes secondary passes over the entire contents to ensure that any items which 
* may be nested are caught in the parsing. The engine also makes checks for circular
* nested items to ensure that infinate parsing loops do not occur. 
* Two special parsing tags for forms and tables of data are also parsed in the method.
* This allows the dynamic creation of form data to be more easily handled instead of
* creating custom form elements for each operation used in the interfaces.
*
* @returns VOID
* @see parseElements, parseBlocks, parseZones, buildForm, buildTable
*/
  function parse() {
    if(isset($this->elements)) {
      reset($this->elements);
      while(list($n,$element) = each($this->elements)){
        $this->elements[$n][register][$n] = 1;
	      $this->elements[$n][parsed_text] = $this->parseElements($element); // Testing removal of reparse!
        unset($this->elements[$n][register]);
      }
    }
    if (isset($this->blocks)) {
      reset($this->blocks);
      while(list($n,$block) = each($this->blocks)) {
      	if (empty($this->blocks[$n][parsed_text])) {
	        $this->blocks[$n][parsed_text] = $this->parseBlocks($block);
	      }
      }
    }
    if (isset($this->zones)) {
      reset($this->zones);
      while(list($n,$zone) = each($this->zones)) {
	      $this->zones[$n][parsed_text] = $this->parseZones($zone);
      }
    }
    $copy = $this->content;
    preg_match_all("/\<zone name=['\"]?([A-Za-z0-9\._]+?)['\"]?\s*\/?>/",$this->content,$zon_array);
    $zon_array = $zon_array[1];
    
    while (list($k,$v)=each($zon_array)) {
      $var = $this->zones[$v][parsed_text];
      $var=(!isset($var))?$null:$var;
      $copy = preg_replace("/\<zone name=['\"]?" . $v . "['\"]?\s*\/?>/",$var,$copy);
    }

    preg_match_all("/\<element name=['\"]?([A-Za-z0-9\._]+?)['\"]?>/",$copy,$ele_array);
    $ele_array = $ele_array[1];
    preg_match_all("/\<form name=['\"]?([A-Za-z0-9\._]+?)['\"]?>/",$copy,$form_array);
    $form_array = $form_array[1];
    preg_match_all("/\<table name=['\"]?([A-Za-z0-9\._]+?)['\"]?>/",$copy,$table_array);    $table_array = $table_array[1];
    preg_match_all("/&([A-Za-z0-9\._]+?);/",$copy,$var_array);
    $var_array = $var_array[1];
    
    while (list($k,$v)=each($ele_array)) {
      $var = $this->elements[$v][parsed_text];
      $var=(!isset($var))?$null:$var;
      $copy = preg_replace("/\<element name=['\"]?" . $v . "['\"]?\>/",$var,$copy);
    }
    while (list($k,$v)=each($form_array)) {
      $var = $this->buildForm($v);
      $copy = preg_replace("/\<form name=['\"]?" . $v . "['\"]?\>/",$var,$copy);
    }
    while (list($k,$v)=each($table_array)) {
      $var = $this->buildTable($v);
      $copy = preg_replace("/\<table name=['\"]?" . $v . "['\"]?\>/",$var,$copy);
    }

    while (list($k,$v)=each($var_array)) {
      $no_value = true;
      $sub = explode(".", $v);
      $retval = $this->data[$sub[0]];
      for ($i = 1; $i < sizeof($sub); $i++) {
        if (isset($retval)) { $no_value = false; }
        $retval = isset($retval[$sub[$i]]) ? $retval[$sub[$i]]: '';
      }
      $var = (empty($retval) && $no_value) ? "&$v;" : $retval;
      $copy = preg_replace("/&" . $v . ";/",$var,$copy);
    }
    $this->parsed_text = $copy;
  }

/**
* Parse Elements
*
* Element parsing is done one element at a time. This ensures that if other element
* dependencies are found during parsing, they are recursively parsed as needed. Recursion
* is flagged on each element, so that if a successive parse call on the element is 
* made, an error is raised and the recursion is stopped. This prevents a element from
* calling on itself or a circular parsing relationship from occuring. During
* the parsing, if a element is flagged as code, it is evaluated and the return output 
* is then parsed for data items. 
*
* @param ArrayRef $element A reference array of the element item to be parsed. Elements are parsed individually from the parse engine.
* @param boolean $reparse If set false, the method will not parse the element if its parsed text has already been set. 
* @return String Contains the parsed text of the element.
*/
  function parseElements (&$element, $reparse = true) {
    global $error; 
    
    if ($element[parsed_text] != '' && !$reparse) {
      return $element[parsed_text];
    } elseif ($element[parsed_text] == "%%%ERROR%%%") {
      return "";
    }
    
    ob_start();
    if ($element[code] == 1) {
      $copy = eval($element[content]);
      $ele_error = ob_get_contents();
    } else {
      $copy = $element[content];
    }
    ob_end_clean();
    if ($ele_error) {
      $ele_error = strip_tags($ele_error);
      trigger_error("Error ($ele_error) in element $element[plugin]::$element[name]", WARNING);
      return "%%%ERROR%%%";
    }
    
    if (preg_match_all("/\<element name=['\"]?([A-Za-z0-9\._]+?)['\"]?>/", $element[content], $ele_array)) {
      $ele_array = $ele_array[1];
      while (list($k, $v) = each ($ele_array)) {
        if ($element[register][$v] > 1) {
  	      $copy = preg_replace("/\<element name=['\"]?" . $v . "['\"]?\>/","ILLEGAL ELEMENT RECURSION - $v",$copy);
  	      continue;
        }
        $element[register][$v]++;
	      $etext = $this->parseElements($this->elements[$v]);
	      $copy = preg_replace("/\<element name=['\"]?" . $v . "['\"]?\>/",$etext,$copy);
      }
    }

    preg_match_all("/&([A-Za-z0-9\._]+?);/",$element[content],$var_array);
    $var_array=$var_array[1];
    while (list($k,$v)=each($var_array)) {
      $no_value = true;
      $sub = explode(".", $v);
      $retval = $this->data[$sub[0]];
      for ($i = 1; $i < sizeof($sub); $i++) {
        if (isset($retval) && $retval != '') { $no_value = false; }
        $retval = (isset($retval[$sub[$i]]) && $retval[$sub[$i]] != '' ) ? $retval[$sub[$i]]: '';
      }
      $var = ((isset($retval) && $retval != '') && $no_value == false) ? $retval : "&$v;"  ;
      $copy = preg_replace("/&" . $v . ";/",$var,$copy);
    }
    return $copy;
  }
  
/**
* Parse Blocks
*
* Unlike elements, blocks are not parsed recursively. However, blocks may be 
* dynamically added to the template repetitively from within the interface zone
* specific methods. We do currently allow blocks to be evaluated as code if the
* block is flagged properly.
*
* @param ArrayRef $block Contains the block definition to parse.
* @return String The parsed block content of the block.
*/
  function &parseBlocks(&$block) {
    $block[code] ? $copy = eval($block[content]) : $copy = $block[content];
    preg_match_all("/\<element name=['\"]?([A-Za-z0-9\._]+?)['\"]?>/",$block[content],$ele_array);
    $ele_array = $ele_array[1];
    preg_match_all("/&([A-Za-z0-9\._]+?);/",$block[content],$var_array);
    $var_array = $var_array[1];
    while (list($k,$v)=each($ele_array)) {
      $var = $this->elements[$v][parsed_text];
      $var=(!isset($var))?$null:$var;
      $copy = preg_replace("/\<element name=['\"]?" . $v . "['\"]?\>/",$var,$copy);
    }
    
/*    while (list($k,$v)=each($var_array)) {
      $no_value = true;
      $sub = explode(".", $v);
      $retval = $this->data[$sub[0]];
      for ($i = 1; $i < sizeof($sub); $i++) {
        if (isset($retval) && $retval != '') { $no_value = false; }
      }
      $var = ((isset($retval) && $retval != '') && $no_value == false) ? $retval : "&$v;"  ;
      $copy = preg_replace("/&" . $v . ";/",$var,$copy);
    }*/
    while (list($k,$v)=each($var_array)) {
      $no_value = true;
      $sub = explode(".", $v);
      $retval = $this->data[$sub[0]];
      for ($i = 1; $i < sizeof($sub); $i++) {
        if (isset($retval)) { $no_value = false; }
        $retval = (isset($retval[$sub[$i]]) && $retval[$sub[$i]] != '' ) ? $retval[$sub[$i]]: '';
      }
      $var = (empty($retval) && $no_value) ? "&$v;" : $retval;
      $copy = preg_replace("/&" . $v . ";/",$var,$copy);
    }
    return $copy;
  }

    
/**
* Parse Zones
*
* Zones differ in how they are parsed from the blocks and elements. A zone
* contains two content definitions. The content area defines the overall layout
* of the zone within the page and is a container for one or more blocks which
* will be placed inside the zone. However, it also contains a common block 
* content definition which defines how each block will be formated within that
* zone. Some zones contain a very specific layout which strictly conforms the
* blocks to a specific look and feel, while other zones may provide only a basic
* container, forcing the block itself to better define its content. 
*
* @param ArrayRef $zone The zone definition containing the content and block definition.
* @return String The parsed zone content.
*/
  function &parseZones(&$zone) {
    //$copy = $zone[content];
    $blockdef = $zone[content];
    $blocks = $this->b_order[$zone[name]];
    // Blocks are not themselves named. Blocks are automatically added based on where they
    // belong in the zone itself. Individual block fields can be displayed, such as the 
    // "title", and most importantly the "content" field.

    preg_match_all("/\<block field=['\"]?([A-Za-z0-9\._]+?)['\"]?>/",$blockdef,$var_array);
    $var_array=$var_array[1];
    $blocktext = '';
    if (isset($blocks)) {
      while(list($n,$block) = each($blocks)) {
        $blockcopy = $blockdef;
        reset($var_array);
        while (list($k,$v)=each($var_array)) {
			    if ($v == "content") { $v1 = "parsed_text"; } else { $v1 = $v;}
				  $var = $block[$v1];
				  $var=(!isset($var))?$null:$var;
				  $blockcopy = preg_replace("/\<block field=['\"]?" . $v . "['\"]?\>/",$var,$blockcopy);
				}
				$blocktext .= $blockcopy;
      }
    }
    return $blocktext;
  }
    
/**
* Add Parsed Block
*
* This method can be used by an interface method on its own theme object to 
* add an additional entry for the same block within a zone. This is useful for
* adding a list of similar blocks, using different content for each block (see
* the article list on the main index page for an example). 
* It should be noted that the block is actually parsed as it is added. As such,
* the block must be appended to the list of current blocks and then all elements
* for the block must be parsed and added.
*
* @return VOID
* @see parseElements, parseBlocks
*/
    function addParsedBlock() {
        $blockID = $this->blockID;
        $zoneID = $this->zoneID;
        // First, add a new block to the zone.
        $zname = $this->zones[$zoneID][name];
        if ($this->blockAppend == true && $this->blocks[$blockID][multi] == 1) {
          // Allocate a new block if we are called again
          $newBlockID = 99999 - sizeof($this->blocks);
          $this->blocks[$newBlockID] = $this->blocks[$blockID];
          $this->blocks[$newBlockID][id] = $newBlockID;
          $this->b_order[$zname][] =& $this->blocks[$newBlockID];
          $this->blockID = $newBlockID;
          $blockID = $this->blockID;
        } elseif ($this->blocks[$blockID][multi] == '1') {
          $this->blockAppend = true;
        } else {
          $this->blockAppend = false;
          return 0;
        }
         // Next, parse the block itself.
        if(isset($this->elements)) {
      	  while(list($n,$element) = each($this->elements)){
        		$this->elements[$n][parsed_text] = $this->parseElements($element, true);
          }
          reset($this->elements);
        }
        $this->blocks[$blockID][parsed_text] = $this->parseBlocks($this->blocks[$blockID]);
        $this->blockAppend == true;
    }

/**
* Build Dynamic Table
*
* When a <[table]> tag is inserted in an element or block, this method is called
* to parse the table into the content. Tables are built from the dynamic form system
* using all dynamic form elements which are defined for the plugin, interface, and
* operation defined in the current interface instance. The table will pull all its
* dynamic data from the interface internal data array. Field types of hidden and 
* password are not displayed. Select fields lookup their proper ID's to ensure that
* the proper item names are displayed instead of cryptic ID's.
* IN future releases, the HTML elements which create the table should be placed in
* a secondary template in the database rather than be in the template class itself.
*
* @param String $formName 
* @return String The parsed content which will composed the table.
*/
	function &buildTable($formName) {
		global $dbh;
		global $gui;
		global $config;
		
    $operations = explode('.', $gui->operation);
    $interface = $gui->command->db_quote($gui->interface);
    $plugin = $gui->command->db_quote($gui->plugin);
    $operation = $gui->command->db_quote($operations[0]);
    $formName = $gui->command->db_quote($formName);
      $sql = <<<END_SQL
select name, value, title, description, formsize_a, formsize_b, source, source_name, type, script, size_min, is_required from dyna_form_element
  where plugin  in ('',  $plugin )
  and form_name in ('', $formName)
  and interface in ('', $interface) 
  and operation in ('', $operation)
  order by ord
END_SQL;
    $ele_result = $dbh->Execute($sql);
    !$ele_result ? die("SQL: $sql -- " . $dbh->ErrorMsg()) : '';
    if (empty($ele_result->fields[name])) {
			$out = '<p class="error">No form information provided for this operation, contact an administrator.</p>';
			return $out;
    }
      
		$out = <<<END_HTML
		<TABLE WIDTH=100% CELLPADDING=2 CELLSPACING=0>
END_HTML;

    while ($ele = $ele_result->fields){
		  $ele[value] = $gui->interface_data[$ele[name]];
			if ($ele[type] == 'hidden' || $ele[type] == 'password') {
				$ele_result->MoveNext();
				continue;
			}
	    if ($ele[type] == 'select') {
	      if ($ele[source] == 'table') {
			// Tables used for selects must have a permission column. This column adds
			// a permission system so that some options cannot be chosen. As an example,
			// the admin theme cannot be used by any users except the admin interfaces.
	        $sql = "select id, name from $ele[source_name] where permission <= {$gui->permission} order by id";
	      } else {
    	    $field = $gui->command->db_quote($ele[source_name]);
    	    $sql = "select name, value from dyna_form_select where form_field = $field";
    	  }
    	  $select_result = $dbh->Execute($sql);
    	  !$select_result ? die("SQL: $sql -- " . $dbh->ErrorMsg()) : '';
    	  
    	  while ($option = $select_result->fields) {
          if ($ele[source] == 'table') {$option[value] = $option[id];}
    	    if ($ele[source] == 'table' && $option[id] == $ele[value]) {
    	      $ele[value] = $option[name];
    	    } elseif ($option[value] == $ele[value]) {
    	      $ele[value] = $option[value];
    	    }
    	    $select_result->MoveNext();
    	  }
      }			
		  $out .= <<<END_HTML
		<TR><TD WIDTH=50% ALIGN=RIGHT VALIGN=TOP>
	      <B>$ele[title]</B><img src="$config[site_url]/images/help.gif" border=0 height=16 width=16 alt='$ele[description]' hspace="4">
	    </TD><TD WIDTH=50% VALIGN=TOP>$ele[value]
	    </TD></TR>
END_HTML;
			$ele_result->MoveNext();
	  }
		$out .= '</TABLE>';
		return $out;		
	}
/**
* Build Dynamic Form
*	
* Dynamic form generation is handled by reading parameters from the dynamic form 
* and form element tables to compose data into the form as needed. The data is 
* pre-entered into the form when the proper data is loaded into the interface data
* array. This class handles the generation and population of all basic HTML form elements.
* IN future releases, the HTML elements which create the table should be placed in
* a secondary template in the database rather than be in the template class itself.
*
* @param String $formName 
* @return String The parsed content which will composed the table.
*/
  function &buildForm($formName, $template = '', $submit = true) {
    global $dbh, $gui, $config;
    $out = '';
    
    $operations = explode('.', $gui->operation);
    $interface = $gui->command->db_quote($gui->interface);
    $plugin = $gui->command->db_quote($gui->plugin);
    $operation = $gui->command->db_quote($operations[0]);
    $formName = $gui->command->db_quote($formName);
    $sql = <<<END_SQL

select f.name, f.action, f.method, t.template, t.has_elements from dyna_form f, dyna_form_template t
  where f.plugin  = $plugin
  and f.interface in ('', $interface) 
  and f.name = $formName
  and f.template = t.id
END_SQL;
    $form_result = $dbh->Execute($sql);
    !$form_result ? die("SQL: $sql -- " . $dbh->ErrorMsg()) : '';

    if (isset($template) && $template != '') {
      $sql = "select template from dyna_form_template where name = $template";
      $temp_result = $dbh->Execute($sql);
      if (isset($temp_result->fields[template]) && $temp_result->fields[template] != '') {
        $form_result->fields[template] = $temp_result->fields[template];
      }
    }

    if (empty($form_result->fields[name])) {
	    $out = '<p class="error">The form for this operation does not exist, contact an administrator.</p>';
	    return $out;
    }
  if ($form_result->fields[has_elements] == 1) {
    $sql = <<<END_SQL
select name, value, title, description, formsize_a, formsize_b, source, source_name, type, script, size_min, is_required from dyna_form_element
  where plugin  in ('', $plugin )
  and form_name in ('', $formName)
  and interface in ('', $interface) 
  and operation in ('', $operation)
  order by ord
END_SQL;
    $ele_result = $dbh->Execute($sql);
    !$ele_result ? die("SQL: $sql -- " . $dbh->ErrorMsg()) : '';
    if (empty($ele_result->fields[name])) {
  	  $out = '<p class="error">No form information provided for this operation, contact an administrator.</p>';
	    return $out;
    }
$count =0;
    while ($ele = $ele_result->fields) {
      $count++;
      $ele_result->MoveNext();
    	if ($ele[formsize_a] == 0) { $ele[formsize_a] = ''; }
	    if ($ele[formsize_b] == 0) { $ele[formsize_b] = ''; }
	    if ($ele[size_min] > 0 || $ele[is_required] == '1') {
        $ele[required] = true;
      }
	    if ($ele[source] == 'user' || $ele[type] == 'select') {
		    if (isset($gui->interface_data[$ele[name]]) && $gui->interface_data[$ele[name]] != '') {
	  	    $ele[value] = $gui->interface_data[$ele[name]];
		    } elseif (isset($gui->form_data[$ele[name]]) && $gui->form_data[$ele[name]] != '') {
	  	    $ele[value] = $gui->form_data[$ele[name]];
		    }
	    } elseif ($ele[source] == 'cgi') {
    	  isset($HTTP_GET_VARS[$ele[name]]) ? $ele[value] = $HTTP_GET_VARS[$ele[name]] : '';
    	  isset($HTTP_POST_VARS[$ele[name]]) ? $ele[value] = $HTTP_POST_VARS[$ele[name]] : '';
    	  isset($gui->form_data[$ele[name]]) ? $ele[value] = $gui->form_data[$ele[name]] : '';
    	} elseif ($ele[source] == 'variable') {
    	  $vars = explode('.', $ele[source_name]);
    	  $retval = $gui->interface_data[$vars[0]];
    	  for ($i = 1; $i < sizeof($vars); $i++) {
      		$retval = isset($retval[$vars[$i]]) ? $retval[$vars[$i]] : '';
	      }
	      isset($retval) ? $ele[value] = $retval : '';
	    }
    	if ($ele[type] == 'text' || $ele[type] == 'number' || $ele[type] == 'alphanum') {
        $ele[field] = "<INPUT TYPE=\"text\" NAME=\"form_$ele[name]\" VALUE=\"$ele[value]\" SIZE=\"$ele[formsize_a]\" MAXLENGTH=\"$ele[formsize_b]\">";
    	} elseif ($ele[type] == 'password') {
	      $ele[field] = "<INPUT TYPE=\"password\" NAME=\"form_$ele[name]\" VALUE=\"$ele[value]\" SIZE=\"$ele[formsize_a]\" MAXLENGTH=\"$ele[formsize_b]\">";
    	} elseif ($ele[type] == 'textarea') {
	      $ele[field] = "<TEXTAREA NAME=\"form_$ele[name]\" ROWS=\"$ele[formsize_a]\" COLS=\"$ele[formsize_b]\" wrap=\"virtual\">$ele[value]</TEXTAREA>";
    	} elseif ($ele[type] == 'select') {
    	  if ($ele[source] == 'table') {
    			// Tables used for selects must have a permission column. This column adds
    			// a permission system so that some options cannot be chosen. As an example,
    			// the admin theme cannot be used by any users except the admin interfaces.
    	    $sql = "select id, name from $ele[source_name] where permission <= {$gui->permission} order by id";
    	  } elseif($ele[source] == 'sql') {
    	    $sql = $ele[source_name];
    	  } else {
    	    $field = $gui->command->db_quote($ele[source_name]);
    	    $sql = "select name, value from dyna_form_select where form_field = $field";
    	  }
    	  $select_result = $dbh->Execute($sql);
    	  !$select_result ? die("SQL: $sql -- " . $dbh->ErrorMsg()) : '';
    	  if ($ele[formsize_b] > 0 ) { $MULTIPLE = 'MULTIPLE'; }
    	  $ele[field] .= <<<END_HTML
<SELECT NAME="form_$ele[name]" SIZE="$ele[formsize_a]" $MULTIPLE $ele[script]>
END_HTML;
    
        if (isset($select_result->fields[name])) {
      	  while ($option = $select_result->fields) {
      	    $SELECTED = '';
            if ($ele[source] == 'table' || $ele[source] == 'sql') {
              $option[value] = $option[id];
            } elseif ($ele[source] == 'table_noid') {
              $option[value] = $option[name];
            }
            if ($option[value] == $ele[value]) {
      	      $SELECTED = 'SELECTED';
      	    }
      						
      	    $ele[field] .= <<<END_HTML
<OPTION VALUE="$option[value]" $SELECTED>$option[name]</OPTION>
END_HTML;
      	    $select_result->MoveNext();
      	  }
        } else {
          $ele[field] .= <<<END_HTML
<OPTION VALUE="" $SELECTED>$ele[value]</OPTION>
END_HTML;
        }
    	  $ele[field] .= <<<END_HTML
</SELECT>
END_HTML;
    	} elseif ($ele[type] == 'checkbox') {
    		$checked = '';
    		if (isset($ele[value]) && $ele[value] !== '' && $ele[value] != 0) {
    			$checked = 'CHECKED';
    		}
    		$ele[field] = <<<END_HTML
<input type="checkbox" name="form_$ele[name]" value="1" $checked>
END_HTML;
    	} elseif ($ele[type] == 'radio') {
    	  $ele[field] = <<<END_HTML
END_HTML;
    	} elseif ($ele[type] == 'hidden') {
    	  $ele[field] = <<<END_HTML
<INPUT TYPE="hidden" NAME="form_$ele[name]" VALUE="$ele[value]">
END_HTML;
    	} elseif ($ele[type] == 'date') {
    		$date_elements = $gui->command->dateArray($ele[value]);
    		$months = $gui->command->monthArray();
    		$ele[field] = "<SELECT NAME=\"form_$ele[name]_month\">\n";
    		$ele[field] .= "<OPTION VALUE=\"\"> </OPTION>\n";
    		for ($i = 0; $i < 13; $i++) {
    			$SELECTED = '';
    			print ":: $date_elements[month]";
    			if ($date_elements[month] == $i) 
    				$SELECTED = 'SELECTED';
    			$ele[field] .= "<OPTION VALUE=\"$i\" $SELECTED>$months[$i]</OPTION>\n";
    		}
    		$ele[field] .= "</SELECT>\n";
    		
    		$ele[field] .= "<SELECT NAME=\"form_$ele[name]_day\">";
    		$ele[field] .= "<OPTION VALUE=\"\"> </OPTION>\n";
    		for ($i = 1; $i <= 31; $i++) {
    			$SELECTED = '';
    			if ($date_elements[day] == $i) 
    				$SELECTED = 'SELECTED';
    			$ele[field] .= "<OPTION VALUE=\"$i\" $SELECTED>$i</OPTION>\n";
    		}
    		$ele[field] .= "</SELECT>\n";
    
    		$ele[field] .= "<SELECT NAME=\"form_$ele[name]_year\">";
    		$ele[field] .= "<OPTION VALUE=\"\"> </OPTION>\n";
    		for ($i = 1900; $i <= 2010; $i++) {
    			$SELECTED = '';
    			if ($date_elements[year] == $i) 
    				$SELECTED = 'SELECTED';
    			$ele[field] .= "<OPTION VALUE=\"$i\" $SELECTED>$i</OPTION>\n";
    		}
    		$ele[field] .= "</SELECT> $REQUIRED\n";
      } elseif ($ele[type] == 'file' ) {
    		if (isset($gui->interface_data[$ele[name]]) && $gui->interface_data[$ele[name]] != '') {
    	  	$ele[value] = $gui->interface_data[$ele[name]];
    		} 
    		$ele[field] .= <<<END_HTML
    		   $ele[value]<br>
    		   <input type="file" name="form_$ele[name]" size="$ele[formsize_a]"><br>
    		   <input type="checkbox" name="form_$ele[name]_remove" value="1"> Remove Current
END_HTML;
    	} elseif ($ele[type] == 'verify') {
    	} else { // Element is probably just info
        $ele[value] = $gui->interface_data[$ele[name]];
    	  $ele[field] = $ele[value];
    	}
      $this->form_element[$ele[name]] = $ele;
    }
  }
    if ($submit == false) { $on_submit = "onSubmit=\"window.alert('This is a sample form and cannot be submitted');return false;\"";}
    $form_out .= <<<END_HTML
	<FORM NAME="{$form_result->fields[name]}" ACTION="{$form_result->fields[action]}" METHOD="{$form_result->fields[method]}" enctype="multipart/form-data" $on_submit>
	<INPUT TYPE="HIDDEN" NAME="form__operation" VALUE="$operations[0]">
	<INPUT TYPE="HIDDEN" NAME="form__name" VALUE="{$form_result->fields[name]}">
	<INPUT TYPE="HIDDEN" NAME="searchby" VALUE="{$gui->search[key]}">
	<INPUT TYPE="HIDDEN" NAME="searchid" VALUE="{$gui->search[id]}">
	<INPUT TYPE="HIDDEN" NAME="searchname" VALUE="{$gui->search[name]}">
	<INPUT TYPE="HIDDEN" NAME="form_id" VALUE="{$gui->interface_data[id]}">
	
END_HTML;
    $form_out .= eval($form_result->fields[template]);
    //print eval($form_result->fields[template]);
    $form_out .= '</form>';

    return $form_out;    
  }

/**
* Get Parsed Text
* 
* Pulls the parsed text of the template and returns it as a string.
*
* @return String The parsed content of the entire template.
*/
    function &getparse() {
        return $this->parsed_text;
    }

/**
* Assign Template Data
* 
* Assigns data to the template using either single items or arrays. The
* method does not properly handle an array of multi-dimensional data. 
*
* @param String $name The name of <[data]> element to assign the data to.
* @param Multi $value Either a single or arrayed set of data to assign to the template.
* @return VOID
*/
    function assign ($name, $value) {
        $this->data[$name] = $value;
    }

/**
* Builds a Meta Content Element
*
*/
  function getMetaElement() {
    while (list ($k, $v) = each ($this->tmeta) ) {
      $out .= "<meta http-equiv=\"$k\" content=\"$v\">\n";
    }
    $this->elements[themeMeta] = array(id => -1,
                                      name => 'themeMeta',
                                      content => $out,
                                      code => 0);
  }
  
}

?>
Return current item: Dark Hart Portal