Commit 784e7be7 authored by davidmetzler's avatar davidmetzler
Browse files

Refactor in preparation for custom controls.

parent c1d28ef8
<?php
class FrxData {
/**
* The FrxData class holds all of the data contexts during the report rendering process.
* The general idea is that during the report render, data objects are pushed on the stack with the id's of the block or foreach objects that invoke them.
* Rendering controls may then get current data contexts, and push data onto the stack or pop data onto the stack. They may also use this method to get the current data
* context from the stack.
*
* The static instance function of this object acts as a factory method that allows other code in forena to always be able to operate on the current context of the class.
* @var unknown_type
*/
private static $instance;
private $cur_context; // The data of the xml;
private $data_sources = array();
private $data_stack = array();
private $id_stack = array();
/**
* Static factory method for working on data objects
* Enter description here ...
*/
static function instance() {
if (!self::$instance) {
self::$instance = new FrxData();
}
return self::$instance;
}
public function __construct($data = array(), $id='parm') {
if ($data) {
$this->push($data, $id);
}
}
/**
* Return the current data context
*
*/
public function currentContext() {
return $this->cur_context;
}
/**
* Push a data context onto the data stacks
* to make sure that we can address these using an
* appropriate syntax. I think we don't need data_stack
* but i'm holding it there in case we develop a "relative" path syntax.
* @param $data
* @param $id
* @return unknown_type
*/
public function push($data, $id='') {
$this->data_stack[] = $data;
$this->id_stack[] = $id;
$this->cur_context = $data;
if ($id) {
$this->data_sources[$id] = $data;
}
}
/**
* Remove data from the data stack. This will make data unavaiable
* when we leave the context of the current nested reports.
* @param $id
* @return mixed
*/
public function pop() {
$id = array_pop($this->id_stack);
array_pop($this->data_stack);
if ($id) {
unset($this->data_sources[$id]);
}
}
/**
* Determines whether an array context exists for the specified id.
* Returns true if the key exists othewise false
* @param string $id
* @return boolean
*/
public function contextExists($id) {
if (array_key_exists($id, $this->data_sources)){
return TRUE;
}
else return FALSE;
}
/**
* Return a data context by id
* Enter description here ...
* @param unknown_type $id
*/
public function getContext($id) {
return @$this->data_sources[$id];
}
}
\ No newline at end of file
......@@ -38,7 +38,7 @@ class FrxHostApplication {
* return html A properly formatted anchor tag
*/
public function link($title, $path, $options=array()) {
return $title;
return '<a href="'. $path . '">' . $title . '</a>';
}
/**
......
......@@ -19,18 +19,20 @@ class FrxReport {
public $body;
public $html;
private $ids;
private $cur_data;
private $teng;
private $frx_data; // Data object
private $root_data;
private $dom;
public function __construct($xhtml, $data=array()) {
$this->teng = new FrxSyntaxEngine(FRX_TOKEN_EXP, '{}', $this);
$this->access = array();
$this->parameters = array();
$this->options = array();
$this->root_data = $data;
$this->frx_data = FrxData::instance();
$this->frx_data;
$this->teng = new FrxSyntaxEngine(FRX_TOKEN_EXP, '{}', $this, $this->frx_data);
if ($xhtml) {
$dom = $this->dom = new DOMDocument('1.0', 'UTF-8');
// Old assumption is an ojbect is a simplexml one
......@@ -42,8 +44,7 @@ class FrxReport {
$rpt_xml = $this->rpt_xml = simplexml_import_dom($dom);
// Loaod data if its there.
$this->cur_data = $data;
$this->teng->push_data($data, 'parm');
$this->frx_data->push($data, 'parm');
// Load header data
$this->body = $rpt_xml->body;
if ($rpt_xml->head) {
......@@ -93,19 +94,21 @@ class FrxReport {
*/
private function get_data($block, $clause='', $id='') {
//@TODO: Merge xml data parameters into the report paramters
$this->cur_data = FrxReportGenerator::instance()->invoke_data_provider($block, $this->cur_data, $clause);
$xml = FrxReportGenerator::instance()->invoke_data_provider($block, $this->frx_data->currentContext(), $clause);
$this->teng->push_data($this->cur_data, $id);
if ($this->cur_data) $this->blocks_loaded = TRUE;
}
if ($xml) {
$this->blocks_loaded = TRUE;
$this->frx_data->push($xml, $id);
}
return $xml;
}
/**
* Recursive report renderer
* Walks the nodes rendering the report.
*/
public function render_section(DOMNode $dom_node) {
$cur_data = $this->cur_data;
$continue = TRUE;
$is_data_block = FALSE;
$node_type = $dom_node->nodeType;
......@@ -116,7 +119,7 @@ class FrxReport {
|| $node_type == XML_ENTITY_REF_NODE
|| $node_type == XML_ENTITY_NODE
) { $text = $dom_node->textContent;
$o .= $this->teng->replace($text, $this->cur_data);
$o .= $this->teng->replace($text);
return $o;
}
......@@ -144,8 +147,8 @@ class FrxReport {
if ((string)$frx['block']) {
$is_data_block = TRUE;
$this->get_data((string)$frx['block'], (string)$frx['clause'], $id);
if (!$this->cur_data) $continue = FALSE;
$xml = $this->get_data((string)$frx['block'], (string)$frx['clause'], $id);
if (!$xml) $continue = FALSE;
}
// Preserve non frx attributes
......@@ -156,20 +159,22 @@ class FrxReport {
$tmp_attr[$key] = (string)$value;
}
// Determine if we have a custom renderer
$renderer = (string)$frx['renderer'];
// if we have a foreach in this node, we need to iterate the children
if ((string)$frx['foreach'] ) {
// Save xml
$path = (string)$frx['foreach'];
$data = $this->cur_data;
$data = $this->frx_data->currentContext();
if (is_object($data)) $nodes = $data->xpath($path);
$i=0;
//$tmp_attrs = (array)$attrs;
if ($nodes) foreach ($nodes as $x) {
$this->cur_data = $x;
$this->teng->push_data($x, $id);
$this->frx_data->push($x, $id);
$i++;
$odd = $i & 1;
$row_class = $odd ? 'odd' : 'even';
......@@ -179,18 +184,16 @@ class FrxReport {
foreach ($tmp_attrs as $key => $value) {
$r_attr_text .= ' ' . $key . '="' . (string)$value . '"';
}
$o .= $this->teng->replace('<' . $tag . $r_attr_text . '>', $this->cur_data);
$o .= $this->teng->replace('<' . $tag . $r_attr_text . '>');
foreach ($dom_node->childNodes as $child) {
$o .= $this->render_section($child);
}
$o .= '</' . $tag . '>';
$this->frx_data->pop();
}
$this->cur_data = $data;
$this->teng->pop_data($id);
}
elseif ($continue) {
$renderer = (string)$frx['renderer'];
if (!$renderer) $o .= $this->teng->replace('<' . $tag . $attr_text . '>');
// @TODO: Determine if there is a custom renderer
......@@ -201,17 +204,18 @@ class FrxReport {
}
if (!$renderer) $o .= '</' . $tag . '>';
}
if ($is_data_block) {
$this->frx_data->pop();
}
}
else {
$tag = $node->getName();
// We can render so lets do it.
$text = $node->asXML();
$o .= $this->teng->replace($text, $this->cur_data);
$o .= $this->teng->replace($text);
}
$this->cur_data = $cur_data;
//if ($is_data_block) $this->teng->pop_data($id);
return $o;
}
......@@ -269,7 +273,7 @@ class FrxReport {
}
if ($link) {
$target = $this->teng->replace($target, $data, TRUE);
$target = $this->teng->replace($target, TRUE);
// use the target attribute to open links in new tabs or as popups.
if (@strpos(strtolower($target),'popup')===0) {
$opts = 'status=1';
......@@ -282,7 +286,7 @@ class FrxReport {
else {
$attributes = array('target' => $target);
}
$link = $this->teng->replace($link, $data, TRUE);
$link = $this->teng->replace($link, TRUE);
@list($url, $query) = explode('?', $link);
$data = array();
parse_str($query, $data);
......
......@@ -193,7 +193,7 @@ class FrxReportGenerator {
$repos = $this->app->repositories();
if ($_forena_repositories) {
array_merge($repos, $forena_repositories);
array_merge($repos, $_forena_repositories);
}
......
......@@ -13,53 +13,28 @@ class FrxSyntaxEngine {
private $tpattern;
private $trim_chars;
private $formatter; // Object used to format the data
private $data_stack;
private $data_sources;
private $frxData ;
/**
* Class for doing syntax replacements;
* @param $regexp
* @return unknown_type
*/
public function __construct($regexp, $trim, $formatter=NULL) {
public function __construct($regexp, $trim, $formatter=NULL, $frxObject=NULL) {
$this->tpattern = $regexp;
$this->trim_chars = $trim;
if (is_object($formatter)) {
$this->formatter=$formatter;
}
$this->data_stack = array();
$this->data_sources = array();
}
/**
* Push a data context onto the data stacks
* to make sure that we can address these using an
* appropriate syntax. I think we don't need data_stack
* but i'm holding it there in case we develop a "relative" path syntax.
* @param $data
* @param $id
* @return unknown_type
*/
public function push_data($data, $id='') {
$this->data_stack[] = $data;
if ($id) {
$this->data_sources[$id] = $data;
if ($frxObject) {
$this->frxData = $frxObject;
}
}
/**
* Remove data from the data stack. This will make data unavaiable
* when we leave the context of the current nested reports.
* @param $id
* @return unknown_type
*/
public function pop_data($id='') {
array_pop($this->data_stack);
if ($id) {
unset($this->data_stack[$id]);
else {
$this->frxData = FrxData::instance();
}
}
/**
* Provides an api to the {=xpath} syntax that can be used
* to evaluat expressions such as sum and count in a report. We
......@@ -91,19 +66,14 @@ class FrxSyntaxEngine {
*/
protected function get_value( $key, $raw=FALSE) {
$retvar = '';
// Determne which $data var we're going to get
$data = array();
if ($this->data_stack) {
$i = count($this->data_stack) - 1;
$data = $this->data_stack[$i];
}
if ($key=='variables') drupal_set_message(print_r($data,1));
// Default to theo current context
$data = $this->frxData->currentContext();
// Determine if we have a . syntax for the id.
if ($key) {
@list($id, $path) = explode('.', $key, 2);
if ($data && isset($this->data_sources[$id])) {
$data = $this->data_sources[$id];
$key = $path;
if ($this->frxData->contextExists($id)) {
$data = $this->frxData->getContext($id);
}
}
......@@ -155,11 +125,10 @@ class FrxSyntaxEngine {
* @param $data
* @return unknown_type
*/
public function replace($text, $data='', $raw=FALSE) {
public function replace($text, $raw=FALSE) {
$match=array();
$o_text = $text;
// Put the data on the stack.
if ($data) $this->push_data($data);
if (preg_match_all($this->tpattern, $o_text, $match)) {
//list($params) = $match[1];
$i=0;
......@@ -174,7 +143,6 @@ class FrxSyntaxEngine {
}
}
}
if ($data) $this->pop_data();
return $text;
}
......
......@@ -10,6 +10,7 @@ require_once('FrxReport.inc');
require_once('FrxDataProvider.inc');
require_once('FrxReportGenerator.inc');
require_once('FrxDrupalApplication.inc');
require_once('frxData.inc');
/**
* Get name from argument 1 or alterntaively from a file name
......
......@@ -42,7 +42,7 @@ class FrxDrupal extends FrxDataProvider {
if ($clause) {
$sql = 'SELECT * FROM (' . trim($sql, ' ;') . ') forena_table ' . $clause;
}
$sql = $this->te->replace($sql, $params);
$sql = $this->te->replace($sql);
$rs = db_query($sql);
$xml = new SimpleXMLElement('<table/>');
......
......@@ -65,7 +65,7 @@ class FrxMSSQL extends FrxDataProvider {
if ($clause) {
$sql = 'SELECT * FROM (' . trim($sql, ' ;') . ') ' . $clause;
}
$sql = $this->te->replace($sql, $params);
$sql = $this->te->replace($sql);
if ($this->use_mssql_xml) {
$xml = $this->mssql_xml($sql, $block_name);
......
......@@ -79,7 +79,7 @@ class FrxOracle extends FrxDataProvider {
if ($clause) {
$sql = 'SELECT * FROM (' . trim($sql, ' ;') . ') ' . $clause;
}
$sql = $this->te->replace($sql, $params);
$sql = $this->te->replace($sql);
if ($this->use_oracle_xml) {
$xml = $this->oracle_xml($sql, $block_name);
......
......@@ -80,7 +80,7 @@ class FrxPDO extends FrxDataProvider {
if ($clause) {
$sql = 'SELECT * FROM (' . trim($sql, ' ;') . ') forena_table ' . $clause;
}
$sql = $this->te->replace($sql, $params);
$sql = $this->te->replace($sql);
$rs = $db->query($sql);
$xml = new SimpleXMLElement('<table/>');
......
......@@ -65,7 +65,7 @@ class FrxPostgres extends FrxDataProvider {
if ($clause) {
$sql = 'SELECT * FROM (' . trim($sql, ' ;') . ') vvv ' . $clause;
}
$sql = $this->te->replace($sql, $params);
$sql = $this->te->replace($sql);
if ($this->use_postgres_xml) {
$xml = $this->postgres_xml($sql, $block_name);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment