package.xml 0000664 0001750 0001750 00000024147 11710512440 013764 0 ustar clockwerx clockwerx
Structures_DataGridpear.php.netRender a data table with automatic pagination and sortingThis package provides a toolkit to generate data tables in HTML, CSV,
Excel, XML, Smarty, and other formats.
It retrieves data from a variety of data sources, including SQL, CSV,
XML, PDO, DB_DataObject, DB_Table, and others.
It can transparently page and sort the data, through optimized database
queries, by parsing/generating GET, POST requests and REST-like urls.
It is designed with modularity and extensibility in mind, using drivers
for all rendering and datasource formats.Andrew S. Nagyasnagyasnagy@webitecture.orgnoOlivier Guilyardioliviergolivier@samalyse.comyesMark Wiesemannwiesemannwiesemann@php.netyes2012-01-270.9.30.9.0betabetaNew BSD
QA release
Bug #19251 Missing 'Structures/DataGrid/Exception.php'
5.0.01.6.0PHPUnitpear.php.net1.3.2Filepear.php.net1.3.0Net_URL_Mapperpear.php.net0.9.0sqliteStructures_DataGrid_DataSource_CSVpear.php.net0.1.0Structures_DataGrid_DataSource_RSSpear.php.net0.1.0Structures_DataGrid_DataSource_XMLpear.php.net0.1.0Structures_DataGrid_DataSource_Arraypear.php.net0.1.0Structures_DataGrid_DataSource_DBpear.php.net0.1.0Structures_DataGrid_DataSource_MDB2pear.php.net0.1.0Structures_DataGrid_DataSource_DataObjectpear.php.net0.1.0Structures_DataGrid_DataSource_DBQuerypear.php.net0.1.0Structures_DataGrid_DataSource_DBTablepear.php.net0.1.0Structures_DataGrid_DataSource_PDOpear.php.net0.1.0Structures_DataGrid_Renderer_XLSpear.php.net0.1.0Structures_DataGrid_Renderer_XULpear.php.net0.1.0Structures_DataGrid_Renderer_XMLpear.php.net0.1.0Structures_DataGrid_Renderer_Smartypear.php.net0.1.0Structures_DataGrid_Renderer_Consolepear.php.net0.1.0Structures_DataGrid_Renderer_CSVpear.php.net0.1.0Structures_DataGrid_Renderer_HTMLTablepear.php.net0.1.0Structures_DataGrid_Renderer_Pagerpear.php.net0.1.0Structures_DataGrid_Renderer_HTMLSortFormpear.php.net0.1.0
Structures_DataGrid-0.9.3/Structures/DataGrid/Column.php 0000664 0001750 0001750 00000041437 11710512440 024047 0 ustar clockwerx clockwerx ,
* Olivier Guilyardi ,
* Mark Wiesemann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* CSV file id: $Id$
*
* @version $Revision$
* @package Structures_DataGrid
* @category Structures
* @license http://opensource.org/licenses/bsd-license.php New BSD License
*/
/**
* Structures_DataGrid_Column Class
*
* This class represents a single column for the DataGrid.
*
* @version $Revision$
* @author Andrew S. Nagy
* @author Olivier Guilyardi
* @author Mark Wiesemann
* @access public
* @package Structures_DataGrid
* @category Structures
*/
class Structures_DataGrid_Column
{
/**
* The unique id of the column
* @var string
*/
var $id;
/**
* The name (label) of the column
* @var string
*/
var $columnName;
/**
* The name of the field to map to
* @var string
*/
var $fieldName;
/**
* The field name to order by. Optional
* @var string
*/
var $orderBy;
/**
* The default direction to order this column by
*
* @var array
* @access private
*/
var $defaultDirection = 'ASC';
/**
* The attributes to use for the cell. Optional
* @var array
*/
var $attribs;
/**
* The value to be used if a cell is empty
* @var string
*/
var $autoFillValue;
/**
* A callback function to be called for each cell to modify the output
* @var mixed
* @access private
*/
var $formatter;
/**
* User defined parameters passed to the formatter callback function
* @var array
* @access private
*/
var $formatterArgs;
/**
* Constructor
*
* Creates default table style settings
*
* @param string $label The label of the column to be printed
* @param string $field The name of the field for the column
* to be mapped to
* @param string $orderBy The field or expression to order the
* data by
* @param array $attributes The attributes for the XML or HTML
* TD tag; form: array(name => value, ...)
* @param string $autoFillValue The value to use for the autoFill
* @param mixed $formatter Formatter callback. See setFormatter()
* @param array $formatterArgs Associative array of arguments
* passed as second argument to the
* formatter callback
* @see http://www.php.net/manual/en/language.pseudo-types.php
* @see Structures_DataGrid::addColumn()
* @see setFormatter()
* @access public
*/
function Structures_DataGrid_Column($label,
$field = null,
$orderBy = null,
$attributes = array(),
$autoFillValue = null,
$formatter = null,
$formatterArgs = array())
{
$this->id = uniqid('_');
$this->columnName = $label;
$this->fieldName = $field;
$this->orderBy = $orderBy;
$this->attribs = $attributes;
$this->autoFillValue = $autoFillValue;
if (!is_null($formatter)) {
$this->setFormatter($formatter, $formatterArgs);
}
}
/**
* Get column label
*
* The label is the text rendered into the column header.
*
* @return string
* @access public
*/
function getLabel()
{
return $this->columnName;
}
/**
* Set column label
*
* The label is the text rendered into the column header.
*
* @param string $str Column label
* @access public
*/
function setLabel($str)
{
$this->columnName = $str;
}
/**
* Get name of the field for the column to be mapped to
*
* Returns the name of the field for the column to be mapped to
*
* @return string
* @access public
*/
function getField()
{
return $this->fieldName;
}
/**
* Set name of the field for the column to be mapped to
*
* Defines the name of the field for the column to be mapped to
*
* @param string $str The name of the field for the column to
* be mapped to
* @access public
*/
function setField($str)
{
$this->fieldName = $str;
}
/**
* Get the field name to order the data by
*
* @return string field name
* @access public
*/
function getOrderBy()
{
return $this->orderBy;
}
/**
* Set the field name to order the data by
*
* @param string $str field name
* @access public
*/
function setOrderBy($str)
{
$this->orderBy = $str;
}
/**
* Return the default direction to order this column by
*
* @return string "ASC" or "DESC"
* @access public
*/
function getDefaultDirection($str)
{
return $this->defaultDirection;
}
/**
* Set the default direction to order this column by
*
* @param string $str "ASC" or "DESC"
* @access public
*/
function setDefaultDirection($str)
{
$this->defaultDirection = $str;
}
/**
* Get the column XML/HTML attributes
*
* Return the attributes applied to all cells in this column.
* This only makes sense for HTML or XML rendering
*
* @return array Attributes; form: array(name => value, ...)
* @access public
*/
function getAttributes()
{
return $this->attribs;
}
/**
* Set the column XML/HTML attributes
*
* Set the attributes to be applied to all cells in this column.
* This only makes sense for HTML or XML rendering
*
* @param array $attributes form: array(name => value, ...)
* @access public
*/
function setAttributes($attributes)
{
$this->attribs = $attributes;
}
/**
* Get auto fill value
*
* Returns the value to be printed if a cell in the column is null.
*
* @return string
* @access public
*/
function getAutoFillValue()
{
return $this->autoFillValue;
}
/**
* Set auto fill value
*
* Defines a value to be printed if a cell in the column is null.
*
* @param string $str The value to use for the autoFill
* @access public
*/
function setAutoFillValue($str)
{
$this->autoFillValue = $str;
}
/**
* Set Formatter Callback
*
* Define a formatting callback function with optional arguments for
* this column.
*
* The callback function receives the following array as its first argument:
*
* array(
* 'record' => associative array of all fields values for this record,
* 'fieldName' => the field name of this column,
* 'columnName' => the label (header) of this column,
* 'orderBy' => the field name to sort this column by,
* 'attribs' => this column's attributes,
* 'currRow' => zero-based row index,
* 'currCol' => zero-based column index,
* );
*
*
* If you pass the optional $arguments parameter to setFormatter(), the callback
* function will receive it as its second argument.
*
* @param mixed $formatter Callback PHP pseudo-type (Array or String)
* @param array $arguments Associative array of parameters passed to
* as second argument to the callback function
* @return mixed PEAR_Error on failure
* @see http://www.php.net/manual/en/language.pseudo-types.php
* @access public
*/
function setFormatter($formatter, $arguments = array())
{
$this->formatterArgs = $arguments;
if (is_array($formatter)) {
$formatter[1] = $this->_parseCallbackString($formatter[1],
$this->formatterArgs);
} else {
$formatter = $this->_parseCallbackString($formatter,
$this->formatterArgs);
}
if (is_callable ($formatter)) {
$this->formatter = $formatter;
} else {
return PEAR::raiseError('Column formatter is not a valid callback');
}
}
/**
* Choose a format preset
*
* EXPERIMENTAL: the behaviour of this method may change in future releases.
*
* This method allows to associate an "automatic" predefined formatter
* to the column, for common needs as formatting dates, numbers, ...
*
* The currently supported predefined formatters are :
* - dateFromTimestamp: format a UNIX timestamp according to the
* date()-like format string passed as second argument
* - dateFromMysql : format a MySQL DATE, DATETIME, or TIMESTAMP MySQL
* according to the date() like format string passed as second argument
* - number: format a number, according to the same optional 2nd, 3rd and
* 4th arguments that the number_format() PHP function accepts.
* - printf: format using the printf expression passed as 2nd argument.
* - printfURL: url-encode and format using the printf expression passed
* as 2nd argument
*
* @example format.php Common formats
* @param mixed $type,... Predefined formatter name, followed by
* formatter-specific parameters
* @return void
* @access public
*/
function format($type)
{
$params = func_get_args();
$this->setFormatter(array(get_class($this), '_autoFormatter'), $params);
}
/**
* Automatic formatter(s)
*
* @param array $data Datagrid and record data
* @param data $params Formatter-specific parameters
* @access private
* @static
*/
function _autoFormatter($data, $params)
{
$value = $data['record'][$data['fieldName']];
$type = $params[0];
switch ($type) {
case 'dateFromTimestamp':
$format = $params[1];
return date($format, $value);
case 'dateFromMysql':
$format = $params[1];
if (preg_match('/^([0-9]+)-([0-9]+)-([0-9]+) '.
'*([0-9]+):([0-9]+):([0-9]+)$/', $value, $r)) {
$time = mktime($r[4], $r[5], $r[6], $r[2], $r[3], $r[1]);
return date($format, $time);
} elseif (preg_match('/^([0-9]+)-([0-9]+)-([0-9]+)$/', $value, $r)){
$time = mktime(0, 0, 0, $r[2], $r[3], $r[1]);
return date($format, $time);
} else {
return "Unrecognized date format";
}
case 'number':
switch (count($params)) {
case 4:
return number_format($value, $params[1],
$params[2], $params[3]);
case 3:
return "Wrong parameter count for the 'number' format";
case 2:
return number_format($value, $params[1]);
default:
return number_format($value);
}
case 'printfURL':
$value = urlencode($value);
case 'printf':
return sprintf($params[1], $value);
}
}
/**
* Parse a callback function string
*
* This method parses a string of the type "myFunction($param1=foo,...)",
* return the isolated function name ("myFunction") and fills $paramList
* with the extracted parameters (array('param1' => foo, ...))
*
* @param string $callback Callback function string
* @param array $paramList Reference to an array of parameters
* @return string Function name
* @access private
*/
function _parseCallbackString($callback, $paramList)
{
if ($size = strpos($callback, '(')) {
$orig_callback = $callback;
// Retrieve the name of the function to call
$callback = substr($callback, 0, $size);
if (strstr($callback, '->')) {
$callback = explode('->', $callback);
} elseif (strstr($callback, '::')) {
$callback = explode('::', $callback);
}
// Build the list of parameters
$length = strlen($orig_callback) - $size - 2;
$parameters = substr($orig_callback, $size + 1, $length);
$parameters = ($parameters === '') ? array() : explode(',', $parameters);
// Process the parameters
foreach($parameters as $param) {
if ($param != '') {
$param = str_replace('$', '', $param);
if (strpos($param, '=') != false) {
$vars = explode('=', $param);
$paramList[trim($vars[0])] = trim($vars[1]);
} else {
$paramList[$param] = $$param;
}
}
}
}
return $callback;
}
/**
* Formatter
*
* This method is not meant to be called by user-space code.
*
* Calls a predefined function to develop custom output for the column. The
* defined function can accept parameters so that each cell in the column
* can be unique based on the record. The function will also automatically
* receive the record array as a parameter. All parameters passed into the
* function will be in one array.
*
* @access public
*/
function formatter($record, $row, $col)
{
// Define the parameter list
$paramList = array();
$paramList['record'] = $record;
$paramList['fieldName'] = $this->fieldName;
$paramList['columnName'] = $this->columnName;
$paramList['orderBy'] = $this->orderBy;
$paramList['attribs'] = $this->attribs;
$paramList['currRow'] = $row;
$paramList['currCol'] = $col;
// Call the formatter
if (isset($GLOBALS['_STRUCTURES_DATAGRID']['column_formatter_BC'])) {
$paramList = array_merge($this->formatterArgs, $paramList);
$formatted = call_user_func($this->formatter, $paramList);
} else {
if ($this->formatterArgs) {
$formatted = call_user_func($this->formatter, $paramList,
$this->formatterArgs);
} else {
$formatted = call_user_func($this->formatter, $paramList);
}
}
return $formatted;
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4: */
?>
Structures_DataGrid-0.9.3/Structures/DataGrid/DataSource.php 0000664 0001750 0001750 00000063656 11710512440 024653 0 ustar clockwerx clockwerx ,
* Olivier Guilyardi ,
* Mark Wiesemann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* CVS file id: $Id$
*
* @version $Revision$
* @package Structures_DataGrid
* @category Structures
* @license http://opensource.org/licenses/bsd-license.php New BSD License
*/
require_once 'Structures/DataGrid/Exception.php';
/**
* Base abstract class for DataSource drivers
*
* SUPPORTED OPTIONS:
*
* - fields: (array) Which data fields to fetch from the datasource.
* An empty array means: all fields.
* Form: array(field1, field2, ...)
* - primaryKey: (array) Name(s), or numerical index(es) of the
* field(s) which contain a unique record
* identifier (only use several fields in case
* of a multiple-fields primary key)
* - generate_columns: (bool) Generate Structures_DataGrid_Column objects
* with labels. See the 'labels' option.
* DEPRECATED:
* use Structures_DataGrid::generateColumns() instead
* - labels: (array) Data field to column label mapping. Only used
* when 'generate_columns' is true.
* Form: array(field => label, ...)
* DEPRECATED:
* use Structures_DataGrid::generateColumns() instead
*
* @author Olivier Guilyardi
* @author Andrew Nagy
* @author Mark Wiesemann
* @package Structures_DataGrid
* @category Structures
* @version $Revision$
*/
class Structures_DataGrid_DataSource
{
/**
* Common and driver-specific options
*
* @var array
* @access protected
* @see Structures_DataGrid_DataSource::_setOption()
* @see Structures_DataGrid_DataSource::addDefaultOptions()
*/
var $_options = array();
/**
* Special driver features
*
* @var array
* @access protected
*/
var $_features = array();
/**
* Constructor
*
*/
function Structures_DataGrid_DataSource()
{
$this->_options = array('generate_columns' => false,
'labels' => array(),
'fields' => array(),
'primaryKey' => null,
);
$this->_features = array(
'multiSort' => false, // Multiple field sorting
'writeMode' => false, // insert, update and delete records
);
}
/**
* Adds some default options.
*
* This method is meant to be called by drivers. It allows adding some
* default options.
*
* @access protected
* @param array $options An associative array of the form:
* array(optionName => optionValue, ...)
* @return void
* @see Structures_DataGrid_DataSource::_setOption
*/
function _addDefaultOptions($options)
{
$this->_options = array_merge($this->_options, $options);
}
/**
* Add special driver features
*
* This method is meant to be called by drivers. It allows specifying
* the special features that are supported by the current driver.
*
* @access protected
* @param array $features An associative array of the form:
* array(feature => true|false, ...)
* @return void
*/
function _setFeatures($features)
{
$this->_features = array_merge($this->_features, $features);
}
/**
* Set options
*
* @param mixed $options An associative array of the form:
* array("option_name" => "option_value",...)
* @access protected
*/
function setOptions($options)
{
$this->_options = array_merge($this->_options, $options);
}
/**
* Set a single option
*
* @param string $name Option name
* @param mixed $value Option value
* @access public
*/
function setOption($name, $value)
{
$this->_options[$name] = $value;
}
/**
* Generate columns if options are properly set
*
* Note: must be called after fetch()
*
* @access public
* @return array Array of Column objects. Empty array if irrelevant.
* @deprecated This method relates to the deprecated "generate_columns" option.
*/
function getColumns()
{
$columns = array();
if ($this->_options['generate_columns']
and $fieldList = $this->_options['fields']) {
include_once 'Structures/DataGrid/Column.php';
foreach ($fieldList as $field) {
$label = strtr($field, $this->_options['labels']);
$col = new Structures_DataGrid_Column($label, $field, $field);
$columns[] = $col;
}
}
return $columns;
}
// Begin driver method prototypes DocBook template
/**#@+
*
* This method is public, but please note that it is not intended to be
* called by user-space code. It is meant to be called by the main
* Structures_DataGrid class.
*
* It is an abstract method, part of the DataGrid Datasource driver
* interface, and must/may be overloaded by drivers.
*/
/**
* Fetching method prototype
*
* When overloaded this method must return an array of records.
* Each record can be either an associative array of field name/value
* pairs, or an object carrying fields as properties.
*
* This method must return a PEAR_Error object on failure.
*
* @abstract
* @param integer $offset Limit offset (starting from 0)
* @param integer $len Limit length
* @return object PEAR_Error with message
* "No data source driver loaded"
* @access public
*/
function fetch($offset = 0, $len = null)
{
return PEAR::raiseError("No data source driver loaded");
}
/**
* Counting method prototype
*
* Note: must be called before fetch()
*
* When overloaded, this method must return the total number or records
* or a PEAR_Error object on failure
*
* @abstract
* @return object PEAR_Error with message
* "No data source driver loaded"
* @access public
*/
function count()
{
return PEAR::raiseError("No data source driver loaded");
}
/**
* Sorting method prototype
*
* When overloaded this method must return true on success or a PEAR_Error
* object on failure.
*
* Note: must be called before fetch()
*
* @abstract
* @param string $sortSpec If the driver supports the "multiSort"
* feature this can be either a single field
* (string), or a sort specification array of
* the form: array(field => direction, ...)
* If "multiSort" is not supported, then this
* can only be a string.
* @param string $sortDir Sort direction: 'ASC' or 'DESC'
* @return object PEAR_Error with message
* "No data source driver loaded"
* @access public
*/
function sort($sortSpec, $sortDir = null)
{
return PEAR::raiseError("No data source driver loaded");
}
/**
* Datasource binding method prototype
*
* When overloaded this method must return true on success or a PEAR_Error
* object on failure.
*
* @abstract
* @param mixed $container The datasource container
* @param array $options Binding options
* @return object PEAR_Error with message
* "No data source driver loaded"
* @access public
*/
function bind($container, $options = array())
{
return PEAR::raiseError("No data source driver loaded");
}
/**
* Record insertion method prototype
*
* Drivers that support the "writeMode" feature must implement this method.
*
* When overloaded this method must return true on success or a PEAR_Error
* object on failure.
*
* @abstract
* @param array $data Associative array of the form:
* array(field => value, ..)
* @return object PEAR_Error with message
* "No data source driver loaded or write mode not
* supported by the current driver"
* @access public
*/
function insert($data)
{
return PEAR::raiseError("No data source driver loaded or write mode not".
"supported by the current driver");
}
/**
* Return the primary key specification
*
* This method always returns an array containing:
* - either one field name or index in case of a single-field key
* - or several field names or indexes in case of a multiple-fields key
*
* Drivers that support the "writeMode" feature should overload this method
* if the key can be detected. However, the detection must not override the
* "primaryKey" option.
*
* @return array Field(s) name(s) or numerical index(es)
* @access protected
*/
function getPrimaryKey()
{
return $this->_options['primaryKey'];
}
/**
* Record updating method prototype
*
* Drivers that support the "writeMode" feature must implement this method.
*
* When overloaded this method must return true on success or a PEAR_Error
* object on failure.
*
* @abstract
* @param array $key Unique record identifier
* @param array $data Associative array of the form:
* array(field => value, ..)
* @return object PEAR_Error with message
* "No data source driver loaded or write mode
* not supported by the current driver"
* @access public
*/
function update($key, $data)
{
return PEAR::raiseError("No data source driver loaded or write mode not".
"supported by the current driver");
}
/**
* Record deletion method prototype
*
* Drivers that support the "writeMode" feature must implement this method.
*
* When overloaded this method must return true on success or a PEAR_Error
* object on failure.
*
* @abstract
* @param array $key Unique record identifier
* @return object PEAR_Error with message
* "No data source driver loaded or write mode
* not supported by the current driver"
* @access public
*/
function delete($key)
{
return PEAR::raiseError("No data source driver loaded or write mode not".
"supported by the current driver");
}
/**
* Resources cleanup method prototype
*
* This is where drivers should close sql connections, files, etc...
* if needed.
*
* @abstract
* @return void
* @access public
*/
function free()
{
}
/**#@-*/
// End DocBook template
/**
* List special driver features
*
* @return array Of the form: array(feature => true|false, etc...)
* @access public
*/
function getFeatures()
{
return $this->_features;
}
/**
* Tell if the driver as a specific feature
*
* @param string $name Feature name
* @return bool
* @access public
*/
function hasFeature($name)
{
return $this->_features[$name];
}
/**
* Dump the data as returned by fetch().
*
* This method is meant for debugging purposes. It returns what fetch()
* would return to its DataGrid host as a nicely formatted console-style
* table.
*
* @param integer $offset Limit offset (starting from 0)
* @param integer $len Limit length
* @param string $sortField Field to sort by
* @param string $sortDir Sort direction: 'ASC' or 'DESC'
* @return string The table string, ready to be printed
* @uses Structures_DataGrid_DataSource::fetch()
* @access public
*/
function dump($offset=0, $len=null, $sortField=null, $sortDir='ASC')
{
$records = $this->fetch($offset, $len, $sortField, $sortDir);
$columns = $this->getColumns();
if (!$columns and !$records) {
return "\n";
}
include_once 'Console/Table.php';
$table = new Console_Table();
$headers = array();
if ($columns) {
foreach ($columns as $col) {
$headers[] = is_null($col->fieldName)
? $col->columnName
: "{$col->columnName} ({$col->fieldName})";
}
} else {
$headers = array_keys($records[0]);
}
$table->setHeaders($headers);
foreach ($records as $rec) {
$table->addRow($rec);
}
return $table->getTable();
}
}
/**
* Base abstract class for SQL query based DataSource drivers
*
* SUPPORTED OPTIONS:
*
* - db_options: (array) Options for the created database object. This option
* is only used when the 'dsn' option is given.
* - count_query: (string) Query that calculates the number of rows. See below
* for more information about when such a count query
* is needed.
*
* @author Olivier Guilyardi
* @author Mark Wiesemann
* @package Structures_DataGrid
* @category Structures
* @version $Revision$
*/
class Structures_DataGrid_DataSource_SQLQuery
extends Structures_DataGrid_DataSource
{
/**
* SQL query
* @var string
* @access protected
*/
var $_query;
/**
* Fields/directions to sort the data by
* @var array
* @access protected
*/
var $_sortSpec;
/**
* Instantiated database object
* @var object
* @access protected
*/
var $_handle;
/**
* Total number of rows
*
* This property caches the result of count() to avoid running the same
* database query multiple times.
*
* @var int
* @access private
*/
var $_rowNum = null;
/**
* Constructor
*
*/
public function __construct()
{
parent::Structures_DataGrid_DataSource();
$this->_addDefaultOptions(array('dbc' => null,
'dsn' => null,
'db_options' => array(),
'count_query' => ''));
$this->_setFeatures(array('multiSort' => true));
}
/**
* Bind
*
* @param string $query The query string
* @param mixed $options array('dbc' => [connection object])
* or
* array('dsn' => [dsn string])
* @access public
* @return mixed True on success, PEAR_Error on failure
*/
function bind($query, $options = array())
{
if ($options) {
$this->setOptions($options);
}
if (isset($this->_options['dbc']) &&
$this->_isConnection($this->_options['dbc'])) {
$this->_handle = $this->_options['dbc'];
} elseif (isset($this->_options['dsn'])) {
$dbOptions = array();
if (array_key_exists('db_options', $options)) {
$dbOptions = $options['db_options'];
}
$this->_handle = $this->_connect();
if (PEAR::isError($this->_handle)) {
throw new Structures_DataGrid_Exception(
'Could not create connection: ' .
$this->_handle->getMessage() . ', ' .
$this->_handle->getUserInfo()
);
}
} else {
return PEAR::raiseError('No Database object or dsn string specified');
}
if (is_string($query)) {
$this->_query = $query;
return true;
} else {
return PEAR::raiseError('Query parameter must be a string');
}
}
/**
* Fetch
*
* @param integer $offset Offset (starting from 0)
* @param integer $limit Limit
* @access public
* @return mixed The 2D Array of the records on success,
* PEAR_Error on failure
*/
function fetch($offset = 0, $limit = null)
{
if (!empty($this->_sortSpec)) {
foreach ($this->_sortSpec as $field => $direction) {
$fields = preg_split('#\.#', $field);
$fields = array_map(array($this, '_quoteIdentifier'), $fields);
$sortArray[] = join('.', $fields) . ' ' . $direction;
}
$sortString = join(', ', $sortArray);
} else {
$sortString = '';
}
$query = $this->_query;
// drop LIMIT statement
$query = preg_replace('#\sLIMIT\s.*$#isD', ' ', $query);
// if we have a sort string, we need to add it to the query string
if ($sortString != '') {
$appendOrderBy = false;
// search for the last ORDER BY statement
$orderByPos = strripos($query, 'ORDER BY');
// does another (sub)query or from clause follow after this ORDER BY statement?
if ( $orderByPos !== false
&& preg_match('/[ \t\n]FROM[ \t\n]/i', substr($query, $orderByPos))
) {
// yes => new ORDER BY statement needs to be appended
$appendOrderBy = true;
}
// if no ORDER BY statement exists, a new one needs to be appended
if ($orderByPos === false) {
$appendOrderBy = true;
}
if ($appendOrderBy === true) {
$query .= ' ORDER BY ' . $sortString;
} else {
$query .= ', ' . $sortString;
}
}
//FIXME: What about SQL injection ?
$recordSet = $this->_getRecords($query, $limit, $offset);
if (PEAR::isError($recordSet)) {
return $recordSet;
}
// Determine fields to render
if (!$this->_options['fields'] && count($recordSet)) {
$this->setOptions(array('fields' => array_keys($recordSet[0])));
}
return $recordSet;
}
/**
* Count
*
* @access public
* @return mixed The number or records (int),
* PEAR_Error on failure
*/
function count()
{
// do we already have the cached number of records? (if yes, return it)
if (!is_null($this->_rowNum)) {
return $this->_rowNum;
}
// try to fetch the number of records
if ($this->_options['count_query'] != '') {
// complex queries might require special queries to get the
// right row count
$count = $this->_getOne($this->_options['count_query']);
// $count has an integer value with number of rows or is a
// PEAR_Error instance on failure
}
elseif (preg_match('#GROUP\s+BY#is', $this->_query) === 1 ||
preg_match('#SELECT.+SELECT#is', $this->_query) === 1 ||
preg_match('#\sUNION\s#is', $this->_query) === 1 ||
preg_match('#SELECT.+DISTINCT.+FROM#is', $this->_query) === 1
) {
// GROUP BY, DISTINCT, UNION and subqueries are special cases
// ==> use the normal query and then numRows()
$count = $this->_getRecordsNum($this->_query);
if (PEAR::isError($count)) {
return $count;
}
} else {
// don't query the whole table, just get the number of rows
$query = preg_replace('#SELECT\s.+\sFROM#is',
'SELECT COUNT(*) FROM',
$this->_query);
$query = preg_replace(
'#ORDER\s+BY\s.+sc#',
'',
$query
);
$count = $this->_getOne($query);
// $count has an integer value with number of rows or is a
// PEAR_Error instance on failure
}
// if we've got a number of records, save it to avoid running the same
// query multiple times
if (!PEAR::isError($count)) {
$this->_rowNum = $count;
}
return $count;
}
/**
* Disconnect from the database, if needed
*
* @abstract
* @return void
* @access public
*/
function free()
{
if ($this->_handle && is_null($this->_options['dbc'])) {
$this->_disconnect();
unset($this->_handle);
}
}
/**
* This can only be called prior to the fetch method.
*
* @access public
* @param mixed $sortSpec A single field (string) to sort by, or a
* sort specification array of the form:
* array(field => direction, ...)
* @param string $sortDir Sort direction: 'ASC' or 'DESC'
* This is ignored if $sortDesc is an array
*/
function sort($sortSpec, $sortDir = 'ASC')
{
if (is_array($sortSpec)) {
$this->_sortSpec = $sortSpec;
} else {
$this->_sortSpec[$sortSpec] = $sortDir;
}
}
}
/**
* Replace strripos()
*
* @category PHP
* @package PHP_Compat
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
* @copyright 2004-2007 Aidan Lister , Arpad Ray
* @link http://php.net/function.strripos
* @author Aidan Lister
* @version $Revision$
* @since PHP 5
* @require PHP 4.0.0 (user_error)
*/
function structures_datagrid_strripos($haystack, $needle, $offset = null)
{
// Sanity check
if (!is_scalar($haystack)) {
user_error('strripos() expects parameter 1 to be scalar, ' .
gettype($haystack) . ' given', E_USER_WARNING);
return false;
}
if (!is_scalar($needle)) {
user_error('strripos() expects parameter 2 to be scalar, ' .
gettype($needle) . ' given', E_USER_WARNING);
return false;
}
if (!is_int($offset) && !is_bool($offset) && !is_null($offset)) {
user_error('strripos() expects parameter 3 to be long, ' .
gettype($offset) . ' given', E_USER_WARNING);
return false;
}
// Initialise variables
$needle = strtolower($needle);
$haystack = strtolower($haystack);
$needle_fc = $needle{0};
$needle_len = strlen($needle);
$haystack_len = strlen($haystack);
$offset = (int) $offset;
$leftlimit = ($offset >= 0) ? $offset : 0;
$p = ($offset >= 0) ?
$haystack_len :
$haystack_len + $offset + 1;
// Reverse iterate haystack
while (--$p >= $leftlimit) {
if ($needle_fc === $haystack{$p} &&
substr($haystack, $p, $needle_len) === $needle) {
return $p;
}
}
return false;
}
if (!function_exists('strripos')) {
function strripos($haystack, $needle, $offset = null)
{
return structures_datagrid_strripos($haystack, $needle, $offset);
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4: */
?>
Structures_DataGrid-0.9.3/Structures/DataGrid/Renderer.php 0000664 0001750 0001750 00000121202 11710512440 024345 0 ustar clockwerx clockwerx ,
* Olivier Guilyardi ,
* Mark Wiesemann
* Sascha Grossenbacher
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* CSV file id: $Id$
*
* @version $Revision$
* @package Structures_DataGrid
* @category Structures
* @license http://opensource.org/licenses/bsd-license.php New BSD License
*/
/**
* Base class of all Renderer drivers
*
* SUPPORTED OPTIONS:
*
* - buildHeader: (bool) Whether to build the header.
* - buildFooter: (bool) Whether to build the footer.
* - fillWithEmptyRows: (bool) Ensures that all pages have the same number of
* rows.
* - numberAlign: (bool) Whether to right-align numeric values.
* - defaultCellValue: (string) What value to put by default into empty cells.
* - defaultColumnValues: (array) Per-column default cell value. This is an array
* of the form: array(fieldName => value, ...).
* - hideColumnLinks: (array) By default sorting links are enabled on all
* columns. With this option it is possible to
* disable sorting links on specific columns. This
* is an array of the form: array(fieldName, ...).
* This option only affects drivers that support
* sorting.
* - encoding: (string) The content encoding. If the mbstring extension
* is present the default value is set from
* mb_internal_encoding(), otherwise it is ISO-8859-1.
* - extraVars: (array) Variables to be added to the generated HTTP
* queries.
* - excludeVars: (array) Variables to be removed from the generated
* HTTP queries.
* - columnAttributes: (array) Column cells attributes. This is an array of
* the form:
* array(fieldName => array(attribute => value, ...) ...)
* This option is only used by XML/HTML based
* drivers.
* - onMove: (string) Name of a Javascript function to call on
* onclick/onsubmit events when the user is either paging
* or sorting the data. This function
* receives a single object argument of the
* form: { page: , sort: [{field: ,
* direction: }, ...],
* data: }. Remark: setting this
* option doesn't remove the href attribute,
* you should return false from your handler
* function to void it (eg: for AJAX, etc..).
* - onMoveData: (string) User data passed in the "data" member of the
* object argument passed to onMove. No JSON
* serialization is performed, this is assigned
* as a raw string to the "data" attribute.
* It's up to you to add quotes, slashes, etc...
*
* --- DRIVER INTERFACE ---
*
* Methods (none required):
* - Constructor
* - setContainer()
* - getContainer()
* - init()
* - defaultCellFormatter()
* - buildHeader()
* - buildBody()
* - buildRow()
* - buildEmptyRow()
* - buildFooter()
* - finalize()
* - flatten()
* - render()
* - getPaging() (deprecated)
*
* Properties (all read-only):
* - $_columns
* - $_columnsNum
* - $_currentSort
* - $_firstRecord
* - $_lastRecord
* - $_multiSort
* - $_options
* - $_page
* - $_pageLimit
* - $_pagesNum
* - $_records
* - $_recordsNum
* - $_requestPrefix
* - $_sortableFields
* - $_totalRecordsNum
*
* Options that drivers may handle:
* - encoding
* - fillWithEmptyRows
* - numberAlign
* - extraVars
* - excludeVars
*
* @version $Revision$
* @author Olivier Guilyardi
* @author Mark Wiesemann
* @author Sascha Grossenbacher
* @access public
* @package Structures_DataGrid
* @category Structures
* @abstract
*/
class Structures_DataGrid_Renderer
{
/**
* Columns' fields names and labels
*
* Drivers can read the content of this property but must not change it.
*
* @var array Structure:
* array( => array(field => ,
* label=>