<?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);
}
}
?>