فهرست منبع

Templates: new type of block = sqlblock, allows for displaying tables/charts based in SQL queries (much quicker for Group By operations)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1289 a333f486-631f-4898-b8df-5754b55c2be0
romainq 14 سال پیش
والد
کامیت
28c64a2ee1
4فایلهای تغییر یافته به همراه345 افزوده شده و 1 حذف شده
  1. 1 0
      application/application.inc.php
  2. 336 0
      application/sqlblock.class.inc.php
  3. 7 1
      application/template.class.inc.php
  4. 1 0
      pages/ajax.render.php

+ 1 - 0
application/application.inc.php

@@ -26,6 +26,7 @@
 require_once(APPROOT.'/application/applicationcontext.class.inc.php');
 require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
 require_once(APPROOT.'/application/displayblock.class.inc.php');
+require_once(APPROOT.'/application/sqlblock.class.inc.php');
 require_once(APPROOT.'/application/audit.category.class.inc.php');
 require_once(APPROOT.'/application/audit.rule.class.inc.php');
 //require_once(APPROOT.'/application/menunode.class.inc.php');

+ 336 - 0
application/sqlblock.class.inc.php

@@ -0,0 +1,336 @@
+<?php
+// Copyright (C) 2010 Combodo SARL
+//
+//   This program is free software; you can redistribute it and/or modify
+//   it under the terms of the GNU General Public License as published by
+//   the Free Software Foundation; version 3 of the License.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//   GNU General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public License
+//   along with this program; if not, write to the Free Software
+//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+/**
+ * SqlBlock - display tables or charts, given an SQL query - use cautiously!
+ *  
+ *
+ * @author      Erwan Taloc <erwan.taloc@combodo.com>
+ * @author      Romain Quetiez <romain.quetiez@combodo.com>
+ * @author      Denis Flaven <denis.flaven@combodo.com>
+ * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
+ */
+
+
+require_once(APPROOT.'/application/webpage.class.inc.php');
+require_once(APPROOT.'/application/utils.inc.php');
+
+require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
+
+/**
+ * Helper class to design optimized dashboards, based on an SQL query
+ *  
+ */
+class SqlBlock
+{
+	protected $m_sQuery;
+	protected $m_aColumns;
+	protected $m_sTitle;
+	protected $m_sType;
+	                            
+	public function __construct($sQuery, $aColumns, $sTitle, $sType)
+	{
+		$this->m_sQuery = $sQuery;
+		$this->m_aColumns = $aColumns;
+		$this->m_sTitle = $sTitle;
+		$this->m_sType = $sType;
+	}
+	
+	/**
+	 * Constructs a SqlBlock object from an XML template
+	/*
+	 *
+	 *		<sqlblock>
+	 *			<sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) &lt; start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d')</sql>
+	 *			<type>table</type>
+	 *			<title>UserRequest:Overview-Title</title>
+	 *			<column>
+	 *				<name>Date</name>
+	 *				<label>UserRequest:Overview-Date</label>
+	 *				<drilldown></drilldown>
+	 *			</column>
+	 *			<column>
+	 *				<name>Count</name>
+	 *				<label>UserRequest:Overview-Count</label>
+	 *				<drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
+	 *			</column>
+	 *		</sqlblock>
+	 *
+	 * Tags
+	 * - sql: a (My)SQL query. Do not forget to use html entities (e.g. &lt; for <)
+	 * - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
+	 * - title: optional title, typed in clear or given as a dictionnary entry
+	 * - column: specification of a column (not displayed if omitted)
+	 * - column / name: name of the column in the SQL query (use aliases)
+	 * - column / label: label, typed in clear or given as a dictionnary entry
+	 * - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
+	 *
+	 * @param $sTemplate string The XML template
+	 * @return DisplayBlock The DisplayBlock object, or null if the template is invalid
+	 */
+	public static function FromTemplate($sTemplate)
+	{
+		$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>');
+		if (false)
+		{
+			// Debug
+			echo "<pre>\n";
+			print_r($oXml);
+			echo "</pre>\n";
+		}
+
+		if (isset($oXml->title))
+		{
+			$sTitle = (string)$oXml->title;
+		}
+		if (isset($oXml->type))
+		{
+			$sType = (string)$oXml->type;
+		}
+		else
+		{
+			$sType = 'table';
+		}
+		if (!isset($oXml->sql))
+		{
+			throw new Exception('Missing tag "sql" in sqlblock');
+		}
+		$sQuery = (string)$oXml->sql;
+
+		$aColumns = array();
+		if (isset($oXml->column))
+		{
+			foreach ($oXml->column AS $oColumnData)
+			{
+				if (!isset($oColumnData->name))
+				{
+					throw new Exception("Missing tag 'name' in sqlblock/column");
+				}
+				$sName = (string) $oColumnData->name;
+				if (strlen($sName) == 0)
+				{
+					throw new Exception("Empty tag 'name' in sqlblock/column");
+				}
+
+				$aColumns[$sName] = array();
+				if (isset($oColumnData->label))
+				{
+					$sLabel = (string)$oColumnData->label;
+					if (strlen($sLabel) > 0)
+					{
+						$aColumns[$sName]['label'] = Dict::S($sLabel);
+					}
+				}
+				if (isset($oColumnData->drilldown))
+				{
+					$sDrillDown = (string)$oColumnData->drilldown;
+					if (strlen($sDrillDown) > 0)
+					{
+						$aColumns[$sName]['drilldown'] = $sDrillDown;
+					}
+				}
+			}
+		}
+
+		return new SqlBlock($sQuery, $aColumns, $sTitle, $sType);		
+	}
+	
+	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	{
+		if (empty($aExtraParams['currentId']))
+		{
+			$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
+		}
+		else
+		{
+			$sId = $aExtraParams['currentId'];
+		}
+//		$oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
+
+		$res = CMDBSource::Query($this->m_sQuery);
+		$aQueryCols = CMDBSource::GetColumns($res);
+
+		// Prepare column definitions (check + give default values)
+		//
+		foreach($this->m_aColumns as $sName => $aColumnData)
+		{
+			if (!in_array($sName, $aQueryCols))
+			{
+				throw new Exception("Unknown column name '$sName' in sqlblock column");
+			}
+			if (!isset($aColumnData['label']))
+			{
+				$this->m_aColumns[$sName]['label'] = $sName;
+			}
+			if (isset($aColumnData['drilldown']))
+			{
+			}
+		}
+
+		if (strlen($this->m_sTitle) > 0)
+		{
+			$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
+		}
+
+		switch ($this->m_sType)
+		{
+		case 'bars':
+		case 'pie':
+			$aColNames = array_keys($this->m_aColumns);
+			$sXColName = $aColNames[0];
+			$sYColName = $aColNames[1]; 
+			$aData = array();
+			while($aRow = CMDBSource::FetchArray($res))
+			{
+				$aData[$aRow[$sXColName]] = $aRow[$sYColName];
+			}
+			$this->RenderChart($oPage, $sId, $aData);
+			break;
+
+		default:
+		case 'table':
+			$aDisplayConfig = array();
+			foreach($this->m_aColumns as $sName => $aColumnData)
+			{
+				$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
+			}
+	
+			$aDisplayData = array();
+			while($aRow = CMDBSource::FetchArray($res))
+			{
+				$aDisplayRow = array();
+				foreach($this->m_aColumns as $sName => $aColumnData)
+				{
+					$aDisplayRow[$sName] = $aRow[$sName];
+				}
+				$aDisplayData[] = $aRow;
+			}
+			$oPage->table($aDisplayConfig, $aDisplayData);
+			break;
+		}
+	}
+	
+	public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
+	{
+		$sHtml = '';
+		return $sHtml;
+	}
+
+	protected function RenderChart($oPage, $sId, $aValues)
+	{
+		// 1- Compute Open Flash Chart data
+		//
+		$aValueKeys = array();
+		foreach($aValues as $key => $value)
+		{
+			// Make sure that values are integers (so that max() will work....)
+			// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
+			$aValues[$key] = (int)$value;
+			$aValueKeys[] = (string)$key;
+		}
+	
+		$oChart = new open_flash_chart();
+	
+		if ($this->m_sType == 'bars')
+		{
+			$oChartElement = new bar_glass();
+		
+			$maxValue = max($aValues);
+			$oYAxis = new y_axis();
+			$aMagicValues = array(1,2,5,10);
+			$iMultiplier = 1;
+			$index = 0;
+			$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
+			while($maxValue > $iTop)
+			{
+				$index++;
+				$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
+				if (($index % count($aMagicValues)) == 0)
+				{
+					$iMultiplier = $iMultiplier * 10;
+				}
+			}
+			//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
+			$oYAxis->set_range(0, $iTop, $iMultiplier);
+			$oChart->set_y_axis( $oYAxis );
+		
+			$oChartElement->set_values(array_values($aValues));
+			$oXAxis = new x_axis();
+			$oXLabels = new x_axis_labels();
+			// set them vertical
+			$oXLabels->set_vertical();
+			// set the label text
+			$oXLabels->set_labels($aValueKeys);
+			// Add the X Axis Labels to the X Axis
+			$oXAxis->set_labels( $oXLabels );
+			$oChart->set_x_axis( $oXAxis );
+		}
+		else
+		{
+			$oChartElement = new pie();
+			$oChartElement->set_start_angle( 35 );
+			$oChartElement->set_animate( true );
+			$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
+			$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
+	
+			$aData = array();
+			foreach($aValues as $sValue => $iValue)
+			{
+				$aData[] = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
+			}
+	
+			$oChartElement->set_values( $aData );
+			$oChart->x_axis = null;
+		}
+	
+		// Title given in HTML
+		//$oTitle = new title($this->m_sTitle);
+		//$oChart->set_title($oTitle);
+		$oChart->set_bg_colour('#FFFFFF');
+		$oChart->add_element( $oChartElement );
+			
+		$sData = $oChart->toPrettyString();
+		$sData = json_encode($sData);
+
+		// 2- Declare the Javascript function that will render the chart data\
+		//
+		$oPage->add_script(
+<<< EOF
+function ofc_get_data_{$sId}()
+{
+	return $sData;
+}
+EOF
+		);
+		
+		// 3- Insert the Open Flash chart
+		//
+		$oPage->add("<div id=\"$sId\">If blah blah cd romain<div>\n");
+		$oPage->add_ready_script(
+<<<EOF
+swfobject.embedSWF(	"../images/open-flash-chart.swf", 
+	"{$sId}", 
+	"100%", "300","9.0.0",
+	"expressInstall.swf",
+	{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"}, 
+	{'wmode': 'transparent'}
+);
+EOF
+		);
+	}
+}
+
+?>

+ 7 - 1
application/template.class.inc.php

@@ -35,7 +35,7 @@ class DisplayTemplate
 	
 	public function __construct($sTemplate)
 	{
-		$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring');
+		$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring', 'sqlblock');
 		$this->m_sTemplate = $sTemplate;
 	}
 	
@@ -203,6 +203,12 @@ class DisplayTemplate
 				$oPage->add(Dict::S($sContent));
 			break;
 			
+			case 'sqlblock':
+				$oBlock = SqlBlock::FromTemplate($sContent);
+				$oBlock->RenderContent($oPage);
+			break;
+			
+
 			case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
 				$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
 			break;

+ 1 - 0
pages/ajax.render.php

@@ -207,6 +207,7 @@ try
 		$oPage->add_script("oWizardHelper{$sFormPrefix}.m_oData=".$oWizardHelper->ToJSON().";\noWizardHelper{$sFormPrefix}.UpdateFields();\n");
 		break;
 			
+		// DisplayBlock
 		case 'ajax':
 		if ($sFilter != "")
 		{