Merge lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk into lp:~titan-phpdevshell/phpdevshell/main

Proposed by ignatia on 2013-05-14
Status: Needs review
Proposed branch: lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk
Merge into: lp:~titan-phpdevshell/phpdevshell/main
Diff against target: 1201 lines (+1134/-0)
11 files modified
TablesAndFilters/config/plugin.config.xml (+116/-0)
TablesAndFilters/controllers/index.php (+16/-0)
TablesAndFilters/includes/TaF_excerpt.class.php (+32/-0)
TablesAndFilters/includes/TaF_filteredQuery.class.php (+398/-0)
TablesAndFilters/includes/TaF_table.class.php (+302/-0)
TablesAndFilters/models/tableTest.query.php (+12/-0)
TablesAndFilters/scripts/tableTest.php (+158/-0)
TablesAndFilters/tests/taf.Test.php (+82/-0)
nbproject/private/private.properties (+2/-0)
nbproject/project.properties (+7/-0)
nbproject/project.xml (+9/-0)
To merge this branch: bzr merge lp:~gregfr/phpdevshell/TablesAndFilters-v1.0.0-trunk
Reviewer Review Type Date Requested Status
TitanKing 2013-05-14 Pending
Review via email: mp+163637@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

2. By greg <greg@Silencer> on 2012-07-01

Added class alias to plugin.config.xml

1. By TitanKing on 2010-11-11

Created tables and filters branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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 @@
1<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
2<!-- Please see http://phpdevshell.org for documentation on plugin config xml files. -->
3<config type="plugin">
4
5 <!-- Use a proper plugin name without using special characters. -->
6 <name>TablesAndFilters</name>
7
8 <!-- Human readable version number of your plugin. -->
9 <version>3.0</version>
10
11 <!-- a Short description of your plugin. -->
12 <description>This plugin provides easy to use tables based on query results.</description>
13
14 <!-- If the plugin/script is modification by you, place the original authors names here. -->
15 <founder>Greg Reitter</founder>
16
17 <!-- Name of the developer for this plugin. -->
18 <author>Greg Reitter</author>
19
20 <!-- Email address of the developer for this plugin. -->
21 <email>greg@phpdevshell.org</email>
22
23 <!-- Plugin developers web address. -->
24 <homepage>http://www.phpdevshell.org</homepage>
25
26 <!-- Date the plugin was developed, modified etc, this is up to you. -->
27 <date>July 2010</date>
28
29 <!-- Copyright notice you would like to amend to your plugin. -->
30 <copyright>Copyright 2010 PHPDevShell.org All rights reserved.</copyright>
31
32 <!-- License this plugin is released under. -->
33 <license>http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU/LGPL</license>
34 <!-- Code Version XML URL check. -->
35 <!-- Version (current) below is used to check for new releases and has little to do with database version. -->
36 <versionurl current="3000">http://version.phpdevshell.org/TablesAndFilters.xml</versionurl>
37
38 <!-- Detailed information and help for this plugin. -->
39 <info>
40 <![CDATA[
41 <p>
42 This plugin provides easy to use tables based on query results.
43 </p>
44 ]]>
45 </info>
46 <!-- Version here represents the database version that should be install. -->
47 <!-- If your database version needs no update, this number can stay the same. -->
48 <!-- Upgrades further down will only be executed up to this number. -->
49 <!-- This is the current database version that will be installed. -->
50 <!-- Below is a series of example upgrade procedures. -->
51 <install version="3000">
52 <!--
53 [contains][All query, menu, hooks, settings installation tags.]
54 [param][version][int][mandatory][The latest database version in numbers only.]
55 [note][This is how the plugin manager will know to what version upgrade scripts should be executed.]
56 [note][Always keep install maintained to the latest menu, query, hooks and setting versions.]
57 -->
58 <menus>
59 <!--
60 [contains][All types of menu items that needs to be installed.]
61 [note][Tags inside menus can be nested and repeated.]
62 -->
63 <menu name="testTable" type="1" link="scripts/tableTest.php" hide="0" rank="last" newwindow="" plugin="TablesAndFilters" >
64 <!--
65 [contains][Menu items can be contained in itself, this will create a menu tree.]
66 [param][name][string][not-mandatory][The name of the menu item, if empty the pluginName.menu.lang.php will be used.]
67 [param][type][int][not-mandatory][There are 8 menu types, 1 is the default if left empty.]
68 [1][Plugin script] normal plugin menu item in your plugin folder.
69 [2][Link existing menu] item while staying in its own menu group when clicked.
70 [3][Link existing menu] item while jumping to original scripts menu group when clicked.
71 [4][External file] Include external PHP web applications into PHPDevShell.
72 [5][HTTP URL] Normal url to outside web.
73 [6][Empty Place Holder] This item will only serve as a unclickable menu place holder.
74 [7][iFrame] Link url to both external url or onsite url.
75 [8][Cronjob Menu Type] The same as a plugin script but is set as cronjob.
76 [param][link][string][mandatory][The url, script location or symlink holder will be entered here depending on type.]
77 [param][hide][int][not-mandatory][There are 4 hide types, 0 is the default if left empty.]
78 [0] Do not hide menu item.
79 [1] Hide menu item from both Menu System and Control Panel.
80 [2] Hide menu item from Control Panel only.
81 [3] Hide menu item from Menu System only.
82 [4] Hide menu only when inactive.
83 [param][rank][string][not-mandatory][If you want to ensure ranking positions, will auto rank if left empty.]
84 [int] Can be ranked with integer.
85 [last] Will be ranked last in a menu group.
86 [first] Will be ranked first in a menu group.
87 [param][newwindow][int][not-mandatory][To make item open in new window set to 1, will not open in new if left empty.]
88 [param][plugin][string][not-mandatory][Plugin name, use to install menu item to a different plugins menu structure.]
89 [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.]
90 [param][parentlink][string][not-mandatory][Use with [param][plugin] or without to install in different structure.]
91 [param][symlink][string][not-mandatory][Url or location with [param][plugin] or without to link to another menu item duplicating its use.]
92 [note][Symlink is mandatory for menu types 1,2,6]
93 [param][template][string][not-mandatory][Set template to use with plugin, if template is unavailable it will be installed.]
94 [param][template][string][not-mandatory][Set the height of an iframe menu type.]
95 [note][Height is mandatory for menu types 7]
96 [param][layout][string][not-mandatory][Set a custom template.tpl location for a certain script.]
97 [param][noautopermission][int][not-mandatory][Set to 1 to not add the installer of the plugin to permit menu item access.]
98 -->
99 </menu>
100 </menus>
101 <classes>
102 <class name="TaF_table" alias="TaF_table" plugin="TablesAndFilters" rank="last" />
103 <class name="TaF_html_table@TaF_table" alias="TaF_table" plugin="TablesAndFilters" rank="last" />
104
105 <class name="TaF_filteredQuery" alias="TaF_filteredQuery" plugin="TablesAndFilters" rank="last" />
106 <class name="TaF_html_filteredQuery@TaF_filteredQuery" alias="TaF_html_filteredQuery" plugin="TablesAndFilters" rank="last" />
107 <class name="TaF_html_filteredTable@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
108 <class name="TaF_html_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
109 <class name="TaF_list_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
110 <class name="TaF_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
111 <class name="TaF_radio_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
112 <class name="TaF_select_queryFilter@TaF_filteredQuery" alias="TaF_html_filteredTable" plugin="TablesAndFilters" rank="last" />
113
114 </classes>
115 </install>
116</config>
0117
=== 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 @@
1<?php
2/**
3 * PHPDevShell is a RAD Framework aimed at developing administrative applications.
4 *
5 * @package PHPDevShell
6 * @link http://www.phpdevshell.org
7 * @copyright Copyright (C) 2007 Jason Schoeman, All rights reserved.
8 * @license GNU/LGPL, see readme/licensed_under_lgpl or http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
9 * @author Jason Schoeman, Contact: titan [at] phpdevshell [dot] org.
10 *
11 * Copyright notice: See readme/notice
12 * By using PHPDevShell you agree to notice and license, if you dont agree to this notice/license you are not allowed to use PHPDevShell.
13 */
14// Directory listing not allowed.
15exit('Access Denied!');
16?>
0\ No newline at end of file17\ No newline at end of file
118
=== 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 @@
1<?php
2
3
4
5 class TaF_excerpt extends PHPDS_dependant
6 {
7 protected $data = array();
8 protected $strip = true;
9
10
11 public function addArray(array $query_result)
12 {
13 //$strip = empty($options['strip']) ? $this->strip : true;
14 foreach($query_result as $key => $value) {
15 $this->data[$key] = $this->strip ? true : $value;
16 }
17 }
18
19 public function addResult($query_name)
20 {
21 $params = func_get_args();
22 array_shift($params); // first parameter of this function is $query_name
23 $query = $this->db->makeQuery($query_name);
24 $result = $query->invoke($params);
25 if (is_array($result)) return $this->addArray($result); else return false;
26 }
27
28 public function dump()
29 {
30 print_r($this->data);
31 }
32 }
0\ No newline at end of file33\ No newline at end of file
134
=== 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 @@
1<?php
2
3
4
5 /**
6 * FILTERED QUERIES AND TABLE - EXPERIMENTAL
7 *
8 * The basic idea is to take the winning couple PHPDS_query + PHPDS_table and add multilayers of user-provided constraints (ie filters) to it
9 *
10 * @author greg completly stolen ideas from Jason
11 *
12 */
13
14 class TaF_queryFilter extends PHPDS_dependant
15 {
16 protected $table; // TaF_html_filteredTable
17 protected $sql = ''; // a snipet in include into the WHERE clause
18
19 protected $field = ''; // filters are usualy (but not always) in the form: "field operator value" (ie. "age > 18")
20 protected $value = '';
21 protected $operator = '=';
22
23 public function __construct(TaF_html_filteredTable $table, TaF_filteredQuery $dependance)
24 {
25 parent::__construct($dependance); // our dependancy is the query
26 $this->table = $table;
27
28 $this->init();
29 }
30
31 /**
32 * Give the filter a chance to alter the given query to do its job
33 *
34 * @param PHPDS_query $query
35 * @param unknown_type $mode
36 * @return unknown_type
37 */
38 public function alterQuery(PHPDS_query $query, $mode)
39 {
40 $sql = $this->sql();
41 if ($sql) $query->addWhere($this->sql, $mode);
42 return true;
43 }
44
45 /**
46 * return a piece of sql to be added to the WHERE clause
47 *
48 * @param unknown_type $sql
49 * @return unknown_type
50 */
51 public function sql($sql = null)
52 {
53 if (!empty($sql)) $this->sql = $sql;
54 if (empty($this->sql) && !empty($this->field) && !empty($this->value)) $this->sql = $this->field.' '.$this->operator.' '.$this->value;
55 return $this->sql;
56 }
57
58 public function init()
59 {
60 return true;
61 }
62 }
63
64
65
66 /**
67 * Add an html presentation layer to a filter
68 *
69 * @author greg
70 *
71 */
72 class TaF_html_queryFilter extends TaF_queryFilter
73 {
74 protected $id = '';
75 protected $label = '';
76
77 public function __construct(TaF_html_filteredTable $table, TaF_filteredQuery $dependance)
78 {
79 if (empty($this->id)) $this->id = $table->id().'_'.get_class($this);
80 parent::__construct($table, $dependance);
81 }
82
83 public function label($label = null)
84 {
85 if (!empty($label)) $this->label = $label;
86 return $this->label;
87 }
88
89 public function id()
90 {
91 return $this->id;
92 }
93
94 /**
95 * This should ouput some html to be added before the table
96 *
97 * @return unknown_type
98 */
99 public function toHTML()
100 {
101 return '<p>'.$this->sql.'</p>';
102 }
103
104 /**
105 * Support for dynamic reload: bind the javascript function in a way you want it to be called for reloading the table
106 *
107 * @return javascript code to add inside a <script> clause
108 */
109 public function toJSbind()
110 {
111 return '';
112 }
113
114 /**
115 *
116 * This should return a pair key=value to add to the request to ensure the filtering
117 *
118 * @return string in the form " key=value " suitable for html request (such as GET or POST)
119 */
120 public function toJSdata()
121 {
122 return '';
123 }
124 }
125
126
127
128
129
130 /**
131 * A filter based on a list of key=>value pairs, possibly from a secondary query
132 *
133 * @author greg
134 *
135 */
136 class TaF_list_queryFilter extends TaF_html_queryFilter
137 {
138 protected $list = array();
139 protected $listQuery;
140
141 public function init ()
142 {
143 if (!empty($this->listQuery)) {
144 $dep = array_pop(func_get_args());
145
146 $this->list = $this->buildList();
147 }
148
149 //if ($this->select($this->select) != $this->select)
150 $select = isset($_POST[$this->id()]) ? $_POST[$this->id()] : $this->defValue();
151 // $this->select(VeM_GetFromRequest($this->id, $this->defValue()));
152 $this->value($select);
153 //TODO: get parameter is a nicer way
154 }
155
156 public function buildList()
157 {
158 return is_a($this->listQuery, PHPDS_query) ? $dep->db->invokeQuery($this->listQuery): array();
159 }
160
161 public function value($value = null)
162 {
163 if (!is_null($value)) {
164 if (is_array($this->list) && isset($this->list[$value])) $this->value = $value;
165 }
166 return $this->value;
167 }
168
169 public function defValue()
170 {
171 if (!empty($this->value)) return $this->value;
172
173 $a = array_keys($this->list);
174 $b = array_shift(array_keys($this->list));
175 if (is_array($this->list)) return array_shift(array_keys($this->list));
176 }
177 }
178
179
180
181 /**
182 *
183 * @author greg
184 *
185 */
186 class TaF_select_queryFilter extends TaF_list_queryFilter
187 {
188 public function toHTML()
189 {
190 $fct_name = $this->table->makeName('js_reload');
191 $html = "<label for=\"{$this->id}\">".$this->label()."</label>";
192 $html .= "<select id=\"{$this->id}\" name=\"{$this->id}\" onChange=\"$fct_name()\" >";
193 foreach($this->list as $key => $value) $html .= "<option value=\"$key\"".($this->value == $key ? 'selected' : '').">$value</option>";
194 $html .= '</select>';
195
196 return $html;
197 }
198
199 /*public function toJSbind()
200 {
201 $js = "$('#{$this->id}').change(function() { alert('toto'); $fct_name });";
202 return $js;
203 }*/
204
205 /*public function toJSdata()
206 {
207 return "'&{$this->id}=' + $('#{$this->id}').val()";
208 }*/
209
210 }
211
212
213
214
215
216
217
218 class TaF_radio_queryFilter extends TaF_list_queryFilter
219
220 {
221 protected $classes = array('line' => 'filterline', 'input' => 'filterinput');
222
223 public function toHTML()
224 {
225 $html = '<div class="'.$this->classes['line'].'">';
226 $html .= '<label>'.$this->label().'</label>';
227 foreach($this->list as $key => $value) {
228 $name = $this->id;
229 $id = $name.'_'.$value;
230 $html .= "<input type=\"radio\" id=\"$id\" name=\"$name\" class=\"{$this->classes['input']}\" value=\"$key\" ";
231 if ($key == $this->value) $html .= 'checked ';
232 $html .= "/><label for=\"$id\">$value</label>";
233 }
234 $html .= '</div>';
235 return $html;
236 }
237
238 public function toJSbind($fct_name = '')
239 {
240 return "$('input[name={$this->id}]').click(function() { $fct_name; });";
241 }
242
243 public function toJSdata()
244 {
245 return "'&{$this->id}=' + $('input:radio[name={$this->id}]:checked').val()";
246 }
247 }
248
249
250
251
252
253
254
255 class TaF_filteredQuery extends PHPDS_query
256 {
257
258 protected $filters = array();
259 protected $mode = 'AND';
260
261 /*
262 * filter can be a TaF_queryFilter object or a TaF_queryFilter-descendant class name
263 */
264 public function addFilter($filter, TaF_html_filteredTable $table)
265 {
266 if (is_a($filter, 'TaF_queryFilter')) $this->filters[] = $filter;
267 else {
268 $params = func_get_args();
269 array_shift($params); // shift-off $filter class name
270 $this->filters[] = $this->_factory($filter, $params);
271 }
272 return $this;
273 }
274
275 /**
276 * Construct the extra part of the query (WHERE ... GROUP BY ... ORDER BY...)
277 * Doesn't change $this->sql but DOES alter the query (our local clone)
278 *
279 * @param array $parameters
280 * @return string (sql)
281 */
282 public function extra_build($parameters = null)
283 {
284 foreach ($this->filters as $filter) $filter->alterQuery($this, $this->mode);
285
286 return parent::extra_build($parameters);
287 }
288 }
289
290
291
292
293
294
295
296 class TaF_html_filteredQuery extends TaF_filteredQuery
297 {
298 public function filtersAsHTML()
299 {
300 $html = '';
301 foreach($this->filters as $filter) $html .= $filter->toHTML();
302 return $html;
303 }
304
305 public function filtersAsJSbind()
306 {
307 $js = '';
308 foreach($this->filters as $filter) $js .= $filter->toJSbind()."\n";
309 return $js;
310 }
311
312 public function filtersAsJSdata()
313 {
314 $js = array();
315 foreach($this->filters as $filter) $js[] = $filter->toJSdata();
316 return implode(' + ', $js);
317 }
318
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332 class TaF_html_filteredTable extends TaF_html_table
333 {
334 /*
335 * filter can be a TaF_queryFilter object or a TaF_queryFilter-descendant class name
336 */
337 public function addFilter($filter)
338 {
339 if (is_a($this->query, 'TaF_html_filteredQuery')) $this->query->addFilter($filter, $this);
340 }
341
342 public function makeName($action)
343 {
344 switch ($action) {
345 case 'js_reload': return 'TaFReload_'.$this->id;
346 }
347 }
348
349 public function make_html($forceLoad = false)
350 {
351 // first fetch the data
352 $data_html = parent::make_html($forceLoad);
353
354 // then add some headers
355 $html = $this->make_tag('div', $this->id.'_container', array('class' => 'slidingTable'));
356 $url = PU_BuildURL();
357 $html .= $this->make_tag('form', $this->id.'_form', array('action' => $url));
358 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
359 $html .= $data_html;
360
361 //and some footers
362 $html .= $this->make_tag(); // _form
363 $html .= $this->make_tag(); // _container
364 if (is_a($this->query, 'TaF_html_filteredQuery')) $html .= $this->make_js($this);
365
366 return $html;
367 }
368
369 public function make_js()
370 {
371 $fct_name = $this->makeName('js_reload');
372
373 if ($js_filters = $this->query->filtersASJSdata()) $js_filters .= ' + '.$js_filters;
374
375 $js = '<script type="text/javascript" language="javascript">';
376 $js .= "\n//<![CDATA[\n";
377 $js .= <<<EndOfJavascript
378
379
380 function $fct_name(opt)
381 {
382 url = $('#{$this->id}_form').attr('action');
383 params = $('#{$this->id}_form').serializeArray(); // so it's sent as POST
384 if (opt) params[params.length] = opt;
385 $('#{$this->id}_container').load(url + ' #{$this->id}_form', params);
386 }
387
388
389EndOfJavascript;
390
391 $js .= $this->query->filtersAsJSbind($fct_name);
392
393 $js .= "\n//]]>\n</script>";
394
395 return $js;
396 }
397 }
398
0399
=== 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 @@
1<?php
2
3
4
5/**
6 * Basic class to link a table (i.e. tabular data) to a query result
7 *
8 * Usage 1 (implict instanciation of the class given its name):
9 * $params = array(
10 * 'query' => 'my_query_class',
11 * 'showHeaders' => true,
12 * 'headers' => array('ref' => 'Reference', 'name' => 'User name')
13 * );
14 * $t = $this->factory('TaF_table', $params);
15 *
16 * Usage 2 (you already have instanciated the class, you pass the object):
17 * $query = $this->db->makeQuery('my_query_class', $query_parameters);
18 * $params = array(
19 * 'query' => 'my_query_class',
20 * 'showHeaders' => true,
21 * 'headers' => array('ref' => 'Reference', 'name' => 'User name')
22 * );
23 * $t = $this->factory($query, $params);
24 *
25 * Note: all unknown method class are routed to the query so you can actually do something like: $t->sql('SELECT * FROM mytable');
26 *
27 * @author greg
28 *
29 */
30class TaF_table extends PHPDS_dependant
31{
32 /**
33 * These are the parameters used to customize the table:
34 * - query (optional): name of the query to instanciate or query object to use; if blank a useless empty PHPDS_query is created
35 * - query_parameters (optional): parameters to pass on to the query when it's actually invokated
36 * @var unknown_type
37 */
38 protected $parameters; // array
39
40 protected $parent = 'query';
41 protected $query; // PHPDS_query
42 protected $data; // array
43
44 protected $request;
45
46 protected $headers;
47 protected $classes;
48
49 protected static $defaults = array('showHeaders' => false);
50
51
52 public function construct ($parameters = null)
53 {
54 $this->parameters = is_array($parameters) ? array_merge(self::$defaults, $parameters) : self::$defaults;
55
56 $query = empty($this->parameters['query']) ? 'PHPDS_query' : $this->parameters['query'];
57 $this->query = (is_a($query, 'PHPDS_query')) ? clone $query : $this->db->makeQuery($query);
58 // TODO: is "clone" enough???
59
60 if (!empty($this->parameters->sql)) $this->query->sql($this->parameters->sql);
61 }
62
63
64 /**
65 * Use the query to load all data into memory
66 *
67 * Unless forced, if the data is already in memory, do nothing
68 *
69 * @version 1.1
70 * @date 20100528 (greg) (v1.1) use the query parameters taken from the table parameters array, if any
71 *
72 * @param boolean $force
73 * @return array the data
74 */
75 public function load($force = false)
76 {
77 if (empty($this->data) || $force) {
78 $this->data = empty($this->parameters['query_parameters']) ? $this->query->invoke() : $this->query->invoke($this->parameters['query_parameters']);
79
80 $this->purge();
81 }
82
83 return $this->data;
84 }
85
86 public function make_request()
87 {
88 $this->request = $this->query->query();
89 }
90
91 public function purge()
92 {
93 }
94
95 public function next()
96 {
97 }
98
99 public function count()
100 {
101 if (empty($data)) return $this->query->count();
102 else return count($this->data);
103 }
104
105 public function scan($line)
106 {
107 return $line;
108
109 }
110
111 /*public function __call($name, $arguments)
112 {
113 if (method_exists($this->query, $name)) return call_user_func_array(array($this->query, $name), $arguments);
114 else trigger_error("Table's query doesn't have a \"$name\"() method.");
115 }*/
116
117 public function data($data = null)
118 {
119 if (is_array($data)) $this->data = $data;
120 return $this->data;
121 }
122}
123
124
125/**
126 * An easy way to turn a query into a flexible HTML table
127 *
128 * @author greg
129 *
130 */
131class TaF_html_table extends TaF_table
132{
133 protected $alternate_styles = array('alt1', 'alt1', 'alt1', 'alt2', 'alt2', 'alt2');
134 protected $tag_styles = array(
135 'table' => 'inside_table', 'tr'=> 'highlight', 'th' => 'head'
136 );
137 protected $id = '';
138
139 protected $tag_stack = array();
140
141 protected $empty_content = '&nbsp;'; // default value in case we have to value to display
142
143
144 public function construct ($parameters = null)
145 {
146 if (empty($this->id)) $this->id = get_class($this);
147 //call_user_func_array(array($this, 'parent::__construct'), func_get_args());
148 parent::construct ($parameters);
149 }
150
151 public function id()
152 {
153 return $this->id;
154 }
155
156 /**
157 * Creates an array with the key and the labels of the headers
158 *
159 * @date 20100428 (v1.0) (greg)
160 * @version 1.0
161 * @author greg
162 * @param array $data an row of data
163 * @return array
164 */
165 public function build_headers($data)
166 {
167 $result = array();
168
169 if (!empty($this->parameters['headers'])) {
170 // field list is given as a parameter
171 $result = $this->parameters['headers'];
172 /*foreach ($this->parameters['headers'] as $key => $value) {
173 $result .= $this->make_tag('th');
174 $result .= $value;
175 $result .= $this->make_tag();
176 }*/
177 } elseif (!empty($this->query->fields)) {
178 // fields are explicitly listed
179 foreach ($this->query->fields as $key => $value) {
180 // $key is column field name (from the DB point of view, $value is what's displayed
181 $result[$key] = $value;
182 }
183 } elseif (is_array($data)) {
184 // we're on our own, so we try to get the field names from the database result
185 $first_line = $data[array_shift(array_keys($data))];
186 if (is_array($first_line)) {
187 $keys = array_keys($first_line);
188 $result = array_combine($keys, $keys);
189 } else $result = array('#', '_');
190 }
191
192 return $result;
193 }
194
195 /**
196 * Takes a header array and make an html string out of it
197 *
198 * @date 20100428 (v1.0) (greg)
199 * @version 1.0
200 * @author greg
201 * @param array $headers
202 * @return string
203 */
204 public function make_headers($headers)
205 {
206 $result = '';
207 if (!empty($this->parameters['showHeaders'])) {
208 $result .= $this->make_tag('thead');
209 $result .= $this->make_tag('tr');
210
211 if(is_array($headers)) {
212 foreach ($headers as $key => $value) {
213 // $key is column field name (from the DB point of view, $value is what's displayed
214 $result .= $this->make_tag('th');
215 $result .= $value;
216 $result .= $this->make_tag(); // th
217 }
218 }
219 $result .= $this->make_tag(); //tr
220 $result .= $this->make_tag(); //theader
221 }
222 return $result;
223 }
224
225
226 public function make_html($forceLoad = false)
227 {
228 $this->load($forceLoad);
229 $result = $this->make_tag('table', $this->id.'_table');
230
231 if (is_array($this->data) && count($this->data) > 0) {
232 $headers = $this->build_headers($this->data);
233 $result .= $this->make_headers($headers);
234
235 $line_index = 0;
236
237 $result .= $this->make_tag('tbody');
238 foreach($this->data as $idx => $line) {
239 $style = $this->alternate_styles[$line_index % count($this->alternate_styles)];
240 $result .= $this->make_tag('tr', '', array('class' => $style));
241
242 foreach($headers as $key => $value) $result .= $this->make_cell($key, $line_index, $line, $idx);
243 $result .= $this->make_tag(); // tr
244 $line_index++;
245 }
246 $result .= $this->make_tag(); // tbody
247 }
248
249 $result .= $this->make_tag(); // table
250
251 return $result;
252 }
253
254
255 public function make_cell($key, $line_index, $line, $idx)
256 {
257 $result = $this->make_tag('td');
258 $matches = array();
259 if (preg_match('/.+ as (?<alias>.+)/', $key, $matches)) $key = $matches['alias'];
260 if (is_array($line)) {
261 $value = empty($line[$key]) ? '' : $line[$key];
262 } else $value = $line;
263 $content = $this->chew($key, $line_index, $line, $value, $idx);
264 if (empty($content)) $content = $this->empty_content;
265 $result .= $content;
266 $result .= $this->make_tag();
267 return $result;
268 }
269
270 /**
271 * Placeholder to give you the opportunity to alter a cell content before it's displayed
272 *
273 * @param string $column_key
274 * @param integer $line_index
275 * @param array $line
276 * @param mixed $value
277 * @return striing
278 */
279 public function chew($column_key, $line_index, $line, $value)
280 {
281 return $value;
282 }
283
284 public function make_tag($tag = null, $id = '', array $attributes = array(), $single = false)
285 {
286 if (empty($tag)) {
287 $html = '</'.array_pop($this->tag_stack).'>';
288 } else {
289 $class_tag = empty($this->tag_styles[$tag]) ? array() : array('class' => $this->tag_styles[$tag]);
290 $attr = PU_BuildAttrString(array_merge($class_tag, $attributes));
291 if ($id) $id = " id=\"$id\" ";
292 if ($single) {
293 $html ="<$tag$id$attr />";
294 }else {
295 array_push($this->tag_stack, $tag);
296 $html ="<$tag$id$attr>";
297 }
298 }
299
300 return $html;
301 }
302}
0\ No newline at end of file303\ No newline at end of file
1304
=== 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 @@
1<?php
2 //require_once 'includes/query.class.php';
3
4 class testTableQuery extends TaF_html_filteredQuery
5 {
6 protected $sql = 'SELECT SQL_CALC_FOUND_ROWS * FROM _db_core_menu_items';
7 protected $keyField = 'user_name';
8
9 }
10
11
12
013
=== 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 @@
1<?php
2
3 //(is_object($security)) ? $this->security->load_security(true) : exit('Access Denied!'); ////////////////////////////////////////
4
5 ?>
6
7 <style type="text/css">
8 .navigBtn {
9 padding: 3px;
10 outline: 1px solid black;
11 }
12 </style>
13
14 <?php
15
16
17 class_exists('TaF_table');
18 class_exists('TaF_filteredQuery');
19 class_exists('PHPDS_user');
20
21
22
23
24 class pagingFilter extends TaF_html_queryFilter
25 {
26 protected $pageSize = 10;
27 protected $pageNumber = 1;
28
29 protected $foundRows = 0;
30 protected $numRows = 0;
31 protected $lastPage = 0;
32
33 public function init()
34 {
35 $pageNo = empty($_POST['pageNo']) ? 1 :intval($_POST['pageNo']);
36 if ($pageNo > 0) $this->pageNumber = $pageNo;
37
38 $pageSize = empty($_POST['pageSize']) ? 10 : intval($_POST['pageSize']);
39 if ($pageSize > 0) $this->pageSize = $pageSize;
40 }
41
42 public function makeNavigBtn($label, $pageNo, $fct_name, $extra = '')
43 {
44 $html = '<button class="navigBtn" onClick="'.$fct_name.'({name:\'pageNo\',value:\''.$pageNo.'\'})"';
45 $html .= ' type="button" value="'.$pageNo.'" name="'.$this->id().'" '.$extra.' >'.$label.'</button>';
46
47 return $html;
48 }
49
50 public function toHTML()
51 {
52 $this->numRows = $this->count();
53 $this->foundRows = mysql_result($this->db->connector->query('SELECT FOUND_ROWS()'), 0 ,0);
54
55 $this->lastPage = intval($this->foundRows / $this->pageSize) + 1;
56
57 $fct_name = $this->table->makeName('js_reload');
58
59 $html = '<p>Paging by '.$this->pageSize.' rows - '.time().'</p>';
60 $html .= '<p>Rows on page '.$this->pageNumber.' (for a total of '.$this->foundRows.' rows on '.$this->lastPage.' pages)</p>';
61
62 $disabled = ($this->pageNumber < 2) ? 'disabled' : '';
63 $html .= $this->makeNavigBtn('First', 1, $fct_name, $disabled);
64 $html .= $this->makeNavigBtn('Prev', $this->pageNumber - 1, $fct_name, $disabled);
65
66 $disabled = ($this->pageNumber >= $this->lastPage) ? 'disabled' : '';
67 $html .= $this->makeNavigBtn('Next', $this->pageNumber + 1, $fct_name, $disabled);
68 $html .= $this->makeNavigBtn('Last', $this->lastPage, $fct_name, $disabled);
69
70 return $html;
71 }
72
73 public function alterQuery(PHPDS_query $query, $mode)
74 {
75 if ($this->pageSize < 1) $this->pageSize = 1;
76 if ($this->pageNumber < 1) $this->pageNumber = 1;
77
78 $query->limit($this->pageSize * ($this->pageNumber -1).', '.$this->pageSize);
79 return true;
80 }
81 }
82
83
84
85 class testTable extends TaF_html_filteredTable
86 {
87 /*public function _make_js()
88 {
89 $fct_name = 'TaFReload_'.$this->id;
90
91 if ($js_filters = $this->query->filtersASJSdata()) $js_filters .= ' + '.$js_filters;
92
93 $js = '<script type="text/javascript" language="javascript">';
94 $js .= "\n//<![CDATA[\n";
95 $js .= <<<EOS
96
97
98 function $fct_name(url, dir)
99 {
100 if (dir < 0) {
101 jQuery.get(url{$js_filters} + ' #{$this->id}_div', function (data, textStatus, XMLHttpRequest) {
102 $('#{$this->id}_container').prepend($(data).find('#testTable_div'));
103 previous = $('#{$this->id}_container div:last-child');
104 //previous.slideDown(function() { previous.remove(); });
105 });
106 } else {
107 jQuery.get(url{$js_filters} + ' #{$this->id}_div', function (data, textStatus, XMLHttpRequest) {
108 $('#{$this->id}_container').append($(data).find('#testTable_div'));
109 previous = $('#{$this->id}_container div:first-child');
110 previous.slideUp(function() { previous.remove(); });
111 });
112 }
113 }
114
115
116EOS;
117
118 $js .= '$(document).ready(function() {';
119 $js .= $this->query->filtersAsJSbind($fct_name.'();');
120 $js .=' });';
121
122 $js .= "\n//]]>\n</script>";
123
124 return $js;
125 }*/
126 }
127
128 class f1 extends TaF_select_queryFilter
129 {
130 protected $field = 'user_role';
131 protected $list = array(1 => 'one', 2 => 'two');
132 protected $value = 2;
133 }
134
135 class tableTestController extends PHPDS_controller
136 {
137
138 protected $params = array(
139 'query' => 'testTableQuery',
140 'showHeaders' => true
141 );
142
143 public function execute()
144 {
145 $t = $this->factory('testTable', $this->params);
146 /*$t->addFilter('pagingFilter');
147 $t->addFilter('f1');*/
148 echo '<tr><td>';
149 echo $t->make_html();
150 echo '</td></tr>';
151 }
152 }
153
154 return 'tableTestController';
155
156
157
158
0159
=== 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 @@
1<?php
2
3 require_once 'mock_connector.php';
4
5 require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_table.class.php';
6 require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_filteredQuery.class.php';
7 require_once BASEPATH.'/plugins/TablesAndFilters/includes/TaF_excerpt.class.php';
8
9 class TAF_testTable extends TaF_html_filteredTable
10 {
11
12 }
13
14 class testTableQuery extends TEST_stubQuery
15 {
16
17 }
18
19 class TAF_tableTest extends PHPUnit_Framework_TestCase
20 {
21 protected $query;
22 protected $stub;
23 protected $table;
24
25 protected function setUp()
26 {
27 $db = PHPDSlib::instance()->my_db();
28 $this->query = $db->factory('TEST_stubQuery');
29 $this->stub = $db->factory('TEST_mock_connector');
30 $this->query->connector($this->stub);
31 }
32
33 public function testDefaults()
34 {
35 $data_in = array(
36 array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
37 );
38 $this->stub->data = $data_in;
39
40 $this->table = $this->query->factory('TAF_testTable');
41
42 $html = $this->table->make_html();
43 $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);
44 }
45
46
47 /**
48 * @dataProvider tableValueProvider
49 * @group TaF
50 */
51 public function testVariousData($data, $result)
52 {
53 $this->stub->data = $data;
54
55 $params = array(
56 'query' => $this->query,
57 'showHeaders' => true
58 );
59 $this->table = $this->query->factory('TAF_testTable', $params);
60 $html = $this->table->make_html(true);
61 $this->assertEquals($result, $html);
62 }
63
64 public function tableValueProvider()
65 {
66 return array(
67 array(
68 array(
69 array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
70 ),
71 '<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>&nbsp;</td><td>abc</td></tr></tbody></table></form></div>'
72 ),
73 array(
74 array(
75 array('col1' => 1, 'col2' => 'one', 'col3' => false, 'col4' => 'abc'),
76 array('col1' => 2, 'col2' => 'two', 'col3' => true, 'col4' => 'def'),
77 ),
78 '<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>&nbsp;</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>'
79 ),
80 );
81 }
82 }
0\ No newline at end of file83\ No newline at end of file
184
=== 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 @@
1index.file=index.php
2url=http://localhost/TablesAndFilters/
03
=== 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 @@
1include.path=${php.global.include.path}
2php.version=PHP_53
3source.encoding=UTF-8
4src.dir=.
5tags.asp=false
6tags.short=true
7web.root=.
08
=== 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 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://www.netbeans.org/ns/project/1">
3 <type>org.netbeans.modules.php.project</type>
4 <configuration>
5 <data xmlns="http://www.netbeans.org/ns/php-project/1">
6 <name>TablesAndFilters</name>
7 </data>
8 </configuration>
9</project>

Subscribers

People subscribed via source and target branches