A control that takes a simple SQL select statement and generates a Grid like the details view in the MS Explorer with range links at the bottom to get more results. Each column can be clicked on and sorted by that column.
Click, on it again and it inverts the results. It also allows you to pass in custom mappings so that you can filter the results, hide, move them around, or run them through any function call. It does it by storing the SQL and state in a hidden form that is manipulated through javascript. It's all completely customizable using PEAR's table class.
This class currently supports Oracle and MySql through PEAR's DB Class. A demo is available
online.
By : ignatz
<?php
/**
* PHP SqlGrid Display Control
* Copyright (C) 2002 Christopher Raymond Baker
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
* Christopher Raymond Baker [cbaker@cbaker.org]
* http://cbaker.org
*/
// PEAR Libraries
require_once "DB.php";
require_once "HTML/Table.php";
///////////////
// CONSTANTS //
///////////////
define("DEFAULT_BASE_NAME", "GridControl");
define("HEAD", "Head");
define("CAPTION", "Caption");
define("COLUMNS", "Columns");
define("CELL", "Contents");
define("RANGE_LINK", "CaptionLink");
define("COLUMN_LINK", "ColumnLink");
// Default style parameters for the grid.
// These can be overridden by passing a class or style to the control at any point.
define("DEFAULT_STYLE_TABLE", "border: solid #333666 1px; border-color: #bebebe; background-color: #bebebe; padding: 0px;");
define("DEFAULT_STYLE_HEAD", "background-color: #006699; border-color: #bebebe; color: white; font-family: verdana arial helvetica sans-serif; font-size: xx-small; font-weight: bold;");
define("DEFAULT_STYLE_COLUMNS", "background-color: #bebebe; border-color: #bebebe; color: black; font-family: verdana arial helvetica sans-serif; font-size: xx-small;");
define("DEFAULT_STYLE_TD", "background-color: #ffffff; border-color: #bebebe; background-color: white; color: black; font-family: verdana arial helvetica sans-serif; font-size: xx-small;");
define("DEFAULT_STYLE_CAPTION", "background-color: #006699; border-color: #bebebe; color: white; font-family: verdana arial helvetica sans-serif; font-size: xx-small;");
define("HTML_UP_ARROW", "<b>↑</b>");
define("HTML_DOWN_ARROW", "<b>↓</b>");
// How many rows per page?
define("DEFAULT_MAX_RESULTS_PER_PAGE", 20);
// How many links each direction from the cursor?
define("DEFAULT_MAX_RANGE_LOOPS", 3);
define("GRID_DEBUG_MODE", false);
// pregHashValReplace() constants
define("RAW_KEY_MATCH", "\[\[(\w+)\]\]");
define("ENCODE_KEY_MATCH", "\[\[>(\w+)<\]\]");
/**
* Compontent for manipulating SQL result sets in an HTML grid.
*
* A control that takes a simple SQL select statement and generates a Grid
* like the details view in the MS Explorer with range links at the bottom to
* get more results. Each column can be clicked on and sorted by that column.
* Click, on it again and it inverts the results. It also allows you to
* pass in custom mappings so that you can filter the results, hide, move them
* around, or run them through any function call. It does it by storing the
* SQL and state in a hidden form that is manipulated through javascript.
* It's all completely customizable using PEAR's table class.
*
* This class currently supports Oracle and MySql through PEAR's DB Class.
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* CURRENTLY ONLY WORKS FOR MySQL or Oracle 8 or higher.
*
* This class requires PEAR in the path on the server and JavaScript on the
* client.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
*******************************************************************************
* USAGE:
*
* EXAMPLE ONE: Default Display
* $dns = "oci8://foo:bar@db1";
* $sql = "select rep_id, logon_name, first_name, last_name from SALES_REP";
* $g = new Grid($dns, $sql);
* print $g->toHtml();
*
* EXAMPLE ONE: With Customization
*
* $dns = "oci8://foo:bar@db1";
* $sql = "select rep_id, logon_name, first_name, last_name from SALES_REP";
*
* $map = array(
* "rep_id" => array(
* "NAME" => "ID",
* "PROP" => "<a href='?itxt_grant_id=[[PORTAL_USER_LOGON_NM]]' style='color: lime'>[[:self:]]</a>"),
* "logon_name" => array("NAME" => "USER ID",
* "PROP" =>"<input type='text' name='[[SLS_REP_ID]]' value='[[:self:]]'>"),
* "first_name" => array("NAME" => "FIRST NAME",
* "SUB" => "LAST_NM", // Set sub sort if selected (i.e. "order by FIRST_NM, LAST_NM")
* "EVAL" => "ucfirst(strtolower([[:self:]]))",
* "PROP" => "<b>[[:self:]]</b>"),
* "last_name" => array("NAME" => "LAST NAME",
* "SUB" => "FIRST_NM",
* "EVAL" => "ucfirst(strtolower([[:self:]]))",
* "PROP" => "<b>[[:self:]]</b>"));
* $g = new SqlGrid($dns, $sql, $map);
*
* // Only show 15 records at a time
* $g->maxResults(15);
*
* // Set LAST_NM to be the default order for the results
* $g->setDefaultColumn("LAST_NM");
*
* // Set the attributes for various parts of the Grid
* // All of these can also be set through an outside stylesheet.
* $g->tableAttributes(array("style"=>"background-color: black;", "width"=>300));
* $g->headerAttributes(array("style"=>"background-color: lime; font-size: 9pt;"));
* $g->columnAttributes(array("style"=>" font-size: 9pt;background-color: silver; border-top: solid white 2px; border-left: solid white 2px; border-bottom: solid #808080 2px; border-right: solid #808080 2px; color: red;"));
* $g->columnLinkAttributes(array("style"=>"color: green;"));
* $g->resultAttributes(array("style"=>"color: white; font-family: 'Comic Sans MS'; font-size: 9pt;"));
* $g->captionLinkAttributes(array("style"=>"color: lime;"));
* $g->captionAttributes(array("style"=>"background-color: black; color: white; font-size: 9pt;"));
*
* // print so that the form before the grid can be closed and not conflick with the
* // grid's hidden form.
* $g->closeForm = true;
*
* // Display the grid, passing in a title.
* print $g->toHtml("Show Reps");
*
*
* EXAMPLE THREE: Using Outside Style Sheet
*
* .box {
* border: solid #CC9966 3px;
* background-color: #FFCC99;
* }
* .boxHead {
* background-color: #FFCC99;
* font-size: 9pt;
* border-bottom: solid #CC9966 3px;
* }
* .boxCaption {
* border-left: solid #CC9966 3px;
* border-right: solid #CC9966 3px;
* border-bottom: solid #CC9966 3px;
* background-color: #FFCC99;
* font-weight: bold;
* font-size: 9pt;
* color: #000000;
* }
* .boxCaptionLink {
* font-weight: bold;
* font-size: 9pt;
* color: #000000;
* }
* .boxCaptionLink:visited {
* font-weight: bold;
* font-size: 9pt;
* color: #000000;
* }
* .boxColumnLink {
* font-weight: bold;
* font-size: 9pt;
* color: #000000;
* }
* .boxContents {
* background-color: #FFFFFF;
* padding-left: 3px;
* padding-right: 3px;
* }
* <?php
* $sql = "select rep_id, logon_name, first_name, last_name from SALES_REP";
*
* $map = array(
* "rep_id" => array(
* "NAME" => "ID",
* "PROP" => "<a href='?itxt_grant_id=[[PORTAL_USER_LOGON_NM]]'>[[:self:]]</a>"),
* "logon_name" => array("NAME" => "USER ID"),
* "first_name" => array(
* "NAME" => "FIRST NAME",
* "SUB" => "LAST_NM",
* "EVAL" => "ucfirst(strtolower([[:self:]]))",
* "PROP" => "<b>[[:self:]]</b>"),
* "last_name" => array(
* "NAME" => "LAST NAME",
* "SUB" => "FIRST_NM",
* "EVAL" => "ucfirst(strtolower([[:self:]]))",
* "PROP" => "<b>[[:self:]]</b>"));
*
* $g = new Grid("oci8://foo:bar@db1", $sql, $map);
*
* // Set the attribiutes for the table, setting the table's base class name
* // to box.
* $g->tableAttributes(array("class"=>"box", "width"=>400));
*
* // Display the grid, passing in a title.
* print $g->toHtml("Mammotome Reps");
*******************************************************************************
* THE MAP ARRAY
*
* The SqlGrid has an optional third argument called the map array.
*
* The map array is a hash with the keys being the column names from the
* returned result set.
*
* The value for each key is a hash that can include four different keys:
*
* NAME: replaces the key in the controls display
* HIDE: Hide this column.
* EVAL: Display the returned value from the quoted string after running
* it though eval(), replacing [[:self:]] with this key's specific
* value, and [[COLUMN_NAME]] with any column that is in the result
* set, thus allowing for using the values of hidden columns.
* PROP: Display the enclosed string, performing the same replacements for
* [[:self:]] and [[COLUMN_NAME]] as with EVAL.
* LENGTH: Shows n length of field with the rest as an HTML title tooltip.
*
*
*******************************************************************************
* FUNCTIONALITY USE CASE
* 1) POST sends POST_DATA to SCRIPT.
* 2) SCRIPT turns POST_DATA in SQL.
* 3) SCRIPT makes CONNECTION to database.
* 4) SCRIPT creates GRID with the CONNECTION and SQL.
* 5) GRID creates HIDDEN_FORM containing the GRID's state.
* 6) GRID recreates itself using HIDDEN_FORM data on interaction.
*
* CHANGES:
*
* 6/21/02
*
* 5/28/02
* *) toHtml() now returns empty on result set return of 0
*
* 3/3/02
*
* *) Supports MySQL
* *) Supports PEAR::DB proper
*
* 3/5/02
*
* *) Removed GridClassProperties file to Gird class proper.
* *) Fixed PROP replacement on non [[:self:]] entities.
* *) CSS Class cascading for grid cells and grid links working.
*/
class SqlGrid
{
/**
* Base select SQL for the control
*
* @var string SQL string
* @access private
*/
var $_baseSql;
/**
* AppSql DB Connection Object
*
* @var AppSql
* @access public
*/
var $db;
/**
* dsn database connection string
*
* @var string
* @access private
*/
var $_dsn;
/**
* The total count of the recordset
*
* @var int
* @access private
*/
var $_count;
/**
* Field holding the maximum results to display per page.
*
* @var int
* @access private
*/
var $_maxResults;
/**
* The pointer to the start of the Recordset slice being viewed.
*
* @val int
* @access private
*/
var $_cursor;
/**
* Pointer to the Grid field that is setting the search order.
*
* @val string
* @access private
*/
var $_order;
/**
* Which direction the record set ORDER BY is going in.
*
* @val boolean
* @access private
*/
var $_isAscending;
/**
* Multi-d array mapping fields to properties.
*
* @val array
*/
var $dataMap;
/**
* List of array column display names
*
* @val array
* @access private
*/
var $_cols;
/**
* Result Set returned from the SQL.
*
* @val array
* @access private
*/
var $_resultSet;
/**
* Should the GridTable end with </form>
*
* @val boolean
* @access public
*/
var $closeForm = false;
/**
* The GridTable object for the class
*
* @var GridTable
* @access public
*/
var $table;
/**
* Error object. Field to hold Pear errors.
*
* @var mixed PEAR_Error/boolean
* @access public
*/
var $state;
/**
* Attributes for the contents of the GrigTable's root table.
*
* @var array HTML_Common properties array
* private
*/
var $_tableAttributes = array();
/**
* Attributes for the contents of the GrigTable's header links.
*
* @var array HTML_Common properties array
* private
*/
var $_headerAttributes = array();
/**
* Attributes for the contents of the GrigTable's header links.
*
* @var array HTML_Common properties array
* private
*/
var $_headerLinkAttributes = array();
/**
* Attributes for the contents of the GrigTable's column headers.
*
* @var array HTML_Common properties array
* private
*/
var $_columnAttributes = array();
/**
* Attributes for the contents of the GrigTable's column header links.
*
* @var array HTML_Common properties array
* private
*/
var $_columnLinkAttributes = array();
/**
* Attributes for the contents of the GrigTable's results rows.
*
* @var array HTML_Common properties array
* private
*/
var $_resultAttributes = array();
/**
* Attributes for the contents of the GrigTable's caption.
*
* @var array HTML_Common properties string
* private
*/
var $_captionAttributes = array();
/**
* Attributes for the links in the GrigTable's caption.
*
* @var array HTML_Common properties string
* private
*/
var $_captionLinkAttributes = array();
/**
* Count of the number of instances of the class that have been declared.
*
* This is used to
*
* @var int
* public
*/
var $classCount;
/**
* The name for the object's hiddenform name
*
* @var string
* private
*/
var $_formName;
/**
* The value of the object's hiddenform name ACTION parameter.
*
* @var string
* private
*/
var $_formAction = "";
/**
* Constructor
*
* @param string $dsn DSN database connection string
* @param string $sql SQL string for the Grid
* @param array $map HASH grid control datamap
*/
function SqlGrid($dsn, $sql = null, $map = null)
{
// Increment the static class instance counter.
static $classCount = 0;
$classCount++;
$this->classCount = $classCount;
// Die on multiple instances
// Working on allowing that, but can't as yet.
if ($classCount > 1) {
die("<h1 style='color: red'>ERROR<BR>Unable to create more than one Grid Class at a time.</h1>");
}
// Initialize detault field values
$this->state = true;
// Make sure that $db is the right class.
if (get_class($dsn) == "appsql") {
$this->db =& $dsn;
} else {
$this->_dsn = $dsn;
$this->db = DB::connect($dsn);
if (DB::isError($this->db)) {
$this->state = $this->db;
}
}
// Set the base query, making sure that it is a select statement.
$e = $this->baseSql($sql);
if (PEAR::isError($e)) {
$this->state = $e;
}
$this->_cursor = 1;
$this->_order = "";
$this->_isAscending = "true";
$this->_maxResults = DEFAULT_MAX_RESULTS_PER_PAGE;
$this->dataMap = $map;
$this->_init();
} // end constructor
/**
* Returns the API version
* @access public
* @returns double
*/
function apiVersion()
{
return 1.2;
} // end func apiVersion
/**
* Initializes the class with the values from the GridControl's post vars.
*
* @returns void
* @access private
*/
function _init()
{
// Make sure that the form has the right name, and that it is coming from
// the same page as it was initially displayed in.
if (SqlGridCgi::getPost("poster") == $this->formName()) {
$this->isAscending(SqlGridCgi::getPost("isAscending"));
$invert = SqlGridCgi::getPost("invert");
if ($invert == "yes") {
if ($this->isAscending() == "true") {
$this->isAscending("false");
} else {
$this->isAscending("true");
}
} elseif ($invert == "no") {
// Do nothing
} else {
$this->isAscending("true");
}
$this->cursor(SqlGridCgi::getPost("cursor"));
$this->order(SqlGridCgi::getPost("order"));
$e = $this->baseSql(urldecode(SqlGridCgi::getPost("basesql")));
if (SqlGridTest::isEvil($e)) {
$this->state = $e;
}
}
} // end func _init
/**
* Maps the resultsset's columns to the dataMap array, generating the column header.
*
* @returns boolean
* @access private
*/
function _map(&$row)
{
$this->_cols = array();
// Create HTML_A object for the range links
$attributes = array();
// Check for cssBase, and if so set a specific CSS class name for the links
if ($this->table->cssBase()) {
$attributes = array("class" => $this->table->cssBase() . COLUMN_LINK);
}
$attributes = array_merge($attributes, $this->columnLinkAttributes());
$colAnchor = new HTML_A($attributes);
foreach($row as $key => $value) {
// Only push in column headers if there is no HIDE attribute in the datamap for the key.
if (!isset($this->dataMap[$key]['HIDE'])) {
// Name the column header after the NAME property of the map, if set
if (isset($this->dataMap[$key]['NAME'])) {
$name = $this->dataMap[$key]['NAME'];
} else {
$name = $key;
}
$href = $this->getJLink($key, true, 1);
if (!isset($this->dataMap[$key]['FIX'])) {
$link = $colAnchor->toHtml($name, $href, array("title" => "Sort by $name"));
} else {
$link = $name;
}
$link .= $this->getDirectionArrow($key);
$link = "<nobr>$link</nobr>";
array_push ($this->_cols, $link);
}
}
} // end func _map
/**
* Updates the attributes for the contents of the GrigTable's root table.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function tableAttributes($attributes = null)
{
if ($attributes) {
$this->_tableAttributes = $attributes;
return true;
}
return $this->_tableAttributes;
} // end func tableAttributes
/**
* Updates the attributes for the contents of the GrigTable's header links.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function headerAttributes($attributes = null)
{
if ($attributes) {
$this->_headerAttributes = $attributes;
return true;
}
return $this->_headerAttributes;
} // end func headerAttributes
/**
* Updates the attributes for the contents of the GrigTable's header links.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function headerLinkAttributes($attributes = null)
{
if ($attributes) {
$this->_headerLinkAttributes = $attributes;
return true;
}
return $this->_headerLinkAttributes;
} // end func headerLinkAttributes
/**
* Updates the attributes for the contents of the GrigTable's column headers.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function columnAttributes($attributes = null)
{
if ($attributes) {
$this->_columnAttributes = $attributes;
return true;
}
return $this->_columnAttributes;
} // end func columnAttributes
/**
* Updates the attributes for the contents of the GrigTable's column header links.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function columnLinkAttributes($attributes = null)
{
if ($attributes) {
$this->_columnLinkAttributes = $attributes;
return true;
}
return $this->_columnLinkAttributes;
} // end func columnLinkAttributes
/**
* Updates the attributes for the contents of the GrigTable's results rows.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function resultAttributes($attributes = null)
{
if ($attributes) {
$this->_resultAttributes = $attributes;
return true;
}
return $this->_resultAttributes;
} // end func resultAttributes
/**
* Updates the attributes for the contents of the GrigTable's caption.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function captionAttributes($attributes = null)
{
if ($attributes) {
$this->_captionAttributes = $attributes;
return true;
}
return $this->_captionAttributes;
} // end func captionAttributes
/**
* Updates the attributes for the links in the GrigTable's caption.
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @access public
* @return array
*/
function captionLinkAttributes($attributes = null)
{
if ($attributes) {
$this->_captionLinkAttributes = $attributes;
return true;
}
return $this->_captionLinkAttributes;
} // end func captionLinkAttributes
/**
* Accessor for the _formName field.
*
* @returns string
*/
function formName($name = "")
{
if ($name) {
$this->_formName = $name;
} elseif (!isset($this->_formName)) {
$this->_formName = DEFAULT_BASE_NAME;
}
return $this->_formName;
} // end func formName
/**
* Updates the attributes for the contents of the GrigTable's column header links.
*
* @param string $action
* @access public
* @return string
*/
function formAction($action = "")
{
if ($action) {
$this->_formAction = $action;
}
return $this->_formAction;
} // end func formAction
function baseSql($sql = "")
{
trim($sql);
if ($sql) {
// Make sure that the SQL is a select
if (!eregi("^select", $sql)) {
return new PEAR_Error("Must use a select statement on this method call.");
} else {
// Strip ORDER BY from the SQL statements as this will break the Grid.
if (ereg("(.+)ORDER BY", $sql, $r)) {
$sql = $r[1];
}
$this->_baseSql = $sql;
return true;
}
} else {
return $this->_baseSql;
}
}
/**
* Takes $this->_baseSql and wraps it in sql related to the GridControl's properties.
*
* @returns string
*/
function sql()
{
return $this->_baseSql . $this->getSqlOrderBy();
} // end func sql
/**
* Returns the proper SQL ORDER BY value.
*
* Created to fix a BUG related to using oracle 7.
*
* @returns string
*/
function getSqlOrderBy()
{
$order = "";
if ($this->order()) {
$order = " ORDER BY " . $this->order() . " ";
if (isset($this->dataMap[$this->order()]['SUB'])) {
$order .= $this->getDescString() . ", " . $this->dataMap[$this->order()]['SUB'] . " ";
}
}
return $order . $this->getDescString();
}
/**
* Wraps the passed SQL in SQL to count the results.
*
* @param string $sql Raw sql string to wrap SQL count around.
* @access public
* @returns string
* @static
*/
function getCountSql($sql)
{
if (extension_loaded('mysql')) {
preg_match("/from\s+(\w+)/i", $sql, $args);
$sql = "Select count(*) C from " . $args[1];
} else {
$sql = "Select count(*) C from (" . $sql . ")";
}
return $sql;
} // end func getCountSql
/**
* Wraps the passed SQL in SQL to count the results.
*
* @access private
* @returns string
* @static
*/
function getSqlSlice()
{
$rownumMax = $this->maxResults() + $this->cursor();
if ( extension_loaded('mysql')) {
return $this->sql() . " LIMIT " . $this->cursor() . ", " . ($rownumMax - 1);
} else {
return "Select * from (" . $this->_baseSql . " " . $this->getSqlOrderBy() . ") where rownum < " . $rownumMax;
}
} // end func getSqlSlice
/**
* Takes $this->_baseSql and determines how many reconds would be returned from the resultset.
*
* @access public
* @returns int
*/
function getAdvancedCount()
{
if (SqlGridTest::isEvil($this->state)) {
return false;
}
$rs = $this->db->getOne(SqlGrid::getCountSql($this->_baseSql));
if (DB::isError($rs)) {
die ($rs->getMessage());
}
// die($rs);
if (extension_loaded('mysql')) {
$rs--;
}
return $rs;
} // end func getAdvancedCount
/**
* Accessor to the basesql's resultset count.
*
* @param int $v (Optional) Sets to Value of count if set.
* @returns int
* @access public
*/
function count($v = NULL)
{
if ($v == NULL) {
// Pattern: Lazy initialization
// http://www.object-arts.com/EducationCentre/Patterns/LazyInitialization.htm
if (!isset($this->_count)) {
$this->_count = $this->getAdvancedCount();
}
return $this->_count;
}
$this->_count = (int) $v;
return true;
} // end func count
/**
* Accessor to the _maxResults field.
*
* @param int $val (Optional) Sets to Value of $this->_maxResults if set.
* @returns int
* @access public
*/
function maxResults($val = false)
{
if ($val) {
$this->_maxResults = (int) $val;
return $this->_maxResults;
} else {
return $this->_maxResults;
}
}
/**
* Accessor to the _order field.
*
* Order is the field_name that the resultSet is being ordered by.
*
* @param string $v (Optional) Sets to Value of $this->_order if set.
* @returns string
* @access public
*/
function order($v = false)
{
if ($v) {
$this->_order = $v;
}
return $this->_order;
} // end func order
/**
* Accessor to the resultset cursor (Starting point of displayed results).
*
* @param int $v (Optional) Sets to Value of $this->_cursor if set.
* @returns int
* @access public
*/
function cursor($v = false)
{
if ($v) {
$this->_cursor = $v;
}
return $this->_cursor;
} // end func cursor
/**
* Accessor to the _isAscending field.
*
* Allowable values are the strings "true" or "false" so that these can be explicitly
* set in the GridControl's hidden properties form.
*
* @param string $v (Optional) Sets to Value of $this->_isAscending if set.
* @returns string
* @access public
*/
function isAscending($v = "")
{
if (!$v)
return $this->_isAscending;
if ($v == "true") {
$this->_isAscending = "true";
} else {
$this->_isAscending = "false";
}
return $this->_isAscending;
} // end func isAscending
/**
* Returns HTML for the resultset's direction.
*
* @param string $var The selected field
* @returns string
* @access public
*/
function getDirectionArrow($var)
{
if ($var == $this->order()) {
if ($this->isAscending() == "true") {
return HTML_DOWN_ARROW;
} else {
return HTML_UP_ARROW;
}
} else {
return "";
}
} // end func getDirectionArrow
/**
* Returns SQL miodifier to invert the direction of the resultSet.
*
* @returns string
* @access public
*/
function getDescString()
{
if ($this->isAscending() == "true") {
return "";
} else {
return " DESC";
}
} // end func getDescString
/**
* Returns HTML results values for the GridControl's header (as in: "[1 - 18 out of 18]")
*
* @returns string
* @access public
*/
function getTitle()
{
$top = ($this->cursor() + $this->maxResults()) -1;
if ($top > $this->count()) {
$top = $this->count();
}
$html = '[' . $this->cursor() . ' - ' . $top . ' out of ' . $this->count() . ']';
return $html;
}
/**
* Sets the _order field to a specific column IF is isn't already set through _init()
*
* @access public
* @return void
*/
function setDefaultColumn($col, $isDescending = false)
{
if (!$this->order()) {
if ($isDescending) {
$this->isAscending("false");
}
$this->order($col);
}
} // end func setDefaultColumn
/////////////
// RESULTS //
/////////////
/**
* Returns a JavaScript link for sorting by the column passed.
*
* @param string $column The column name clicked through JScript.
* @param boolean $invert
* @param int $cursor
* @access private
* @return string
*/
function getJLink($column, $invert, $cursor = false)
{
if (!$cursor) {
$cursor = $this->cursor();
}
$s = "javascript: setOrder(\"$column\", \"";
$inVal = "no";
if ($invert) {
if ($column == $this->order()) {
$inVal = "yes";
} else {
$inVal = "void";
}
}
$s .= $inVal . "\", " . $cursor . ")";
return $s;
} // end func getJLink
/**
* Creates a row of links to various views of the dataset, i.e.
* ... [61-80] [81-100] [101-120] [121-140] [141-160] [161-180] [181-200] ...
*
* This is to mimic the links for more results at the bottom of search results pages.
*
* The attributes of the row within the GridControl can be set by passing in values
* through the captionAttributes() and captionLinkAttributes() methods.
*
* IMPORTANT VARIABLES
*
* $this->cursor() Pointer to the current views starting point.
* Starts at 1 and goes up in increments of $this->maxResults()
* $this->maxResults() The number of records that are displayed at a time.
* DEFAULT_MAX_RANGE_LOOPS The number of range links in either direction from $this->cursor()
*
* @access protected
* @return string
*/
function getRangeLinks()
{
$results = "";
$startingPoint = $this->cursor() - ($this->maxResults() * DEFAULT_MAX_RANGE_LOOPS);
if ($startingPoint < 1) {
$startingPoint = 1;
}
// Used to determine if a "..." indicator needs to be added to the end of a range.
$rBounds = ((DEFAULT_MAX_RANGE_LOOPS * 2) + 1) * $this->maxResults();
// Used to determine if a "..." indicator needs to be added to the beginning of a range.
$border = DEFAULT_MAX_RANGE_LOOPS * $this->maxResults();
$lBounds = ($this->cursor()) - $border;
// See if the curser is at a point greater than where the start range link is visible.
if ($lBounds > 1) {
$results .= " ... ";
}
// Create A object for the range links
if ($this->table->cssBase()) {
$attributes = array("class" => $this->table->cssBase() . RANGE_LINK);
} else {
$attributes = array("style"=>"color: #80FFFF");
}
$attributes = array_merge($attributes, $this->captionLinkAttributes());
$rangeAnchor = new HTML_A($attributes);
$maxLoop = 0;
for ($x = $startingPoint; $x < $this->count(); $x = $x + $this->maxResults()) {
// Get end number.
$nextNum = (($x + $this->maxResults()) - 1);
if ($nextNum > $this->count()) {
$nextNum = $this->count();
}
$results .= "[";
if ($x == $this->cursor()) {
$results .= $x . "-" . $nextNum ;
} else {
$results .= $rangeAnchor->toHtml($x . "-" . $nextNum, $this->getJLink($this->order(), false, $x));
}
$results .= "] ";
$maxLoop++;
if ($maxLoop == (DEFAULT_MAX_RANGE_LOOPS + (DEFAULT_MAX_RANGE_LOOPS + 1))) {
break;
}
}
if (($this->count() > $rBounds) && (($this->cursor() + $this->maxResults()) < ($this->count() - (DEFAULT_MAX_RANGE_LOOPS * $this->maxResults())) )) {
$results .= " ... ";
}
return $results;
} // end func getRangeLinks
/**
* Returns the form used at the bottom of the control to do dimension sorts.
*
* @access private
* @return string
*/
function getForm()
{
$html = ("
<script>
function setOrder(order, invertOrder, cursor)
{
document." . $this->formName() . ".order.value = order;
if (invertOrder == 'yes') {
document." . $this->formName() . ".invert.value = 'yes';
} else if (invertOrder == 'no') {
document." . $this->formName() . ".invert.value = 'no';
}
document." . $this->formName() . ".cursor.value = cursor;
document." . $this->formName() . ".submit();
}
</script>");
$html .= "\n\t\t\t<!-- Start Grid Class Form -->";
$html .= "\n\t\t\t<form method='post' name ='" . $this->formName() . "' action='" . $this->formAction() . "'>";
$html .= ("
<input type='hidden' name='poster' value='" . $this->formName() . "'>
<input type='hidden' name='basesql' value='" . urlencode($this->_baseSql) . "'>
<input type='hidden' name='order' value='TYPE'>
<input type='hidden' name='isAscending' value='" . $this->isAscending() . "'>
<input type='hidden' name='invert' value='void'>
<input type='hidden' name='cursor' value='1'>");
$html .= "\n\t\t\t</form>\n";
$html .= "\t\t\t<!-- End Grid Class Form -->";
return $html;
} // end func getForm
/**
* Returns the SqlGrid as HTML
*
* @access public
* @param string $title String to be added to the from of the getTitle() value.
* @return string
*/
function toHtml($title = "")
{
if (SqlGridTest::isEvil($this->state)) {
return false;
}
if ($this->count()) {
$query = $this->getSqlSlice();
$result = $this->db->query($query);
if (DB::isError($result)) {
return new PEAR_Error($result->getMessage());
} else {
$this->table =& GridTable::factory($this->tableAttributes(), 2);
$title .= " " . $this->getTitle();
$this->table->setHeader($title, $this->headerAttributes());
$counter = 0;
while($row = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
if ($counter == 0) {
$this->_map($row);
$this->table->setColumns($this->_cols, $this->columnAttributes());
}
$counter++;
// MySql has the limit range, so it doesn't need to cut out rows from display.
if (extension_loaded('mysql') || $counter >= $this->cursor()) {
$rowCells = array();
foreach($row as $key => $value) {
// Only push in cell values if there is no HIDE attribute in the datamap.
if (!isset($this->dataMap[$key]['HIDE'])) {
$nv = $value;
if (isset($this->dataMap[$key]['SIZE'])) {
$nv = substr($nv, 0, $this->dataMap[$key]['SIZE']);
}
// Run the value through the datamap's EVAL property (if it has one)
if (isset($this->dataMap[$key]['EVAL'])) {
$nv = $this->_filterEval($key, $nv, $row);
}
// Check the datamap for the LENGTH property and process it
// Only showing the first n length and showing the rest as an HTML title tooltip.
// ie: $string = "<span title='FULL STRING'>STRING_TO_LENGTH<font size='1'>...</font></span>";
if (isset($this->dataMap[$key]['LENGTH'])) {
$nvSub = substr($nv, 0, $this->dataMap[$key]['LENGTH']);
$nv = preg_replace("/'/", "\'", $nv);
$nv = "<span title='$nv'>$nvSub<font size='1'>...</font></span>";
}
// Do the same for its PROP property
if (isset($this->dataMap[$key]['PROP'])) {
$nv = $this->_filterProp($key, $nv, $row);
}
array_push ($rowCells, $nv);
}
}
$this->table->setResultRow($rowCells, $this->resultAttributes());
}
}
$this->db->freeResult($result);
$this->table->setRangeLinks($this->getRangeLinks(), $this->captionAttributes());
$closeFormHTML = "";
if ($this->closeForm) {
$closeFormHTML = "</form>";
}
$this->db->disconnect();
return $this->table->display() . $closeFormHTML . $this->getForm();
}
} else {
return "";
}
} // end func toHtml
/**
* Takes a result field and filters it replacing [[key]] with the values in the row hash.
*/
function _filterProp($key, $value, &$row)
{
// Replace all instances of [[:self:]] in $this->dataMap[$key]['PROP'] with $value
$nv = str_replace("[[:self:]]", $value, $this->dataMap[$key]['PROP']);
// Loop through each PROP string replacing each [[>key<]] with urlencode(stripslashes($row[$key]))
$nv = Grid::pregHashValReplace(ENCODE_KEY_MATCH, $nv, $row);
// Loop through each PROP string replacing each [[key]] with $row[$key]
$nv = Grid::pregHashValReplace(RAW_KEY_MATCH, $nv, $row);
return $nv;
}
/**
* Takes a result field and filters it replacing [[key]] with the values in the row hash,
* AND running the EVAL string through eval returning it's scalar result.
*/
function _filterEval($key, $value, &$row)
{
$result = "";
// The eval statement MUST return a scaler.
$e = '$result = ' . $this->dataMap[$key]['EVAL'] . ';';
// Replace all instances of [[:self:]] in $this->dataMap[$key]['EVAL'] with $value
$e = str_replace("[[:self:]]",$value ,$e);
// Loop through each PROP string replacing each [[>key<]] with urlencode(stripslashes($row[$key]))
$e = Grid::pregHashValReplace(ENCODE_KEY_MATCH, $e, $row);
// Loop through each PROP string replacing each [[key]] with $row[$key]
$e = Grid::pregHashValReplace(RAW_KEY_MATCH, $e, $row);
eval($e);
return $result;
} // end func _filterEval
/**
* Greedy preg_match replacing a pattern with a value in a hash.
*
* NOTE JUST MADE ON php.net: [http://www.php.net/manual/en/function.preg-replace.php]
*
* Since, as far as I can tell, the preg_replace() replacement parameter can't
* deal with using $1 as a key in an existing hash, here's an ugly hack that
* does just that:
*
* $string = "asdf[[foo]]asdf[[bar]]asdf";
* $args = array("foo"=>"BAR", "bar"=>"PACO");
* while(preg_match("/^(.*)\[\[(\w+)\]\](.*)$/", $string, $match)) {
* $string = $match[1] . $args[$match[2]] . $match[3];
* }
*
* It would be nice if
* $string = preg_replace("/\[\[(\w+)\]\]/", $args["$1"], $string);
* worked, but it don't.
*/
function pregHashValReplace($regex, $val, &$hash)
{
// Loop through each PROP string replacing each [[key]] with $row[$key]
while(preg_match("/^(.*)" . $regex . "(.*)$/", $val, $match)) {
$middle = $hash[$match[2]];
if ($regex == ENCODE_KEY_MATCH) {
$middle = urlencode(stripslashes($middle));
}
$val = $match[1] . $middle . $match[3];
}
return $val;
} // end func pregHashValReplace
/////////////////////////////////////////////////////////////////////
//////////////////////// DEBUGGING METHODS //////////////////////////
/////////////////////////////////////////////////////////////////////
/**
* Returns a hash of the classes current fields.
*
* @return array
*/
function toHash()
{
$dumpee = array(
"_baseSql" => $this->_baseSql,
"sql" => $this->sql(),
"urlencode(sql)" => urlencode($this->sql()),
"getSqlSlice" => $this->getSqlSlice(),
"count" => $this->count(),
"maxResults" => $this->maxResults(),
"cursor" => $this->cursor(),
"order" => $this->order(),
"isAscending" => $this->isAscending(),
"dataMap" => $this->dataMap,
"_tableAttributes" => $this->_tableAttributes,
"_headerAttributes" => $this->_headerAttributes,
"_headerLinkAttributes" => $this->_headerLinkAttributes,
"_columnAttributes" => $this->_columnAttributes,
"_columnLinkAttributes" => $this->_columnLinkAttributes,
"_captionAttributes" => $this->_captionAttributes,
"_captionAttributes" => $this->_captionAttributes,
"_captionLinkAttributes" => $this->_captionLinkAttributes,
"state" => $this->state,
"this->classCount" => $this->classCount,
"this->formName()" => $this->formName()
);
return $dumpee;
}
} // end class Grid
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* Special PEAR Table class for use by the GridControl Component.
*
* Functionality that is above and beyond what the class' parent
* HTML_Table includes:
* * Automatic table style parameter generation
* * Ability to override the default style parameter names
* * Disabling of default styles IF a user passed
* a class parameter to the class. (This avoiding CSS clashes
* since attributes set in the style parameter override
* CSS from an included style sheet referenced in a class
* attribute.
*
* Below is the format of the table as created by the GridControl
* class. Application developers shouldn't have to directly call
* this class, instead letting GridControl do the work for them.
*
* GRID FORMAT:
* ********************************************************
* * setHeader() *
* ********************************************************
* * setColumns() * * * * * *
* ********************************************************
* * setResultRow() * * * * * *
* ********************************************************
* * * * * * * * * *
* ********************************************************
* * * * * * * * * *
* ********************************************************
* * setRangeLinks() *
* ********************************************************
*/
class GridTable extends HTML_Table
{
/**
* Base text string for the class attribute passed to the table for each row.
* For Example:
*
* $grid = new HTML_GridControl(array("class"=>"foo", "border"=>2));
* // _cssBase set to "foo"
* $grid->setHeader("Sample Grid");
* // Header row's class parameter set to "fooHead" (Default action)
* $grid->setColumns(array("Row 1", "Row 2", "Row 3"));
* // Column's class parameter set to "fooColumns" (Default action)
* $grid->setResultRow(array("Cell 1A", "Cell 2A", "Cell 3A"));
* // Row's class parameter set to "fooCell" (Default action)
* $grid->setResultRow(array("Cell 1B", "Cell 2B", "Cell 3B"), array("class"=>"bar"));
* // Row's class parameter set to "bar" (Overriding default action)
* $grid->setRangeLinks("[1...3]");
* // Table caption's class parameter set to "fooCaption" (Default action)
* print $grid->display();
*
* This would result in the following html:
*
* <table class="foo" border="2">
* <caption class="fooCaption" align="bottom">[1...3]</caption>
* <tr>
* <td class="fooHead" align="left" colspan="3">Sample Grid</td>
* <!-- span -->
* <!-- span -->
* </tr>
* <tr>
* <th class="fooColumns" align="center">Row 1</th>
* <th class="fooColumns" align="center">Row 2</th>
* <th class="fooColumns" align="center">Row 3</th>
* </tr>
* <tr>
* <td class="fooCell" align="left">Cell 1A</td>
* <td class="fooCell" align="left">Cell 2A</td>
* <td class="fooCell" align="left">Cell 3A</td>
* </tr>
* <tr>
* <td class="bar" align="left">Cell 1B</td>
* <td class="bar" align="left">Cell 2B</td>
* <td class="bar" align="left">Cell 3B</td>
* </tr>
* </table>
*
* NOTE!!!
* It is important to remember that ALL of this will be done automatically
* by the GridControl class (Not this HTML_GridControl utility class).
* These notes are to document HOW it is doing it and how a user of the
* GridControl class can easily override the default behavoir of the
* control.
*
* @var string
* @private
*/
var $_cssBase;
/**
* HTML_Table pointer to the row created for the header.
*
* @var int
* @private
*/
var $_rowID;
/**
* Constructor
*
* @param array $attributes (optional) Associative array or string of HTML_Common class style attributes
* @param int $tabOffset (optional) Tab indenting for the table.
*/
function GridTable($attributes = null, $tabOffset = 0)
{
$commonVersion = 1.4;
if (HTML_Common::apiVersion() < $commonVersion) {
return new PEAR_Error("HTML_Table version " . $this->apiVersion() . " requires " .
"HTML_Common version $commonVersion or greater.", 0, PEAR_ERROR_TRIGGER);
}
// Set table class base based on the attribute passed in in table creation
//
// Defaults at empty
$this->_cssBase = "";
if (isset($attributes["class"])) {
$this->cssBase($attributes["class"]);
} else {
// If CSS hasn't been defined in the attributes, set the tables
// style through the style HTML parameter
$folder = array("style" => DEFAULT_STYLE_TABLE);
$attributes = array_merge($folder, $attributes);
}
// Trigger the parent's constructor, same as java's super();
// See comments at http://www.php.net/manual/en/keyword.parent.php
$par = get_parent_class($this);
$this->$par($attributes, $tabOffset);
} // end constructor
/**
* Returns the API version
*
* @access public
* @returns double
*/
function apiVersion()
{
return 1.6;
} // end func apiVersion
/**
* Static factory method.
*
* @access public
* @static
*/
function &factory($attributes = null, $tabOffset = 0)
{
return new GridTable($attributes, $tabOffset);
} // end func factory
/**
* Adds an HTML_Table row formatted for the result's column headers and returns the row identifier.
*
* @param array $contents Must be a indexed array of valid cell contents
* @param mixed $attributes (optional) Associative array or string of table row attributes
* @returns int
* @access public
*/
function setHeader($title, $attributes = null)
{
// OVERRIDE DEFAULT STYLE ON CLASS DECLARATION
if ($this->cssBase()) {
$class = $this->cssBase() . HEAD;
$folder = array(
"class" => $class,
"align" => "left");
} else {
$folder = array(
"style" => DEFAULT_STYLE_HEAD,
"align" => "left");
}
// Fold in $folder
// Allows for individual table parameters to by overridded by caller.
$attributes = array_merge($folder, $attributes);
// Save the ID returned by this value.
// This pointer is used is used by the display method to set the
// colspan attribute for this row once all of the columns are set
// and we know how many columns there will be.
$this->_rowID = $this->addRow(array($title), $attributes);
} // end func setHeader
/**
* Adds an HTML_Table row formatted for the result's column headers and returns the row identifier.
*
* @param array $contents Must be a indexed array of valid cell contents
* @param mixed $attributes (optional) Associative array or string of table row attributes
* @returns int
* @access public
*/
function setColumns($contents, $attributes = null)
{
// OVERRIDE DEFAULT STYLE ON CLASS DECLARATION
if ($this->cssBase()) {
$class = $this->cssBase() . COLUMNS;
$folder = array(
"class" => $class,
"align" => "center");
} else {
$folder = array(
"style" => DEFAULT_STYLE_COLUMNS,
"align" => "center");
}
// Fold in $folder
// Allows for individual table parameters to by overridded by caller.
$attributes = array_merge($folder, $attributes);
return $this->addRow($contents, $attributes, "TH");
} // end func setColumns
/**
* Adds an HTML_Table row formatted for a result row and returns the row identifier.
*
* @param array $contents Must be a indexed array of valid cell contents
* @param mixed $attributes (optional) Associative array or string of table row attributes
* @returns int
* @access public
*/
function setResultRow($contents, $attributes = null)
{
// OVERRIDE DEFAULT STYLE ON CLASS DECLARATION
if ($this->cssBase()) {
$class = $this->cssBase() . CELL;
$folder = array(
"class" => $class,
"align" => "left");
} else {
$folder = array(
"style" => DEFAULT_STYLE_TD,
"align" => "left");
}
// Fold in $folder
// Allows for individual table parameters to by overridded by caller.
$attributes = array_merge($folder, $attributes);
return $this->addRow($contents, $attributes);
}
/**
* Sets the table caption for use to display the range links for the result set.
*
* By default this row is formatted at the bottom.
*
* @param string $contents
* @param mixed $attributes (optional) Associative array or string of table row attributes
* @returns int
* @access public
*/
function setRangeLinks($contents, $attributes = null)
{
// OVERRIDE DEFAULT STYLE ON CLASS DECLARATION
if ($this->cssBase()) {
$class = $this->cssBase() . CAPTION;
$folder = array(
"class" => $class,
"align" => "center",
"align" => "bottom");
} else {
$folder = array(
"style" => DEFAULT_STYLE_CAPTION,
"align" => "center",
"align" => "bottom");
}
// Fold in $folder
// Allows for individual table parameters to by overridded by caller.
$attributes = array_merge($folder, $attributes);
return $this->setCaption($contents, $attributes);
} // end func setRangeLinks
/**
* Assessor method for the base name used by default for each row's class parameter.
*
* This class method does not have to be called in order to set the base css name
* for the developer. The HTML_GridControl's constructed searches the class' attributes
* to see if class is a key, and if so sets the _cssBase field to that value.
*
* The default css name for a row can be overridden at any time with each row's
* attributes hash.
*
* @param string $t (optional) If $t is passed, it sets the _cssBase field to that value.
* @returns string
* @access public
*/
function cssBase($t = "")
{
if ($t) {
$this->_cssBase = (string) $t;
} else {
return $this->_cssBase;
}
} // end func cssBase
/**
* Returns the table structure as HTML, formatting the header to only have one cell.
*
* @access public
* @return string
*/
function display()
{
// Set the colspan for the control header.
$this->updateCellAttributes($this->_rowID, 0, array("colspan" => $this->getColCount()));
return $this->toHtml();
} // end func display
/**
* Returns a hash of the classes current fields.
*
* @return array
*/
function toHash()
{
$dumpee = array(
"_cssBase" => $this->_cssBase,
"_rowID" => $this->_rowID
);
return $dumpee;
}
/**
* Static self test method for this class. >> UNDER CONSTRUCTION <<
*
* @return Test Object
* @static
*/
function &testMe()
{
require_once "test/Debug.php";
// Debug Object
$debug = new Debug();
$tester = new Test("GridTable Test");
$gTable =& GridTable::factory();
////////////////////////////////////////////////////////////////
//////////////////// Test Results /////////////////////////
////////////////////////////////////////////////////////////////
$tester->addTestHeader("<big>controls/GridTable</big>");
$tester->addTestHeader("factory()");
// Does it nave the right class name when one uses the factory method?
$tester->testPositive(get_class($gTable) == 'gridtable');
////////////////////////////////////////////////////////////////
$tester->addTestHeader("get/set cssBase()");
// Does this parameter default to ""?
$tester->testNegative($gTable->cssBase());
// Does it return the right value when you pass it in?
$tester->testPositive($gTable->cssBase("tVal") == 'tVal');
// Does it no longer have the default value?
$tester->testNegative($gTable->cssBase("tVal") == '');
////////////////////////////////////////////////////////////////
$tester->addTestHeader("setHeader()");
$header = "Test Table";
$gtr1 = $gTable->setHeader($header);
$tester->testPositive($gtr1 == 0);
$tester->testPositive($gTable->getCellContents($gtr1, 0) == $header);
////////////////////////////////////////////////////////////////
$tester->addTestHeader("setColumns()");
////////////////////////////////////////////////////////////////
$tester->addTestHeader("setResultRow()");
////////////////////////////////////////////////////////////////
$tester->addTestHeader("setRangeLinks()");
////////////////////////////////////////////////////////////////
$tester->addTestHeader("display()");
return $tester;
} // end func testMe
} // end class GridTable
/**
* One of the primary purposes of this class is to easily get CGI variables in
* php environments that have strict configurations, such as setting
* register_globals and register_argc_argv to off in the php.ini file.
*/
class SqlGridCgi
{
function SqlGridCgi()
{
die("DOHH! SqlGridCgi is a static class.");
} // anti-constructor
function getGet($v)
{
return SqlGridCgi::_parse($v, "GET");
} // end func get
function getPost($v)
{
return SqlGridCgi::_parse($v);
} // end func post
function _parse($v, $type = "POST")
{
$h = "HTTP_" . $type . "_VARS";
$HTTP_VARS = &$GLOBALS[$h];
// is it there at all ?
if (isset($HTTP_VARS[$v])) {
$value = $HTTP_VARS[$v];
// does it have value?
if ($value) {
return $value;
} else {
// if not, return an empty string
return "";
}
} else {
// There's no there there.
// return false
return false;
}
} // end func _parse
} // end class SqlGridCgi
/**
* The core values of evil is that a value passed is either "false" in PHP terms
* or is an error object.
*/
class SqlGridTest
{
function SqlGridTest()
{
die("DOHH! SqlGridTest is a static class not meant for generating objects with.");
} // end anti-constructor
function isEvil($v)
{
if (SqlGridTest::isGood($v)) {
return false;
} else {
return true;
}
} // end isEvil
function isGood($v)
{
if ( (!$v) || (PEAR::isError($v)) ) {
return false;
} else {
return true;
}
} // end isGood
function testMe()
{
$foo = new PEAR_Error("You suck");
$test = "SqlGridTest::isGood() fails on PEAR_Error";
if (SqlGridTest::isGood($foo))
print "<h6>TEST: $test<br>Failed</h6>";
else
print "<h6>TEST: $test<br>Passed</h6>";
if (SqlGridTest::isEvil($foo))
print "<h6>TEST: $test<br>Passed</h6>";
else
print "<h6>TEST: $test<br>Failed</h6>";
} // testMe
} // end class SqlGridTest
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More Database Code Articles
More By Codewalkers
developerWorks - FREE Tools! |
CakePHP is a stable production-ready, rapid-development aid for building Web sites in PHP. This "Cook up Web sites fast with CakePHP" series shows you how to build an online product catalog using CakePHP. FREE! Go There Now!
|
|
|
|
Visit IBM developerWorks to download the latest trial version of IBM Data Studio V1.1 at no cost. IBM Data Studio is a comprehensive data management solution that helps you effectively design, develop, deploy and manage your data, databases, and database applications throughout the data management life cycle utilizing a consistent and integrated user interface. Unlike other client-side data management solutions that focus on only one aspect of the application lifecycle or database administration, Data Studio complements the Rational Software Delivery platform, providing unparalleled flexibility for a heterogeneous data server environment across platforms. FREE! Go There Now!
|
|
|
|
Visit IBM developerWorks to download a free trial of the latest release of IBM Lotus Sametime Standard V8.0. Lotus Sametime Standard V8.0 is a platform for unified communications and collaboration that combines security features with an extensible, open solution including integrated Voice over IP, geographic location awareness, mobile clients, and a robust Business Partner community offering telephony and video integration. FREE! Go There Now!
|
|
|
|
IBM Enterprise Modernization solutions help organizations evolve core IT systems towards modern architectures and technologies—reducing the burden of maintenance and freeing up resources to develop new business requirements and capabilities. With the IBM Enterprise Modernization Sandbox for System z you can evaluate IBM Enterprise Modernization solutions focused on five key areas: Assets, Architectures, Skills, Processes and Infrastructures, and Investment. Each solution is based upon real customer experiences and offers a proven path to get you started with your modernization projects. FREE! Go There Now!
|
|
|
|
Informix Dynamic Server (IDS) Express Edition offers outstanding online transaction processing (OLTP) database performance, while helping to simplify and automate many of the tasks associated with deploying databases for small business applications. IDS 11 further extends the ease of management and applications integration with the Admin API and Scheduler, high availability with Continuous Log Restore for backup server recovery in case of a primary server failure, and column level encryption to protect personal and company private data. FREE! Go There Now!
|
|
|
|
Get a free trial download of the latest version of IBM Rational Performance Tester V7.0.1, a load and performance testing solution for teams concerned about the scalability of their Web-based applications. Combining multiple ease-of-use features with granular detail, Rational Performance Tester simplifies the test-creation, load-generation and data-collection processes that help teams ensure the ability of their applications to accommodate required user loads. FREE! Go There Now!
|
|
|
|
You can now evaluate IBM Rational Asset Manager V7.0 online without installing or configuring it on your own system! Rational Asset Manager helps create, modify, govern, find, and reuse any type of development assets, including SOA and systems development assets. Rational Asset Manager helps you reduce software development costs and improve quality by facilitating the reuse of all types of software development-related assets. Visit developerWorks to learn more about this product and register to explore its capabilities online. FREE! Go There Now!
|
|
|
|
Visit IBM developerWorks to try the IBM SOA Sandbox for people. The SOA Sandbox for people provides a trial environment with the necessary tooling and components required to enable consistent human and process interaction and collaboration, showing how you can improve user experience and business productivity. FREE! Go There Now!
|
|
|
|
In this webcast, IBM Rational will discuss the importance of Web application security and will share techniques and best practices to introduce application security testing into current QA processes including: understanding common security vulnerabilities and techniques to integrate security testing with defect tracking and remediation systems in an effort to safeguard sensitive online information. FREE! Go There Now!
|
|
|
|
Viper 2 brings a great value to developer communities including SQL, XML, PHP, Ruby, .NET and Java. You probably already know that DB2 Express-C is free for developers to develop, deploy and distribute. Viper 2 provides a variety of means that help move your application from the development stage to deployment more rapidly. This webcast shows how to best utilize the latest tools available for developing DB2 applications. FREE! Go There Now!
|
|
|
|
All FREE IBM® developerWorks Tools! |