phpdevshell team mailing list archive
-
phpdevshell team
-
Mailing list archive
-
Message #01263
[Merge] lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk into lp:phpdevshell
ignatia has proposed merging lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk into lp:phpdevshell.
Requested reviews:
TitanKing (titan-phpdevshell)
For more details, see:
https://code.launchpad.net/~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk/+merge/163637
--
https://code.launchpad.net/~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk/+merge/163637
Your team PHPDevShell is subscribed to branch lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk.
=== added directory 'TablesAndFilters'
=== added directory 'TablesAndFilters/config'
=== added file 'TablesAndFilters/config/plugin.config.xml'
--- TablesAndFilters/config/plugin.config.xml 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/config/plugin.config.xml 2013-05-14 05:06:25 +0000
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<!-- Please see http://phpdevshell.org for documentation on plugin config xml files. -->
+<config type="plugin">
+
+ <!-- Use a proper plugin name without using special characters. -->
+ <name>TablesAndFilters</name>
+
+ <!-- Human readable version number of your plugin. -->
+ <version>3.0</version>
+
+ <!-- a Short description of your plugin. -->
+ <description>This plugin provides easy to use tables based on query results.</description>
+
+ <!-- If the plugin/script is modification by you, place the original authors names here. -->
+ <founder>Greg Reitter</founder>
+
+ <!-- Name of the developer for this plugin. -->
+ <author>Greg Reitter</author>
+
+ <!-- Email address of the developer for this plugin. -->
+ <email>greg@xxxxxxxxxxxxxxx</email>
+
+ <!-- Plugin developers web address. -->
+ <homepage>http://www.phpdevshell.org</homepage>
+
+ <!-- Date the plugin was developed, modified etc, this is up to you. -->
+ <date>July 2010</date>
+
+ <!-- Copyright notice you would like to amend to your plugin. -->
+ <copyright>Copyright 2010 PHPDevShell.org All rights reserved.</copyright>
+
+ <!-- License this plugin is released under. -->
+ <license>http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU/LGPL</license>
+ <!-- Code Version XML URL check. -->
+ <!-- Version (current) below is used to check for new releases and has little to do with database version. -->
+ <versionurl current="3000">http://version.phpdevshell.org/TablesAndFilters.xml</versionurl>
+
+ <!-- Detailed information and help for this plugin. -->
+ <info>
+ <![CDATA[
+ <p>
+ This plugin provides easy to use tables based on query results.
+ </p>
+ ]]>
+ </info>
+ <!-- Version here represents the database version that should be install. -->
+ <!-- If your database version needs no update, this number can stay the same. -->
+ <!-- Upgrades further down will only be executed up to this number. -->
+ <!-- This is the current database version that will be installed. -->
+ <!-- Below is a series of example upgrade procedures. -->
+ <install version="3000">
+ <!--
+ [contains][All query, menu, hooks, settings installation tags.]
+ [param][version][int][mandatory][The latest database version in numbers only.]
+ [note][This is how the plugin manager will know to what version upgrade scripts should be executed.]
+ [note][Always keep install maintained to the latest menu, query, hooks and setting versions.]
+ -->
+ <menus>
+ <!--
+ [contains][All types of menu items that needs to be installed.]
+ [note][Tags inside menus can be nested and repeated.]
+ -->
+ <menu name="testTable" type="1" link="scripts/tableTest.php" hide="0" rank="last" newwindow="" plugin="TablesAndFilters" >
+ <!--
+ [contains][Menu items can be contained in itself, this will create a menu tree.]
+ [param][name][string][not-mandatory][The name of the menu item, if empty the pluginName.menu.lang.php will be used.]
+ [param][type][int][not-mandatory][There are 8 menu types, 1 is the default if left empty.]
+ [1][Plugin script] normal plugin menu item in your plugin folder.
+ [2][Link existing menu] item while staying in its own menu group when clicked.
+ [3][Link existing menu] item while jumping to original scripts menu group when clicked.
+ [4][External file] Include external PHP web applications into PHPDevShell.
+ [5][HTTP URL] Normal url to outside web.
+ [6][Empty Place Holder] This item will only serve as a unclickable menu place holder.
+ [7][iFrame] Link url to both external url or onsite url.
+ [8][Cronjob Menu Type] The same as a plugin script but is set as cronjob.
+ [param][link][string][mandatory][The url, script location or symlink holder will be entered here depending on type.]
+ [param][hide][int][not-mandatory][There are 4 hide types, 0 is the default if left empty.]
+ [0] Do not hide menu item.
+ [1] Hide menu item from both Menu System and Control Panel.
+ [2] Hide menu item from Control Panel only.
+ [3] Hide menu item from Menu System only.
+ [4] Hide menu only when inactive.
+ [param][rank][string][not-mandatory][If you want to ensure ranking positions, will auto rank if left empty.]
+ [int] Can be ranked with integer.
+ [last] Will be ranked last in a menu group.
+ [first] Will be ranked first in a menu group.
+ [param][newwindow][int][not-mandatory][To make item open in new window set to 1, will not open in new if left empty.]
+ [param][plugin][string][not-mandatory][Plugin name, use to install menu item to a different plugins menu structure.]
+ [param][alias][string][not-mandatory][When switching on friendly urls in the settings and renaming rename.htaccess in the root, sef url will use this alias.]
+ [param][parentlink][string][not-mandatory][Use with [param][plugin] or without to install in different structure.]
+ [param][symlink][string][not-mandatory][Url or location with [param][plugin] or without to link to another menu item duplicating its use.]
+ [note][Symlink is mandatory for menu types 1,2,6]
+ [param][template][string][not-mandatory][Set template to use with plugin, if template is unavailable it will be installed.]
+ [param][template][string][not-mandatory][Set the height of an iframe menu type.]
+ [note][Height is mandatory for menu types 7]
+ [param][layout][string][not-mandatory][Set a custom template.tpl location for a certain script.]
+ [param][noautopermission][int][not-mandatory][Set to 1 to not add the installer of the plugin to permit menu item access.]
+ -->
+ </menu>
+ </menus>
+ <classes>
+ <class name="TaF_table" alias="TaF_table" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_html_table@TaF_table" alias="TaF_table" plugin="TablesAndFilters" rank="last" />
+
+ <class name="TaF_filteredQuery" alias="TaF_filteredQuery" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_html_filteredQuery@TaF_filteredQuery" alias="TaF_html_filteredQuery" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_html_filteredTable@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_html_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_list_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_radio_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+ <class name="TaF_select_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
+
+ </classes>
+ </install>
+</config>
=== added directory 'TablesAndFilters/controllers'
=== added file 'TablesAndFilters/controllers/index.php'
--- TablesAndFilters/controllers/index.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/controllers/index.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,16 @@
+<?php
+/**
+ * PHPDevShell is a RAD Framework aimed at developing administrative applications.
+ *
+ * @package PHPDevShell
+ * @link http://www.phpdevshell.org
+ * @copyright Copyright (C) 2007 Jason Schoeman, All rights reserved.
+ * @license GNU/LGPL, see readme/licensed_under_lgpl or http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+ * @author Jason Schoeman, Contact: titan [at] phpdevshell [dot] org.
+ *
+ * Copyright notice: See readme/notice
+ * By using PHPDevShell you agree to notice and license, if you dont agree to this notice/license you are not allowed to use PHPDevShell.
+ */
+// Directory listing not allowed.
+exit('Access Denied!');
+?>
\ No newline at end of file
=== added directory 'TablesAndFilters/includes'
=== added file 'TablesAndFilters/includes/TaF_excerpt.class.php'
--- TablesAndFilters/includes/TaF_excerpt.class.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/includes/TaF_excerpt.class.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,32 @@
+<?php
+
+
+
+ class TaF_excerpt extends PHPDS_dependant
+ {
+ protected $data = array();
+ protected $strip = true;
+
+
+ public function addArray(array $query_result)
+ {
+ //$strip = empty($options['strip']) ? $this->strip : true;
+ foreach($query_result as $key => $value) {
+ $this->data[$key] = $this->strip ? true : $value;
+ }
+ }
+
+ public function addResult($query_name)
+ {
+ $params = func_get_args();
+ array_shift($params); // first parameter of this function is $query_name
+ $query = $this->db->makeQuery($query_name);
+ $result = $query->invoke($params);
+ if (is_array($result)) return $this->addArray($result); else return false;
+ }
+
+ public function dump()
+ {
+ print_r($this->data);
+ }
+ }
\ No newline at end of file
=== added file 'TablesAndFilters/includes/TaF_filteredQuery.class.php'
--- TablesAndFilters/includes/TaF_filteredQuery.class.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/includes/TaF_filteredQuery.class.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,398 @@
+<?php
+
+
+
+ /**
+ * FILTERED QUERIES AND TABLE - EXPERIMENTAL
+ *
+ * The basic idea is to take the winning couple PHPDS_query + PHPDS_table and add multilayers of user-provided constraints (ie filters) to it
+ *
+ * @author greg completly stolen ideas from Jason
+ *
+ */
+
+ class TaF_queryFilter extends PHPDS_dependant
+ {
+ protected $table; // TaF_html_filteredTable
+ protected $sql = ''; // a snipet in include into the WHERE clause
+
+ protected $field = ''; // filters are usualy (but not always) in the form: "field operator value" (ie. "age > 18")
+ protected $value = '';
+ protected $operator = '=';
+
+ public function __construct(TaF_html_filteredTable $table, TaF_filteredQuery $dependance)
+ {
+ parent::__construct($dependance); // our dependancy is the query
+ $this->table = $table;
+
+ $this->init();
+ }
+
+ /**
+ * Give the filter a chance to alter the given query to do its job
+ *
+ * @param PHPDS_query $query
+ * @param unknown_type $mode
+ * @return unknown_type
+ */
+ public function alterQuery(PHPDS_query $query, $mode)
+ {
+ $sql = $this->sql();
+ if ($sql) $query->addWhere($this->sql, $mode);
+ return true;
+ }
+
+ /**
+ * return a piece of sql to be added to the WHERE clause
+ *
+ * @param unknown_type $sql
+ * @return unknown_type
+ */
+ public function sql($sql = null)
+ {
+ if (!empty($sql)) $this->sql = $sql;
+ if (empty($this->sql) && !empty($this->field) && !empty($this->value)) $this->sql = $this->field.' '.$this->operator.' '.$this->value;
+ return $this->sql;
+ }
+
+ public function init()
+ {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Add an html presentation layer to a filter
+ *
+ * @author greg
+ *
+ */
+ class TaF_html_queryFilter extends TaF_queryFilter
+ {
+ protected $id = '';
+ protected $label = '';
+
+ public function __construct(TaF_html_filteredTable $table, TaF_filteredQuery $dependance)
+ {
+ if (empty($this->id)) $this->id = $table->id().'_'.get_class($this);
+ parent::__construct($table, $dependance);
+ }
+
+ public function label($label = null)
+ {
+ if (!empty($label)) $this->label = $label;
+ return $this->label;
+ }
+
+ public function id()
+ {
+ return $this->id;
+ }
+
+ /**
+ * This should ouput some html to be added before the table
+ *
+ * @return unknown_type
+ */
+ public function toHTML()
+ {
+ return '<p>'.$this->sql.'</p>';
+ }
+
+ /**
+ * Support for dynamic reload: bind the javascript function in a way you want it to be called for reloading the table
+ *
+ * @return javascript code to add inside a <script> clause
+ */
+ public function toJSbind()
+ {
+ return '';
+ }
+
+ /**
+ *
+ * This should return a pair key=value to add to the request to ensure the filtering
+ *
+ * @return string in the form " key=value " suitable for html request (such as GET or POST)
+ */
+ public function toJSdata()
+ {
+ return '';
+ }
+ }
+
+
+
+
+
+ /**
+ * A filter based on a list of key=>value pairs, possibly from a secondary query
+ *
+ * @author greg
+ *
+ */
+ class TaF_list_queryFilter extends TaF_html_queryFilter
+ {
+ protected $list = array();
+ protected $listQuery;
+
+ public function init ()
+ {
+ if (!empty($this->listQuery)) {
+ $dep = array_pop(func_get_args());
+
+ $this->list = $this->buildList();
+ }
+
+ //if ($this->select($this->select) != $this->select)
+ $select = isset($_POST[$this->id()]) ? $_POST[$this->id()] : $this->defValue();
+ // $this->select(VeM_GetFromRequest($this->id, $this->defValue()));
+ $this->value($select);
+ //TODO: get parameter is a nicer way
+ }
+
+ public function buildList()
+ {
+ return is_a($this->listQuery, PHPDS_query) ? $dep->db->invokeQuery($this->listQuery): array();
+ }
+
+ public function value($value = null)
+ {
+ if (!is_null($value)) {
+ if (is_array($this->list) && isset($this->list[$value])) $this->value = $value;
+ }
+ return $this->value;
+ }
+
+ public function defValue()
+ {
+ if (!empty($this->value)) return $this->value;
+
+ $a = array_keys($this->list);
+ $b = array_shift(array_keys($this->list));
+ if (is_array($this->list)) return array_shift(array_keys($this->list));
+ }
+ }
+
+
+
+ /**
+ *
+ * @author greg
+ *
+ */
+ class TaF_select_queryFilter extends TaF_list_queryFilter
+ {
+ public function toHTML()
+ {
+ $fct_name = $this->table->makeName('js_reload');
+ $html = "<label for=\"{$this->id}\">".$this->label()."</label>";
+ $html .= "<select id=\"{$this->id}\" name=\"{$this->id}\" onChange=\"$fct_name()\" >";
+ foreach($this->list as $key => $value) $html .= "<option value=\"$key\"".($this->value == $key ? 'selected' : '').">$value</option>";
+ $html .= '</select>';
+
+ return $html;
+ }
+
+ /*public function toJSbind()
+ {
+ $js = "$('#{$this->id}').change(function() { alert('toto'); $fct_name });";
+ return $js;
+ }*/
+
+ /*public function toJSdata()
+ {
+ return "'&{$this->id}=' + $('#{$this->id}').val()";
+ }*/
+
+ }
+
+
+
+
+
+
+
+ class TaF_radio_queryFilter extends TaF_list_queryFilter
+
+ {
+ protected $classes = array('line' => 'filterline', 'input' => 'filterinput');
+
+ public function toHTML()
+ {
+ $html = '<div class="'.$this->classes['line'].'">';
+ $html .= '<label>'.$this->label().'</label>';
+ foreach($this->list as $key => $value) {
+ $name = $this->id;
+ $id = $name.'_'.$value;
+ $html .= "<input type=\"radio\" id=\"$id\" name=\"$name\" class=\"{$this->classes['input']}\" value=\"$key\" ";
+ if ($key == $this->value) $html .= 'checked ';
+ $html .= "/><label for=\"$id\">$value</label>";
+ }
+ $html .= '</div>';
+ return $html;
+ }
+
+ public function toJSbind($fct_name = '')
+ {
+ return "$('input[name={$this->id}]').click(function() { $fct_name; });";
+ }
+
+ public function toJSdata()
+ {
+ return "'&{$this->id}=' + $('input:radio[name={$this->id}]:checked').val()";
+ }
+ }
+
+
+
+
+
+
+
+ class TaF_filteredQuery extends PHPDS_query
+ {
+
+ protected $filters = array();
+ protected $mode = 'AND';
+
+ /*
+ * filter can be a TaF_queryFilter object or a TaF_queryFilter-descendant class name
+ */
+ public function addFilter($filter, TaF_html_filteredTable $table)
+ {
+ if (is_a($filter, 'TaF_queryFilter')) $this->filters[] = $filter;
+ else {
+ $params = func_get_args();
+ array_shift($params); // shift-off $filter class name
+ $this->filters[] = $this->_factory($filter, $params);
+ }
+ return $this;
+ }
+
+ /**
+ * Construct the extra part of the query (WHERE ... GROUP BY ... ORDER BY...)
+ * Doesn't change $this->sql but DOES alter the query (our local clone)
+ *
+ * @param array $parameters
+ * @return string (sql)
+ */
+ public function extra_build($parameters = null)
+ {
+ foreach ($this->filters as $filter) $filter->alterQuery($this, $this->mode);
+
+ return parent::extra_build($parameters);
+ }
+ }
+
+
+
+
+
+
+
+ class TaF_html_filteredQuery extends TaF_filteredQuery
+ {
+ public function filtersAsHTML()
+ {
+ $html = '';
+ foreach($this->filters as $filter) $html .= $filter->toHTML();
+ return $html;
+ }
+
+ public function filtersAsJSbind()
+ {
+ $js = '';
+ foreach($this->filters as $filter) $js .= $filter->toJSbind()."\n";
+ return $js;
+ }
+
+ public function filtersAsJSdata()
+ {
+ $js = array();
+ foreach($this->filters as $filter) $js[] = $filter->toJSdata();
+ return implode(' + ', $js);
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ class TaF_html_filteredTable extends TaF_html_table
+ {
+ /*
+ * filter can be a TaF_queryFilter object or a TaF_queryFilter-descendant class name
+ */
+ public function addFilter($filter)
+ {
+ if (is_a($this->query, 'TaF_html_filteredQuery')) $this->query->addFilter($filter, $this);
+ }
+
+ public function makeName($action)
+ {
+ switch ($action) {
+ case 'js_reload': return 'TaFReload_'.$this->id;
+ }
+ }
+
+ public function make_html($forceLoad = false)
+ {
+ // first fetch the data
+ $data_html = parent::make_html($forceLoad);
+
+ // then add some headers
+ $html = $this->make_tag('div', $this->id.'_container', array('class' => 'slidingTable'));
+ $url = PU_BuildURL();
+ $html .= $this->make_tag('form', $this->id.'_form', array('action' => $url));
+ if (is_a($this->query, 'TaF_html_filteredQuery')) $html .= $this->filtersAsHTML($this); // this is actually calling the query's method "filtersAsHTML()", at least if it's not overriden by the table
+ $html .= $data_html;
+
+ //and some footers
+ $html .= $this->make_tag(); // _form
+ $html .= $this->make_tag(); // _container
+ if (is_a($this->query, 'TaF_html_filteredQuery')) $html .= $this->make_js($this);
+
+ return $html;
+ }
+
+ public function make_js()
+ {
+ $fct_name = $this->makeName('js_reload');
+
+ if ($js_filters = $this->query->filtersASJSdata()) $js_filters .= ' + '.$js_filters;
+
+ $js = '<script type="text/javascript" language="javascript">';
+ $js .= "\n//<![CDATA[\n";
+ $js .= <<<EndOfJavascript
+
+
+ function $fct_name(opt)
+ {
+ url = $('#{$this->id}_form').attr('action');
+ params = $('#{$this->id}_form').serializeArray(); // so it's sent as POST
+ if (opt) params[params.length] = opt;
+ $('#{$this->id}_container').load(url + ' #{$this->id}_form', params);
+ }
+
+
+EndOfJavascript;
+
+ $js .= $this->query->filtersAsJSbind($fct_name);
+
+ $js .= "\n//]]>\n</script>";
+
+ return $js;
+ }
+ }
+
=== added file 'TablesAndFilters/includes/TaF_table.class.php'
--- TablesAndFilters/includes/TaF_table.class.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/includes/TaF_table.class.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,302 @@
+<?php
+
+
+
+/**
+ * Basic class to link a table (i.e. tabular data) to a query result
+ *
+ * Usage 1 (implict instanciation of the class given its name):
+ * $params = array(
+ * 'query' => 'my_query_class',
+ * 'showHeaders' => true,
+ * 'headers' => array('ref' => 'Reference', 'name' => 'User name')
+ * );
+ * $t = $this->factory('TaF_table', $params);
+ *
+ * Usage 2 (you already have instanciated the class, you pass the object):
+ * $query = $this->db->makeQuery('my_query_class', $query_parameters);
+ * $params = array(
+ * 'query' => 'my_query_class',
+ * 'showHeaders' => true,
+ * 'headers' => array('ref' => 'Reference', 'name' => 'User name')
+ * );
+ * $t = $this->factory($query, $params);
+ *
+ * Note: all unknown method class are routed to the query so you can actually do something like: $t->sql('SELECT * FROM mytable');
+ *
+ * @author greg
+ *
+ */
+class TaF_table extends PHPDS_dependant
+{
+ /**
+ * These are the parameters used to customize the table:
+ * - query (optional): name of the query to instanciate or query object to use; if blank a useless empty PHPDS_query is created
+ * - query_parameters (optional): parameters to pass on to the query when it's actually invokated
+ * @var unknown_type
+ */
+ protected $parameters; // array
+
+ protected $parent = 'query';
+ protected $query; // PHPDS_query
+ protected $data; // array
+
+ protected $request;
+
+ protected $headers;
+ protected $classes;
+
+ protected static $defaults = array('showHeaders' => false);
+
+
+ public function construct ($parameters = null)
+ {
+ $this->parameters = is_array($parameters) ? array_merge(self::$defaults, $parameters) : self::$defaults;
+
+ $query = empty($this->parameters['query']) ? 'PHPDS_query' : $this->parameters['query'];
+ $this->query = (is_a($query, 'PHPDS_query')) ? clone $query : $this->db->makeQuery($query);
+ // TODO: is "clone" enough???
+
+ if (!empty($this->parameters->sql)) $this->query->sql($this->parameters->sql);
+ }
+
+
+ /**
+ * Use the query to load all data into memory
+ *
+ * Unless forced, if the data is already in memory, do nothing
+ *
+ * @version 1.1
+ * @date 20100528 (greg) (v1.1) use the query parameters taken from the table parameters array, if any
+ *
+ * @param boolean $force
+ * @return array the data
+ */
+ public function load($force = false)
+ {
+ if (empty($this->data) || $force) {
+ $this->data = empty($this->parameters['query_parameters']) ? $this->query->invoke() : $this->query->invoke($this->parameters['query_parameters']);
+
+ $this->purge();
+ }
+
+ return $this->data;
+ }
+
+ public function make_request()
+ {
+ $this->request = $this->query->query();
+ }
+
+ public function purge()
+ {
+ }
+
+ public function next()
+ {
+ }
+
+ public function count()
+ {
+ if (empty($data)) return $this->query->count();
+ else return count($this->data);
+ }
+
+ public function scan($line)
+ {
+ return $line;
+
+ }
+
+ /*public function __call($name, $arguments)
+ {
+ if (method_exists($this->query, $name)) return call_user_func_array(array($this->query, $name), $arguments);
+ else trigger_error("Table's query doesn't have a \"$name\"() method.");
+ }*/
+
+ public function data($data = null)
+ {
+ if (is_array($data)) $this->data = $data;
+ return $this->data;
+ }
+}
+
+
+/**
+ * An easy way to turn a query into a flexible HTML table
+ *
+ * @author greg
+ *
+ */
+class TaF_html_table extends TaF_table
+{
+ protected $alternate_styles = array('alt1', 'alt1', 'alt1', 'alt2', 'alt2', 'alt2');
+ protected $tag_styles = array(
+ 'table' => 'inside_table', 'tr'=> 'highlight', 'th' => 'head'
+ );
+ protected $id = '';
+
+ protected $tag_stack = array();
+
+ protected $empty_content = ' '; // default value in case we have to value to display
+
+
+ public function construct ($parameters = null)
+ {
+ if (empty($this->id)) $this->id = get_class($this);
+ //call_user_func_array(array($this, 'parent::__construct'), func_get_args());
+ parent::construct ($parameters);
+ }
+
+ public function id()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Creates an array with the key and the labels of the headers
+ *
+ * @date 20100428 (v1.0) (greg)
+ * @version 1.0
+ * @author greg
+ * @param array $data an row of data
+ * @return array
+ */
+ public function build_headers($data)
+ {
+ $result = array();
+
+ if (!empty($this->parameters['headers'])) {
+ // field list is given as a parameter
+ $result = $this->parameters['headers'];
+ /*foreach ($this->parameters['headers'] as $key => $value) {
+ $result .= $this->make_tag('th');
+ $result .= $value;
+ $result .= $this->make_tag();
+ }*/
+ } elseif (!empty($this->query->fields)) {
+ // fields are explicitly listed
+ foreach ($this->query->fields as $key => $value) {
+ // $key is column field name (from the DB point of view, $value is what's displayed
+ $result[$key] = $value;
+ }
+ } elseif (is_array($data)) {
+ // we're on our own, so we try to get the field names from the database result
+ $first_line = $data[array_shift(array_keys($data))];
+ if (is_array($first_line)) {
+ $keys = array_keys($first_line);
+ $result = array_combine($keys, $keys);
+ } else $result = array('#', '_');
+ }
+
+ return $result;
+ }
+
+ /**
+ * Takes a header array and make an html string out of it
+ *
+ * @date 20100428 (v1.0) (greg)
+ * @version 1.0
+ * @author greg
+ * @param array $headers
+ * @return string
+ */
+ public function make_headers($headers)
+ {
+ $result = '';
+ if (!empty($this->parameters['showHeaders'])) {
+ $result .= $this->make_tag('thead');
+ $result .= $this->make_tag('tr');
+
+ if(is_array($headers)) {
+ foreach ($headers as $key => $value) {
+ // $key is column field name (from the DB point of view, $value is what's displayed
+ $result .= $this->make_tag('th');
+ $result .= $value;
+ $result .= $this->make_tag(); // th
+ }
+ }
+ $result .= $this->make_tag(); //tr
+ $result .= $this->make_tag(); //theader
+ }
+ return $result;
+ }
+
+
+ public function make_html($forceLoad = false)
+ {
+ $this->load($forceLoad);
+ $result = $this->make_tag('table', $this->id.'_table');
+
+ if (is_array($this->data) && count($this->data) > 0) {
+ $headers = $this->build_headers($this->data);
+ $result .= $this->make_headers($headers);
+
+ $line_index = 0;
+
+ $result .= $this->make_tag('tbody');
+ foreach($this->data as $idx => $line) {
+ $style = $this->alternate_styles[$line_index % count($this->alternate_styles)];
+ $result .= $this->make_tag('tr', '', array('class' => $style));
+
+ foreach($headers as $key => $value) $result .= $this->make_cell($key, $line_index, $line, $idx);
+ $result .= $this->make_tag(); // tr
+ $line_index++;
+ }
+ $result .= $this->make_tag(); // tbody
+ }
+
+ $result .= $this->make_tag(); // table
+
+ return $result;
+ }
+
+
+ public function make_cell($key, $line_index, $line, $idx)
+ {
+ $result = $this->make_tag('td');
+ $matches = array();
+ if (preg_match('/.+ as (?<alias>.+)/', $key, $matches)) $key = $matches['alias'];
+ if (is_array($line)) {
+ $value = empty($line[$key]) ? '' : $line[$key];
+ } else $value = $line;
+ $content = $this->chew($key, $line_index, $line, $value, $idx);
+ if (empty($content)) $content = $this->empty_content;
+ $result .= $content;
+ $result .= $this->make_tag();
+ return $result;
+ }
+
+ /**
+ * Placeholder to give you the opportunity to alter a cell content before it's displayed
+ *
+ * @param string $column_key
+ * @param integer $line_index
+ * @param array $line
+ * @param mixed $value
+ * @return striing
+ */
+ public function chew($column_key, $line_index, $line, $value)
+ {
+ return $value;
+ }
+
+ public function make_tag($tag = null, $id = '', array $attributes = array(), $single = false)
+ {
+ if (empty($tag)) {
+ $html = '</'.array_pop($this->tag_stack).'>';
+ } else {
+ $class_tag = empty($this->tag_styles[$tag]) ? array() : array('class' => $this->tag_styles[$tag]);
+ $attr = PU_BuildAttrString(array_merge($class_tag, $attributes));
+ if ($id) $id = " id=\"$id\" ";
+ if ($single) {
+ $html ="<$tag$id$attr />";
+ }else {
+ array_push($this->tag_stack, $tag);
+ $html ="<$tag$id$attr>";
+ }
+ }
+
+ return $html;
+ }
+}
\ No newline at end of file
=== added directory 'TablesAndFilters/models'
=== added file 'TablesAndFilters/models/tableTest.query.php'
--- TablesAndFilters/models/tableTest.query.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/models/tableTest.query.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,12 @@
+<?php
+ //require_once 'includes/query.class.php';
+
+ class testTableQuery extends TaF_html_filteredQuery
+ {
+ protected $sql = 'SELECT SQL_CALC_FOUND_ROWS * FROM _db_core_menu_items';
+ protected $keyField = 'user_name';
+
+ }
+
+
+
=== added directory 'TablesAndFilters/scripts'
=== added file 'TablesAndFilters/scripts/tableTest.php'
--- TablesAndFilters/scripts/tableTest.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/scripts/tableTest.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,158 @@
+<?php
+
+ //(is_object($security)) ? $this->security->load_security(true) : exit('Access Denied!'); ////////////////////////////////////////
+
+ ?>
+
+ <style type="text/css">
+ .navigBtn {
+ padding: 3px;
+ outline: 1px solid black;
+ }
+ </style>
+
+ <?php
+
+
+ class_exists('TaF_table');
+ class_exists('TaF_filteredQuery');
+ class_exists('PHPDS_user');
+
+
+
+
+ class pagingFilter extends TaF_html_queryFilter
+ {
+ protected $pageSize = 10;
+ protected $pageNumber = 1;
+
+ protected $foundRows = 0;
+ protected $numRows = 0;
+ protected $lastPage = 0;
+
+ public function init()
+ {
+ $pageNo = empty($_POST['pageNo']) ? 1 :intval($_POST['pageNo']);
+ if ($pageNo > 0) $this->pageNumber = $pageNo;
+
+ $pageSize = empty($_POST['pageSize']) ? 10 : intval($_POST['pageSize']);
+ if ($pageSize > 0) $this->pageSize = $pageSize;
+ }
+
+ public function makeNavigBtn($label, $pageNo, $fct_name, $extra = '')
+ {
+ $html = '<button class="navigBtn" onClick="'.$fct_name.'({name:\'pageNo\',value:\''.$pageNo.'\'})"';
+ $html .= ' type="button" value="'.$pageNo.'" name="'.$this->id().'" '.$extra.' >'.$label.'</button>';
+
+ return $html;
+ }
+
+ public function toHTML()
+ {
+ $this->numRows = $this->count();
+ $this->foundRows = mysql_result($this->db->connector->query('SELECT FOUND_ROWS()'), 0 ,0);
+
+ $this->lastPage = intval($this->foundRows / $this->pageSize) + 1;
+
+ $fct_name = $this->table->makeName('js_reload');
+
+ $html = '<p>Paging by '.$this->pageSize.' rows - '.time().'</p>';
+ $html .= '<p>Rows on page '.$this->pageNumber.' (for a total of '.$this->foundRows.' rows on '.$this->lastPage.' pages)</p>';
+
+ $disabled = ($this->pageNumber < 2) ? 'disabled' : '';
+ $html .= $this->makeNavigBtn('First', 1, $fct_name, $disabled);
+ $html .= $this->makeNavigBtn('Prev', $this->pageNumber - 1, $fct_name, $disabled);
+
+ $disabled = ($this->pageNumber >= $this->lastPage) ? 'disabled' : '';
+ $html .= $this->makeNavigBtn('Next', $this->pageNumber + 1, $fct_name, $disabled);
+ $html .= $this->makeNavigBtn('Last', $this->lastPage, $fct_name, $disabled);
+
+ return $html;
+ }
+
+ public function alterQuery(PHPDS_query $query, $mode)
+ {
+ if ($this->pageSize < 1) $this->pageSize = 1;
+ if ($this->pageNumber < 1) $this->pageNumber = 1;
+
+ $query->limit($this->pageSize * ($this->pageNumber -1).', '.$this->pageSize);
+ return true;
+ }
+ }
+
+
+
+ class testTable extends TaF_html_filteredTable
+ {
+ /*public function _make_js()
+ {
+ $fct_name = 'TaFReload_'.$this->id;
+
+ if ($js_filters = $this->query->filtersASJSdata()) $js_filters .= ' + '.$js_filters;
+
+ $js = '<script type="text/javascript" language="javascript">';
+ $js .= "\n//<![CDATA[\n";
+ $js .= <<<EOS
+
+
+ function $fct_name(url, dir)
+ {
+ if (dir < 0) {
+ jQuery.get(url{$js_filters} + ' #{$this->id}_div', function (data, textStatus, XMLHttpRequest) {
+ $('#{$this->id}_container').prepend($(data).find('#testTable_div'));
+ previous = $('#{$this->id}_container div:last-child');
+ //previous.slideDown(function() { previous.remove(); });
+ });
+ } else {
+ jQuery.get(url{$js_filters} + ' #{$this->id}_div', function (data, textStatus, XMLHttpRequest) {
+ $('#{$this->id}_container').append($(data).find('#testTable_div'));
+ previous = $('#{$this->id}_container div:first-child');
+ previous.slideUp(function() { previous.remove(); });
+ });
+ }
+ }
+
+
+EOS;
+
+ $js .= '$(document).ready(function() {';
+ $js .= $this->query->filtersAsJSbind($fct_name.'();');
+ $js .=' });';
+
+ $js .= "\n//]]>\n</script>";
+
+ return $js;
+ }*/
+ }
+
+ class f1 extends TaF_select_queryFilter
+ {
+ protected $field = 'user_role';
+ protected $list = array(1 => 'one', 2 => 'two');
+ protected $value = 2;
+ }
+
+ class tableTestController extends PHPDS_controller
+ {
+
+ protected $params = array(
+ 'query' => 'testTableQuery',
+ 'showHeaders' => true
+ );
+
+ public function execute()
+ {
+ $t = $this->factory('testTable', $this->params);
+ /*$t->addFilter('pagingFilter');
+ $t->addFilter('f1');*/
+ echo '<tr><td>';
+ echo $t->make_html();
+ echo '</td></tr>';
+ }
+ }
+
+ return 'tableTestController';
+
+
+
+
=== added directory 'TablesAndFilters/tests'
=== added file 'TablesAndFilters/tests/taf.Test.php'
--- TablesAndFilters/tests/taf.Test.php 1970-01-01 00:00:00 +0000
+++ TablesAndFilters/tests/taf.Test.php 2013-05-14 05:06:25 +0000
@@ -0,0 +1,82 @@
+<?php
+
+ require_once 'mock_connector.php';
+
+ require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_table.class.php';
+ require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_filteredQuery.class.php';
+ require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_excerpt.class.php';
+
+ class TAF_testTable extends TaF_html_filteredTable
+ {
+
+ }
+
+ class testTableQuery extends TEST_stubQuery
+ {
+
+ }
+
+ class TAF_tableTest extends PHPUnit_Framework_TestCase
+ {
+ protected $query;
+ protected $stub;
+ protected $table;
+
+ protected function setUp()
+ {
+ $db = PHPDSlib::instance()->my_db();
+ $this->query = $db->factory('TEST_stubQuery');
+ $this->stub = $db->factory('TEST_mock_connector');
+ $this->query->connector($this->stub);
+ }
+
+ public function testDefaults()
+ {
+ $data_in = array(
+ array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
+ );
+ $this->stub->data = $data_in;
+
+ $this->table = $this->query->factory('TAF_testTable');
+
+ $html = $this->table->make_html();
+ $this->assertEquals('<div id="TAF_testTable_container" class="slidingTable"><form id="TAF_testTable_form" action="http://TEST/test.php"><table id="TAF_testTable_table" class="inside_table"></table></form></div>', $html);
+ }
+
+
+ /**
+ * @dataProvider tableValueProvider
+ * @group TaF
+ */
+ public function testVariousData($data, $result)
+ {
+ $this->stub->data = $data;
+
+ $params = array(
+ 'query' => $this->query,
+ 'showHeaders' => true
+ );
+ $this->table = $this->query->factory('TAF_testTable', $params);
+ $html = $this->table->make_html(true);
+ $this->assertEquals($result, $html);
+ }
+
+ public function tableValueProvider()
+ {
+ return array(
+ array(
+ array(
+ array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
+ ),
+ '<div id="TAF_testTable_container" class="slidingTable"><form id="TAF_testTable_form" action="http://TEST/test.php"><table id="TAF_testTable_table" class="inside_table"><thead><tr class="highlight"><th class="head">col1</th><th class="head">col2</th><th class="head">col3</th><th class="head">col4</th></tr></thead><tbody><tr class="alt1"><td>1</td><td>one</td><td> </td><td>abc</td></tr></tbody></table></form></div>'
+ ),
+ array(
+ array(
+ array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
+ array('col1' => 2, 'col2' => 'two', 'col3' => true, 'col4' => 'def'),
+ ),
+ '<div id="TAF_testTable_container" class="slidingTable"><form id="TAF_testTable_form" action="http://TEST/test.php"><table id="TAF_testTable_table" class="inside_table"><thead><tr class="highlight"><th class="head">col1</th><th class="head">col2</th><th class="head">col3</th><th class="head">col4</th></tr></thead><tbody><tr class="alt1"><td>1</td><td>one</td><td> </td><td>abc</td></tr><tr class="alt1"><td>2</td><td>two</td><td>1</td><td>def</td></tr></tbody></table></form></div>'
+ ),
+ );
+ }
+ }
\ No newline at end of file
=== added directory 'nbproject'
=== added directory 'nbproject/private'
=== added file 'nbproject/private/private.properties'
--- nbproject/private/private.properties 1970-01-01 00:00:00 +0000
+++ nbproject/private/private.properties 2013-05-14 05:06:25 +0000
@@ -0,0 +1,2 @@
+index.file=index.php
+url=http://localhost/TablesAndFilters/
=== added file 'nbproject/project.properties'
--- nbproject/project.properties 1970-01-01 00:00:00 +0000
+++ nbproject/project.properties 2013-05-14 05:06:25 +0000
@@ -0,0 +1,7 @@
+include.path=${php.global.include.path}
+php.version=PHP_53
+source.encoding=UTF-8
+src.dir=.
+tags.asp=false
+tags.short=true
+web.root=.
=== added file 'nbproject/project.xml'
--- nbproject/project.xml 1970-01-01 00:00:00 +0000
+++ nbproject/project.xml 2013-05-14 05:06:25 +0000
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.php.project</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/php-project/1">
+ <name>TablesAndFilters</name>
+ </data>
+ </configuration>
+</project>