source: extensions/GrumPluginClasses/classes/GPCRequestBuilder.class.inc.php @ 8961

Revision 8961, 43.0 KB checked in by grum, 9 years ago (diff)

release 3.4.0
fix bug:1984, bug:2109
js file are minified, remove packed files

Line 
1<?php
2/* -----------------------------------------------------------------------------
3  class name: GCPRequestBuilder
4  class version  : 1.1.2
5  plugin version : 3.3.3
6  date           : 2010-09-08
7
8  ------------------------------------------------------------------------------
9  Author     : Grum
10    email    : grum@piwigo.org
11    website  : http://photos.grum.com
12    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
13
14    << May the Little SpaceFrog be with you ! >>
15  ------------------------------------------------------------------------------
16  *
17  * theses classes provides base functions to manage search pictures in the
18  * database
19  *
20  *
21  * HOW TO USE IT ?
22  * ===============
23  *
24  * when installing the plugin, you have to register the usage of the request
25  * builder
26  *
27  * 1/ Create a RBCallback class
28  *  - extends the GPCSearchCallback class ; the name of the extended class must
29  *    be "RBCallBack%" => replace the "%" by the plugin name
30  *     for example : 'ThePlugin' => 'RBCallBackThePlugin'
31  *
32  * 2/ In the plugin 'maintain.inc.php' file :
33  *  - function plugin_install, add :
34  *       GPCRequestBuilder::register('plugin name', 'path to the RBCallback classe');
35  *          for example : GPCRequestBuilder::register('ThePlugin', $piwigo_path.'plugins/ThePlugin/rbcallback_file_name.php');
36  *
37  *
38  *  - function plugin_uninstall, add :
39  *       GPCRequestBuilder::unregister('plugin name');
40  *          for example : GPCRequestBuilder::unregister('ThePlugin');
41  *
42  * 3/ In the plugin code, put somewhere
43  *     GPCRequestBuilder::loadJSandCSS();
44  *     => this will load specific JS and CSS in the page, by adding url in the
45  *        the header, so try to put this where you're used to prepare the header
46  *
47  * 4/ to display the request builder, just add the returned string in the html
48  *    page
49  *       $stringForTheTemplate=GPCRequestBuilder::displaySearchPage();
50  *
51  *
52  *
53  * HOW DOES THE REQUEST BUILDER WORKS ?
54  * ====================================
55  *
56  * the request builder works in 2 steps :
57  *  - first step  : build a cache, to associate all image id corresponding to
58  *                  the search criterion
59  *                  the cache is an association of request ID/image id
60  *  - second step : use the cache to retrieve images informations
61  *
62  ------------------------------------------------------------------------------
63  :: HISTORY
64
65| release | date       |
66| 1.0.0   | 2010/04/30 | * start coding
67|         |            |
68| 1.1.0   | 2010/09/08 | * add functionnalities to manage complex requests
69|         |            |
70| 1.1.1   | 2010/10/14 | * fix bug on the buildGroupRequest function
71|         |            |   . adding 'DISTINCT' keyword to the SQL requests
72|         |            |
73|         |            | * ajax management moved into the gpc_ajax.php file
74|         |            |
75|         |            | * fix bug on user level access to picture
76|         |            |
77| 1.1.2   | 2010/11/01 | * mantis bug:1984
78|         |            |   . RBuilder returns an error message when one picture
79|         |            |     have multiple categories
80|         |            |
81|         |            |
82
83  --------------------------------------------------------------------------- */
84
85if(!defined('GPC_DIR')) define('GPC_DIR' , baseName(dirname(dirname(__FILE__))));
86if(!defined('GPC_PATH')) define('GPC_PATH' , PHPWG_PLUGINS_PATH . GPC_DIR . '/');
87
88include_once('GPCTables.class.inc.php');
89
90/**
91 *
92 * Preparing the temporary table => doCache()
93 * ------------------------------------------
94 * To prepare the cache, the request builder use the following functions :
95 *  - getImageId
96 *  - getFrom
97 *  - getWhere
98 *  - getHaving
99 *
100 * Preparing the cache table => doCache()
101 * --------------------------------------
102 * To prepare the cache, the request builder use the following functions :
103 *  => the getFilter function is used to prepare the filter for the getPage()
104 *     function ; not used to build the cache
105 *
106 * Retrieving the results => getPage()
107 * -----------------------------------
108 * To retrieve the image informations, the request builder uses the following
109 * functions :
110 *  - getSelect
111 *  - getFrom
112 *  - getJoin
113 *  - getFilter (in fact, the result of this function is stored by the doCache()
114 *               function while the cache is builded, but it is used only when
115 *               retrieving the results for multirecord tables)
116 *  - formatData
117 *
118 *
119 * Example
120 * -------
121 * Consider the table "tableA" like this
122 *
123 *  - (*) imageId
124 *  - (*) localId
125 *  -     att1
126 *  -     att2
127 *  The primary key is the 'imageId'+'localId' attributes
128 *    => for one imageId, you can have ZERO or more than ONE record
129 *       when you register the class, you have to set the $multiRecord parameter
130 *       to 'y'
131 *
132 *  gatImageId returns      : "tableA.imageId"
133 *  getSelect returns       : "tableA.att1, tableA.att2"
134 *  getFrom returns         : "tableA"
135 *  getWhere returns        : "tableA.localId= xxxx AND tableA.att1 = zzzz"
136 *  getJoin returns         : "tableA.imageId = pit.id"
137 *  getFilter returns       : "tableA.localId= xxxx"
138 *
139 *  Examples :
140 *   - plugin AdvancedMetadata use getFilter
141 *   - plugin AdvancedSearchEngine, module ASETag use getHaving and getWhere
142 */
143class GPCSearchCallback {
144
145  /**
146   * the getImageId returns the name of the image id attribute
147   * return String
148   */
149  static public function getImageId()
150  {
151    return("");
152  }
153
154  /**
155   * the getSelect function must return an attribute list separated with a comma
156   *
157   * "att1, att2, att3, att4"
158   *
159   * you can specifie tables names and aliases
160   *
161   * "table1.att1 AS alias1, table1.att2 AS alias2, table2.att3 AS alias3"
162   */
163  static public function getSelect($param="")
164  {
165    return("");
166  }
167
168  /**
169   * the getFrom function must return a tables list separated with a comma
170   *
171   * "table1, (table2 left join table3 on table2.key = table3.key), table4"
172   */
173  static public function getFrom($param="")
174  {
175    return("");
176  }
177
178  /**
179   * the getWhere function must return a ready to use where clause
180   *
181   * "(att1 = value0 OR att2 = value1) AND att4 LIKE value2 "
182   */
183  static public function getWhere($param="")
184  {
185    return("");
186  }
187
188
189  /**
190   * the getHaving function return a ready to user HAVING clause
191   *
192   * " FIND_IN_SET(value0, GROUP_CONCAT(DISTINCT att1 SEPARATOR ',')) AND
193   *   FIND_IN_SET(value0, GROUP_CONCAT(DISTINCT att1 SEPARATOR ',')) "
194   *
195   */
196  static public function getHaving($param="")
197  {
198    return("");
199  }
200
201
202  /**
203   * the getJoin function must return a ready to use sql statement allowing to
204   * join the IMAGES table (key : pit.id) with given conditions
205   *
206   * "att3 = pit.id "
207   */
208  static public function getJoin($param="")
209  {
210    return("");
211  }
212
213
214  /**
215   * the getFilter function must return a ready to use where clause
216   * this where clause is used to filter the cache when the used tables can
217   * return more than one result
218   *
219   * the filter can be empty, can be equal to the where clause, or can be equal
220   * to a sub part of the where clause
221   *
222   * in most case, return "" is the best solution
223   *
224   */
225  static public function getFilter($param="")
226  {
227    //return(self::getWhere($param));
228    return("");
229  }
230
231
232  /**
233   * this function is called by the request builder, allowing to display plugin
234   * data with a specific format
235   *
236   * @param Array $attributes : array of ('attribute_name' => 'attribute_value')
237   * @return String : HTML formatted value
238   */
239  static public function formatData($attributes)
240  {
241    return(print_r($attributes, true));
242  }
243
244
245  /**
246   * this function is called by the request builder to make the search page, and
247   * must return the HTML & JS code of the dialogbox used to select criterion
248   *
249   * Notes :
250   *  - the dialogbox is a JS object with a public method 'show'
251   *  - when the method show is called, one parameter is given by the request
252   *    builder ; the parameter is an object defined as this :
253   *      {
254   *        cBuilder: an instance of the criteriaBuilder object used in the page,
255   *      }
256   *
257   *
258   *
259   *
260   * @param String $mode : can take 'admin' or 'public' values, allowing to
261   *                       return different interface if needed
262   * @return String : HTML formatted value
263   */
264  static public function getInterfaceContent($mode='admin')
265  {
266    return("");
267  }
268
269  /**
270   * this function returns the label displayed in the criterion menu
271   *
272   * @return String : label displayed in the criterions menu
273   */
274  static public function getInterfaceLabel()
275  {
276    return(l10n('gpc_rb_unknown_interface'));
277  }
278
279  /**
280   * this function returns the name of the dialog box class
281   *
282   * @return String : name of the dialogbox class
283   */
284  static public function getInterfaceDBClass()
285  {
286    return('');
287  }
288
289
290}
291
292
293//load_language('rbuilder.lang', GPC_PATH);
294
295
296class GPCRequestBuilder {
297
298  static public $pluginName = 'GPCRequestBuilder';
299  static public $version = '1.1.0';
300
301  static private $tables = Array();
302  static protected $tGlobalId=0;
303
304  /**
305   * register a plugin using GPCRequestBuilder
306   *
307   * @param String $pluginName : the plugin name
308   * @param String $fileName : the php filename where the callback function can
309   *                           be found
310   * @return Boolean : true if registering is Ok, otherwise false
311   */
312  static public function register($plugin, $fileName)
313  {
314    $config=Array();
315    if(GPCCore::loadConfig(self::$pluginName, $config))
316    {
317      $config['registered'][$plugin]=Array(
318        'name' => $plugin,
319        'fileName' => $fileName,
320        'date' => date("Y-m-d H:i:s"),
321        'version' => self::$version
322      );
323      return(GPCCore::saveConfig(self::$pluginName, $config));
324    }
325    return(false);
326  }
327
328  /**
329   * unregister a plugin using GPCRequestBuilder
330   *
331   * assume that if the plugin was not registerd before, unregistering returns
332   * a true value
333   *
334   * @param String $pluginName : the plugin name
335   * @return Boolean : true if registering is Ok, otherwise false
336   */
337  static public function unregister($plugin)
338  {
339    $config=Array();
340    if(GPCCore::loadConfig(self::$pluginName, $config))
341    {
342      if(array_key_exists('registered', $config))
343      {
344        if(array_key_exists($plugin, $config['registered']))
345        {
346          unset($config['registered'][$plugin]);
347          return(GPCCore::saveConfig(self::$pluginName, $config));
348        }
349      }
350    }
351    // assume if the plugin was not registered before, unregistering it is OK
352    return(true);
353  }
354
355  /**
356   * @return Array : list of registered plugins
357   */
358  static public function getRegistered()
359  {
360    $config=Array();
361    if(GPCCore::loadConfig(self::$pluginName, $config))
362    {
363      if(array_key_exists('registered', $config))
364      {
365        return($config['registered']);
366      }
367    }
368    return(Array());
369  }
370
371
372  /**
373   * initialise the class
374   *
375   * @param String $prefixeTable : the piwigo prefixe used on tables name
376   * @param String $pluginNameFile : the plugin name used for tables name
377   */
378  static public function init($prefixeTable, $pluginNameFile)
379  {
380    $list=Array('request', 'result_cache', 'temp');
381
382    for($i=0;$i<count($list);$i++)
383    {
384      self::$tables[$list[$i]]=$prefixeTable.$pluginNameFile.'_'.$list[$i];
385    }
386  }
387
388  /**
389   * create the tables needed by RequestBuilder (used during the gpc process install)
390   */
391  static public function createTables()
392  {
393    $tablesDef=array(
394"CREATE TABLE `".self::$tables['request']."` (
395  `id` int(10) unsigned NOT NULL auto_increment,
396  `user_id` int(10) unsigned NOT NULL,
397  `date` datetime NOT NULL,
398  `num_items` int(10) unsigned NOT NULL default '0',
399  `execution_time` float unsigned NOT NULL default '0',
400  `connected_plugin` char(255) NOT NULL,
401  `filter` text NOT NULL,
402  `parameters` text NOT NULL,
403  PRIMARY KEY  (`id`)
404)
405CHARACTER SET utf8 COLLATE utf8_general_ci",
406
407"CREATE TABLE `".self::$tables['result_cache']."` (
408  `id` int(10) unsigned NOT NULL,
409  `image_id` int(10) unsigned NOT NULL,
410  PRIMARY KEY  (`id`,`image_id`)
411)
412CHARACTER SET utf8 COLLATE utf8_general_ci",
413
414"CREATE TABLE `".self::$tables['temp']."` (
415  `requestId` char(30) NOT NULL,
416  `imageId` mediumint(8) unsigned NOT NULL,
417  PRIMARY KEY  (`requestId`,`imageId`)
418)
419CHARACTER SET utf8 COLLATE utf8_general_ci",
420  );
421
422    $tablef= new GPCTables(self::$tables);
423    $tablef->create($tablesDef);
424
425    return(true);
426  }
427
428  /**
429   * update the tables needed by RequestBuilder (used during the gpc process
430   * activation)
431   */
432  static public function updateTables($pluginPreviousRelease)
433  {
434    $tablef=new GPCTables(array(self::$tables['temp']));
435
436    switch($pluginPreviousRelease)
437    {
438      case '03.01.00':
439        $tablesCreate=array();
440        $tablesUpdate=array();
441
442        $tablesCreate[]=
443"CREATE TABLE `".self::$tables['temp']."` (
444  `requestId` char(30) NOT NULL,
445  `imageId` mediumint(8) unsigned NOT NULL,
446  PRIMARY KEY  (`requestId`,`imageId`)
447)
448CHARACTER SET utf8 COLLATE utf8_general_ci";
449
450        $tablesUpdate[self::$tables['request']]['filter']=
451"ADD COLUMN  `filter` text NOT NULL default '' ";
452
453
454
455        $tablef->create($tablesCreate);
456        $tablef->updateTablesFields($tablesUpdate);
457        // no break ! need to be updated like the next release
458        // break;
459      case '03.01.01':
460      case '03.02.00':
461      case '03.02.01':
462      case '03.03.00':
463      case '03.03.01':
464        $tablesUpdate=array();
465
466        $tablesUpdate[self::$tables['request']]['parameters']=
467"ADD COLUMN `parameters` TEXT NOT NULL AFTER `filter`";
468
469        $tablef->updateTablesFields($tablesUpdate);
470        // no break ! need to be updated like the next release
471        // break;
472    }
473
474    return(true);
475  }
476
477  /**
478   * delete the tables needed by RequestBuilder
479   */
480  static public function deleteTables()
481  {
482    $tablef= new GPCTables(self::$tables);
483    $tablef->drop();
484    return(true);
485  }
486
487
488  /**
489   * this function add and handler on the 'loc_end_page_header' to add request
490   * builder JS script & specific CSS on the page
491   *
492   * use it when the displayed page need an access to the criteriaBuilder GUI
493   *
494   */
495  static public function loadJSandCSS()
496  {
497    load_language('rbuilder.lang', GPC_PATH);
498    add_event_handler('loc_begin_page_header', array('GPCRequestBuilder', 'insertJSandCSSFiles'), 9);
499  }
500
501
502  /**
503   * insert JS a CSS file in header
504   *
505   * the function is declared public because it used by the 'loc_begin_page_header'
506   * event callback
507   *
508   * DO NOT USE IT DIRECTLY
509   *
510   */
511  static public function insertJSandCSSFiles()
512  {
513    global $template;
514
515
516    $baseName=basename(dirname(dirname(__FILE__))).'/css/';
517    $template->append('head_elements', '<link href="plugins/'.$baseName.'rbuilder.css" type="text/css" rel="stylesheet"/>');
518    if(defined('IN_ADMIN')) $template->append('head_elements', '<link href="plugins/'.$baseName.'rbuilder_'.$template->get_themeconf('name').'.css" type="text/css" rel="stylesheet"/>');
519
520
521    $baseName=basename(dirname(dirname(__FILE__))).'/js/';
522    GPCCore::addHeaderJS('jquery', 'themes/default/js/jquery.packed.js');
523    GPCCore::addHeaderJS('gpc.interface', 'plugins/'.$baseName.'external/interface/interface.js');
524    GPCCore::addHeaderJS('gpc.inestedsortable', 'plugins/'.$baseName.'external/inestedsortable.pack.js');
525    GPCCore::addHeaderJS('gpc.rbCriteriaBuilder', 'plugins/'.$baseName.'rbCriteriaBuilder'.GPCCore::getMinified().'.js');
526
527    $template->append('head_elements',
528"<script type=\"text/javascript\">
529  requestBuilderOptions = {
530    textAND:\"".l10n('gpc_rb_textAND')."\",
531    textOR:\"".l10n('gpc_rb_textOR')."\",
532    textNoCriteria:\"".l10n('There is no criteria ! At least, one criteria is required to do search...')."\",
533    textSomethingWrong:\"".l10n('gpc_something_is_wrong_on_the_server_side')."\",
534    textCaddieUpdated:\"".l10n('gpc_the_caddie_is_updated')."\",
535    helpEdit:\"".l10n('gpc_help_edit_criteria')."\",
536    helpDelete:\"".l10n('gpc_help_delete_criteria')."\",
537    helpMove:\"".l10n('gpc_help_move_criteria')."\",
538    helpSwitchCondition:\"".l10n('gpc_help_switch_condition')."\",
539    ajaxUrl:'plugins/GrumPluginClasses/gpc_ajax.php',
540  }
541</script>");
542  }
543
544
545  /**
546   * execute request from the ajax call
547   *
548   * @return String : a ready to use HTML code
549   */
550  static public function executeRequest($ajaxfct)
551  {
552    $result='';
553    switch($ajaxfct)
554    {
555      case 'public.rbuilder.searchExecute':
556        $result=self::doCache();
557        break;
558      case 'public.rbuilder.searchGetPage':
559        $result=self::getPage($_REQUEST['requestNumber'], $_REQUEST['page'], $_REQUEST['numPerPage']);
560        break;
561    }
562    return($result);
563  }
564
565
566  /**
567   * clear the cache table
568   *
569   * @param Boolean $clearAll : if set to true, clear all records without
570   *                            checking timestamp
571   */
572  static public function clearCache($clearAll=false)
573  {
574    if($clearAll)
575    {
576      $sql="DELETE FROM ".self::$tables['result_cache'];
577    }
578    else
579    {
580      $sql="DELETE pgrc FROM ".self::$tables['result_cache']." pgrc
581              LEFT JOIN ".self::$tables['request']." pgr
582                ON pgrc.id = pgr.id
583              WHERE pgr.date < '".date('Y-m-d H:i:s', strtotime("-2 hour"))."'";
584    }
585    pwg_query($sql);
586  }
587
588  /**
589   * prepare the temporary table used for multirecord requests
590   *
591   * @param Integer $requestNumber : id of request
592   * @return String : name of the request key temporary table
593   */
594  static private function prepareTempTable($requestNumber)
595  {
596    //$tableName=call_user_func(Array('RBCallBack'.$plugin, 'getFrom'));
597    //$imageIdName=call_user_func(Array('RBCallBack'.$plugin, 'getImageId'));
598
599    $tempClauses=array();
600    foreach($_REQUEST['extraData'] as $key => $extraData)
601    {
602      $tempClauses[$key]=array(
603        'plugin' => $extraData['owner'],
604        'where' => call_user_func(Array('RBCallBack'.$extraData['owner'], 'getWhere'), $extraData['param']),
605        'having' => call_user_func(Array('RBCallBack'.$extraData['owner'], 'getHaving'), $extraData['param']),
606      );
607    }
608
609    $sql="INSERT INTO ".self::$tables['temp']." ".self::buildGroupRequest($_REQUEST[$_REQUEST['requestName']], $tempClauses, $_REQUEST['operator'], ' AND ', $requestNumber);
610//echo $sql;
611    $result=pwg_query($sql);
612
613    return($requestNumber);
614  }
615
616  /**
617   * clear the temporary table used for multirecord requests
618   *
619   * @param Array $requestNumber : the requestNumber to delete
620   */
621  static private function clearTempTable($requestNumber)
622  {
623    $sql="DELETE FROM ".self::$tables['temp']." WHERE requestId = '$requestNumber';";
624    pwg_query($sql);
625  }
626
627
628  /**
629   * execute a query, and place result in cache
630   *
631   *
632   * @return String : queryNumber;numberOfItems
633   */
634  static private function doCache()
635  {
636    global $user;
637
638    self::clearCache();
639
640    $registeredPlugin=self::getRegistered();
641    $requestNumber=self::getNewRequest($user['id']);
642
643    $build=Array(
644      'SELECT' => 'pit.id',
645      'FROM' => '',
646      'WHERE' => 'pit.level <= '.$user['level'],
647      'GROUPBY' => '',
648      'FILTER' => ''
649    );
650    $tmpBuild=Array(
651      'FROM' => Array(
652        '('.IMAGES_TABLE.' pit LEFT JOIN '.IMAGE_CATEGORY_TABLE.' pic ON pit.id = pic.image_id)' /*JOIN IMAGES & IMAGE_CATEGORY tables*/
653       .'   JOIN '.USER_CACHE_CATEGORIES_TABLE.' pucc ON pucc.cat_id=pic.category_id',  /* IMAGE_CATEGORY & USER_CACHE_CATEGORIES_TABLE tables*/
654
655      ),
656      'WHERE' => Array(),
657      'JOIN' => Array(999=>'pucc.user_id='.$user['id']),
658      'GROUPBY' => Array(
659        'pit.id'
660      ),
661      'FILTER' => Array(),
662    );
663
664    /* build data request for plugins
665     *
666     * Array('Plugin1' =>
667     *          Array(
668     *            criteriaNumber1 => pluginParam1,
669     *            criteriaNumber2 => pluginParam2,
670     *            criteriaNumberN => pluginParamN
671     *          ),
672     *       'Plugin2' =>
673     *          Array(
674     *            criteriaNumber1 => pluginParam1,
675     *            criteriaNumber2 => pluginParam2,
676     *            criteriaNumberN => pluginParamN
677     *          )
678     * )
679     *
680     */
681    $pluginNeeded=Array();
682    $pluginList=Array();
683    $tempName=Array();
684    foreach($_REQUEST['extraData'] as $key => $val)
685    {
686      $pluginNeeded[$val['owner']][$key]=$_REQUEST['extraData'][$key]['param'];
687      $pluginList[$val['owner']]=$val['owner'];
688    }
689
690    /* for each plugin, include the rb callback class file */
691    foreach($pluginList as $val)
692    {
693      if(file_exists($registeredPlugin[$val]['fileName']))
694      {
695        include_once($registeredPlugin[$val]['fileName']);
696      }
697    }
698
699    /* prepare the temp table for the request */
700    self::prepareTempTable($requestNumber);
701    $tmpBuild['FROM'][]=self::$tables['temp'];
702    $tmpBuild['JOIN'][]=self::$tables['temp'].".requestId = '".$requestNumber."'
703                        AND ".self::$tables['temp'].".imageId = pit.id";
704
705    /* for each needed plugin, prepare the filter */
706    foreach($pluginNeeded as $key => $val)
707    {
708      foreach($val as $itemNumber => $param)
709      {
710        $tmpFilter=call_user_func(Array('RBCallBack'.$key, 'getFilter'), $param);
711
712        if(trim($tmpFilter)!="") $tmpBuild['FILTER'][$key][]='('.$tmpFilter.')';
713      }
714    }
715
716
717    /* build FROM
718     *
719     */
720    $build['FROM']=implode(',', $tmpBuild['FROM']);
721    unset($tmpBuild['FROM']);
722
723    /* build WHERE
724     */
725    self::cleanArray($tmpBuild['WHERE']);
726    if(count($tmpBuild['WHERE'])>0)
727    {
728      $build['WHERE']=' ('.self::buildGroup($_REQUEST[$_REQUEST['requestName']], $tmpBuild['WHERE'], $_REQUEST['operator'], ' AND ').') ';
729    }
730    unset($tmpBuild['WHERE']);
731
732
733    /* build FILTER
734     */
735    self::cleanArray($tmpBuild['FILTER']);
736    if(count($tmpBuild['FILTER'])>0)
737    {
738      $tmp=array();
739      foreach($tmpBuild['FILTER'] as $key=>$val)
740      {
741        $tmp[$key]='('.implode(' OR ', $val).')';
742      }
743      $build['FILTER']=' ('.implode(' AND ', $tmp).') ';
744    }
745    unset($tmpBuild['FILTER']);
746
747
748    /* for each plugin, adds jointure with the IMAGE table
749     */
750    self::cleanArray($tmpBuild['JOIN']);
751    if(count($tmpBuild['JOIN'])>0)
752    {
753      if($build['WHERE']!='') $build['WHERE'].=' AND ';
754      $build['WHERE'].=' ('.implode(' AND ', $tmpBuild['JOIN']).') ';
755    }
756    unset($tmpBuild['JOIN']);
757
758    self::cleanArray($tmpBuild['GROUPBY']);
759    if(count($tmpBuild['GROUPBY'])>0)
760    {
761      $build['GROUPBY'].=' '.implode(', ', $tmpBuild['GROUPBY']).' ';
762    }
763    unset($tmpBuild['GROUPBY']);
764
765
766
767    $sql=' FROM '.$build['FROM'];
768    if($build['WHERE']!='')
769    {
770      $sql.=' WHERE '.$build['WHERE'];
771    }
772    if($build['GROUPBY']!='')
773    {
774      $sql.=' GROUP BY '.$build['GROUPBY'];
775    }
776
777    $sql.=" ORDER BY pit.id ";
778
779    $sql="INSERT INTO ".self::$tables['result_cache']." (SELECT DISTINCT $requestNumber, ".$build['SELECT']." $sql)";
780
781//echo $sql;
782    $returned="0;0";
783
784    $result=pwg_query($sql);
785    if($result)
786    {
787      $numberItems=pwg_db_changes($result);
788      self::updateRequest($requestNumber, $numberItems, 0, implode(',', $pluginList), $build['FILTER'], $_REQUEST['extraData']);
789
790      $returned="$requestNumber;".$numberItems;
791    }
792
793    self::clearTempTable($requestNumber);
794
795    return($returned);
796  }
797
798  /**
799   * return a page content. use the cache table to find request result
800   *
801   * @param Integer $requestNumber : the request number (from cache table)
802   * @param Integer $pageNumber : the page to be returned
803   * @param Integer $numPerPage : the number of items returned on a page
804   * @param String $mode : if mode = 'count', the function returns the number of
805   *                       rows ; otherwise, returns rows in a html string
806   * @return String : formatted HTML code
807   */
808  static private function getPage($requestNumber, $pageNumber, $numPerPage)
809  {
810    global $conf, $user;
811    $request=self::getRequest($requestNumber);
812
813    if($request===false)
814    {
815      return("KO");
816    }
817
818    $limitFrom=$numPerPage*($pageNumber-1);
819
820    $pluginNeeded=explode(',', $request['connected_plugin']);
821    $registeredPlugin=self::getRegistered();
822
823    $build=Array(
824      'SELECT' => '',
825      'FROM' => '',
826      'WHERE' => '',
827      'GROUPBY' => '',
828    );
829    $tmpBuild=Array(
830      'SELECT' => Array(
831        'RB_PIT' => "pit.id AS imageId, pit.name AS imageName, pit.path AS imagePath", // from the piwigo's image table
832        'RB_PIC' => "GROUP_CONCAT( pic.category_id SEPARATOR ',') AS imageCategoriesId",     // from the piwigo's image_category table
833        'RB_PCT' => "GROUP_CONCAT( CASE WHEN pct.name IS NULL THEN '' ELSE pct.name END SEPARATOR '#sep#') AS imageCategoriesNames,
834                     GROUP_CONCAT( CASE WHEN pct.permalink IS NULL THEN '' ELSE pct.permalink END SEPARATOR '#sep#') AS imageCategoriesPLink,
835                     GROUP_CONCAT( CASE WHEN pct.dir IS NULL THEN 'V' ELSE 'P' END) AS imageCategoriesDir",   //from the piwigo's categories table
836      ),
837      'FROM' => Array(
838        // join rb result_cache table with piwigo's images table, joined with the piwigo's image_category table, joined with the categories table
839        'RB' => "(((".self::$tables['result_cache']." pgrc
840                  RIGHT JOIN ".IMAGES_TABLE." pit
841                  ON pgrc.image_id = pit.id)
842                    RIGHT JOIN ".IMAGE_CATEGORY_TABLE." pic
843                    ON pit.id = pic.image_id)
844                       RIGHT JOIN ".CATEGORIES_TABLE." pct
845                       ON pct.id = pic.category_id)
846                          RIGHT JOIN ".USER_CACHE_CATEGORIES_TABLE." pucc
847                          ON pucc.cat_id = pic.category_id",
848      ),
849      'WHERE' => Array(
850        'RB' => "pgrc.id=".$requestNumber." AND pucc.user_id=".$user['id'],
851        ),
852      'JOIN' => Array(),
853      'GROUPBY' => Array(
854        'RB' => "pit.id"
855      )
856    );
857
858
859    $extraData=array();
860    foreach($request['parameters'] as $data)
861    {
862      $extraData[$data['owner']]=$data['param'];
863    }
864
865    /* for each needed plugin :
866     *  - include the file
867     *  - call the static public function getFrom, getJoin, getSelect
868     */
869    foreach($pluginNeeded as $key => $val)
870    {
871      if(array_key_exists($val, $registeredPlugin))
872      {
873        if(file_exists($registeredPlugin[$val]['fileName']))
874        {
875          include_once($registeredPlugin[$val]['fileName']);
876
877          $tmp=explode(',', call_user_func(Array('RBCallBack'.$val, 'getSelect'), $extraData[$val]));
878          foreach($tmp as $key2=>$val2)
879          {
880            $tmp[$key2]=self::groupConcatAlias($val2, '#sep#');
881          }
882          $tmpBuild['SELECT'][$val]=implode(',', $tmp);
883          $tmpBuild['FROM'][$val]=call_user_func(Array('RBCallBack'.$val, 'getFrom'), $extraData[$val]);
884          $tmpBuild['JOIN'][$val]=call_user_func(Array('RBCallBack'.$val, 'getJoin'), $extraData[$val]);
885        }
886      }
887    }
888
889    /* build SELECT
890     *
891     */
892    $build['SELECT']=implode(',', $tmpBuild['SELECT']);
893
894    /* build FROM
895     *
896     */
897    $build['FROM']=implode(',', $tmpBuild['FROM']);
898    unset($tmpBuild['FROM']);
899
900
901    /* build WHERE
902     */
903    if($request['filter']!='') $tmpBuild['WHERE'][]=$request['filter'];
904    $build['WHERE']=implode(' AND ', $tmpBuild['WHERE']);
905    unset($tmpBuild['WHERE']);
906
907    /* for each plugin, adds jointure with the IMAGE table
908     */
909    self::cleanArray($tmpBuild['JOIN']);
910    if(count($tmpBuild['JOIN'])>0)
911    {
912      $build['WHERE'].=' AND ('.implode(' AND ', $tmpBuild['JOIN']).') ';
913    }
914    unset($tmpBuild['JOIN']);
915
916    self::cleanArray($tmpBuild['GROUPBY']);
917    if(count($tmpBuild['GROUPBY'])>0)
918    {
919      $build['GROUPBY'].=' '.implode(', ', $tmpBuild['GROUPBY']).' ';
920    }
921    unset($tmpBuild['GROUPBY']);
922
923
924    $imagesList=Array();
925
926    $sql='SELECT DISTINCT '.$build['SELECT']
927        .' FROM '.$build['FROM']
928        .' WHERE '.$build['WHERE']
929        .' GROUP BY '.$build['GROUPBY'];
930
931    $sql.=' ORDER BY pit.id '
932         .' LIMIT '.$limitFrom.', '.$numPerPage;
933
934//echo $sql;
935    $result=pwg_query($sql);
936    if($result)
937    {
938      while($row=pwg_db_fetch_assoc($result))
939      {
940        // affect standard datas
941        $datas['imageThumbnail']=dirname($row['imagePath'])."/".$conf['dir_thumbnail']."/".$conf['prefix_thumbnail'].basename($row['imagePath']);
942        $datas['imageId']=$row['imageId'];
943        $datas['imagePath']=$row['imagePath'];
944        $datas['imageName']=$row['imageName'];
945
946        $datas['imageCategoriesId']=explode(',', $row['imageCategoriesId']);
947        $datas['imageCategoriesNames']=explode('#sep#', $row['imageCategoriesNames']);
948        $datas['imageCategoriesPLink']=explode('#sep#', $row['imageCategoriesPLink']);
949        $datas['imageCategoriesDir']=explode(',', $row['imageCategoriesDir']);
950
951        $datas['imageCategories']=Array();
952        for($i=0;$i<count($datas['imageCategoriesId']);$i++)
953        {
954          $datas['imageCategories'][]=array(
955            'id' => $datas['imageCategoriesId'][$i],
956            'name' => $datas['imageCategoriesNames'][$i],
957            'dirType' => $datas['imageCategoriesDir'][$i],
958            'pLinks' => $datas['imageCategoriesPLink'][$i],
959            'link'=> make_picture_url(
960                        array(
961                          'image_id' => $datas['imageId'],
962                          'category' => array
963                            (
964                              'id' => $datas['imageCategoriesId'][$i],
965                              'name' => $datas['imageCategoriesNames'][$i],
966                              'permalink' => $datas['imageCategoriesPLink'][$i]
967                            )
968                        )
969                      )
970          );
971        }
972
973        /* affect datas for each plugin
974         *
975         * each plugin have to format the data in an HTML code
976         *
977         * so, for each plugin :
978         *  - look the attributes given in the SELECT clause
979         *  - for each attributes, associate the returned value of the record
980         *  - affect in datas an index equals to the plugin pluginName, with returned HTML code ; HTML code is get from a formatData function
981         *
982         * Example :
983         *  plugin ColorStart provide 2 attributes 'csColors' and 'csColorsPct'
984         *
985         *  we affect to the $attributes var :
986         *  $attributes['csColors'] = $row['csColors'];
987         *  $attributes['csColorsPct'] = $row['csColorsPct'];
988         *
989         *  call the ColorStat RB callback formatData with the $attributes => the function return a HTML code ready to use in the template
990         *
991         *  affect $datas['ColorStat'] = $the_returned_html_code;
992         *
993         *
994         */
995        foreach($tmpBuild['SELECT'] as $key => $val)
996        {
997          if($key!='RB_PIT' && $key!='RB_PIC' && $key!='RB_PCT')
998          {
999            $tmp=explode(',', $val);
1000
1001            $attributes=Array();
1002
1003            foreach($tmp as $key2 => $val2)
1004            {
1005              $name=self::getAttribute($val2);
1006              $attributes[$name]=$row[$name];
1007            }
1008
1009            $datas['plugin'][$key]=call_user_func(Array('RBCallBack'.$key, 'formatData'), $attributes);
1010
1011            unset($tmp);
1012            unset($attributes);
1013          }
1014        }
1015        $imagesList[]=$datas;
1016        unset($datas);
1017      }
1018    }
1019
1020    return(self::toHtml($imagesList));
1021    //return("get page : $requestNumber, $pageNumber, $numPerPage<br>$debug<br>$sql");
1022  }
1023
1024  /**
1025   * remove all empty value from an array
1026   * @param Array a$array : the array to clean
1027   */
1028  static private function cleanArray(&$array)
1029  {
1030    foreach($array as $key => $val)
1031    {
1032      if(is_array($val))
1033      {
1034        self::cleanArray($val);
1035        if(count($val)==0) unset($array[$key]);
1036      }
1037      elseif(trim($val)=='') unset($array[$key]);
1038    }
1039  }
1040
1041  /**
1042   * returns the alias for an attribute
1043   *
1044   *  item1                          => returns item1
1045   *  table1.item1                   => returns item1
1046   *  table1.item1 AS alias1         => returns alias1
1047   *  item1 AS alias1                => returns alias1
1048   *  GROUP_CONCAT( .... ) AS alias1 => returns alias1
1049   *
1050   * @param String $var : value to examine
1051   * @return String : the attribute name
1052   */
1053  static private function getAttribute($val)
1054  {
1055    preg_match('/(?:GROUP_CONCAT\(.*\)|(?:[A-Z0-9_]*)\.)?([A-Z0-9_]*)(?:\s+AS\s+([A-Z0-9_]*))?/i', trim($val), $result);
1056    if(array_key_exists(2, $result))
1057    {
1058      return($result[2]);
1059    }
1060    elseif(array_key_exists(1, $result))
1061    {
1062      return($result[1]);
1063    }
1064    else
1065    {
1066      return($val);
1067    }
1068  }
1069
1070
1071  /**
1072   * returns a a sql statement GROUP_CONCAT for an alias
1073   *
1074   *  item1                  => returns GROUP_CONCAT(item1 SEPARATOR $sep) AS item1
1075   *  table1.item1           => returns GROUP_CONCAT(table1.item1 SEPARATOR $sep) AS item1
1076   *  table1.item1 AS alias1 => returns GROUP_CONCAT(table1.item1 SEPARATOR $sep) AS alias1
1077   *  item1 AS alias1        => returns GROUP_CONCAT(item1 SEPARATOR $sep) AS alias1
1078   *
1079   * @param String $val : value to examine
1080   * @param String $sep : the separator
1081   * @return String : the attribute name
1082   */
1083  static private function groupConcatAlias($val, $sep=',')
1084  {
1085    /*
1086     * table1.item1 AS alias1
1087     *
1088     * $result[3] = alias1
1089     * $result[2] = item1
1090     * $result[1] = table1.item1
1091     */
1092    preg_match('/((?:(?:[A-Z0-9_]*)\.)?([A-Z0-9_]*))(?:\s+AS\s+([A-Z0-9_]*))?/i', trim($val), $result);
1093    if(array_key_exists(3, $result))
1094    {
1095      return("GROUP_CONCAT(DISTINCT ".$result[1]." SEPARATOR '$sep') AS ".$result[3]);
1096    }
1097    elseif(array_key_exists(2, $result))
1098    {
1099      return("GROUP_CONCAT(DISTINCT ".$result[1]." SEPARATOR '$sep') AS ".$result[2]);
1100    }
1101    else
1102    {
1103      return("GROUP_CONCAT(DISTINCT $val SEPARATOR '$sep') AS ".$val);
1104    }
1105  }
1106
1107
1108  /**
1109   * get a new request number and create it in the request table
1110   *
1111   * @param Integer $userId : id of the user
1112   * @return Integer : the new request number, -1 if something wrong appened
1113   */
1114  static private function getNewRequest($userId)
1115  {
1116    $sql="INSERT INTO ".self::$tables['request']." VALUES('', '$userId', '".date('Y-m-d H:i:s')."', 0, 0, '', '', '')";
1117    $result=pwg_query($sql);
1118    if($result)
1119    {
1120      return(pwg_db_insert_id());
1121    }
1122    return(-1);
1123  }
1124
1125  /**
1126   * update request properties
1127   *
1128   * @param Integer $request_id : the id of request to update
1129   * @param Integer $numItems : number of items found in the request
1130   * @param Float $executionTime : time in second to execute the request
1131   * @param String $pluginList : list of used plugins
1132   * @param String $parameters : parameters given for the request
1133   * @return Boolean : true if request was updated, otherwise false
1134   */
1135  static private function updateRequest($requestId, $numItems, $executionTime, $pluginList, $additionalFilter, $parameters)
1136  {
1137    $sql="UPDATE ".self::$tables['request']."
1138            SET num_items = $numItems,
1139                execution_time = $executionTime,
1140                connected_plugin = '$pluginList',
1141                filter = '".mysql_escape_string($additionalFilter)."',
1142                parameters = '".serialize($parameters)."'
1143            WHERE id = $requestId";
1144    $result=pwg_query($sql);
1145    if($result)
1146    {
1147      return(true);
1148    }
1149    return(false);
1150  }
1151
1152  /**
1153   * returns request properties
1154   *
1155   * @param Integer $request_id : the id of request to update
1156   * @return Array : properties for request, false if request doesn't exist
1157   */
1158  static private function getRequest($requestId)
1159  {
1160    $returned=false;
1161    $sql="SELECT user_id, date, num_items, execution_time, connected_plugin, filter, parameters
1162          FROM ".self::$tables['request']."
1163          WHERE id = $requestId";
1164    $result=pwg_query($sql);
1165    if($result)
1166    {
1167      while($row=pwg_db_fetch_assoc($result))
1168      {
1169        if($row['parameters']!='') $row['parameters']=unserialize($row['parameters']);
1170        $returned=$row;
1171      }
1172    }
1173    return($returned);
1174  }
1175
1176
1177  /**
1178   * internal function used by the executeRequest function for single record
1179   * requests
1180   *
1181   * this function is called recursively
1182   *
1183   * @param Array $groupContent :
1184   * @param Array $items :
1185   * @return String : a where clause
1186   */
1187  static private function buildGroup($groupContent, $items, $groups, $operator)
1188  {
1189    $returned=Array();
1190    foreach($groupContent as $key => $val)
1191    {
1192      if(strpos($val['id'], 'iCbGroup')!==false)
1193      {
1194        preg_match('/[0-9]*$/i', $val['id'], $groupNumber);
1195        $returned[]=self::buildGroup($val['children'], $items, $groups, $groups[$groupNumber[0]]);
1196      }
1197      else
1198      {
1199        preg_match('/[0-9]*$/i', $val['id'], $itemNumber);
1200        $returned[]=" (".$items[$itemNumber[0]].") ";
1201      }
1202    }
1203    return('('.implode($operator, $returned).')');
1204  }
1205
1206
1207  /**
1208   * internal function used by the executeRequest function for multi records
1209   * requests
1210   *
1211   * this function is called recursively
1212   *
1213   * @param Array $groupContent :
1214   * @param Array $clausesItems : array with 'where' and 'having' conditions (and 'plugin' for the plugin)
1215   * @param Array $groups : operators of each group
1216   * @param String $operator : 'OR' or 'AND', according with the current group operator
1217   * @param String $requestNumber : the request number
1218   * @return String : part of a SQL request
1219   */
1220  static private function buildGroupRequest($groupContent, $clausesItems, $groups, $operator, $requestNumber)
1221  {
1222    $returnedS='';
1223    $returned=Array();
1224    foreach($groupContent as $key => $val)
1225    {
1226      if(strpos($val['id'], 'iCbGroup')!==false)
1227      {
1228        preg_match('/[0-9]*$/i', $val['id'], $groupNumber);
1229
1230        $groupValue=self::buildGroupRequest($val['children'], $clausesItems, $groups, $groups[$groupNumber[0]], $requestNumber);
1231
1232        if($groupValue!='')
1233          $returned[]=array(
1234            'mode'  => 'group',
1235            'value' => $groupValue
1236          );
1237      }
1238      else
1239      {
1240        preg_match('/[0-9]*$/i', $val['id'], $itemNumber);
1241
1242        $returned[]=array(
1243          'mode'  => 'item',
1244          'plugin' => $clausesItems[$itemNumber[0]]['plugin'],
1245          'valueWhere' => ($clausesItems[$itemNumber[0]]['where']!='')?" (".$clausesItems[$itemNumber[0]]['where'].") ":'',
1246          'valueHaving' => ($clausesItems[$itemNumber[0]]['having'])?" (".$clausesItems[$itemNumber[0]]['having'].") ":'',
1247        );
1248      }
1249    }
1250
1251    if(count($returned)>0)
1252    {
1253      if(strtolower(trim($operator))=='and')
1254      {
1255        $tId=0;
1256        foreach($returned as $key=>$val)
1257        {
1258          if($tId>0) $returnedS.=" JOIN ";
1259
1260          if($val['mode']=='item')
1261          {
1262            $returnedS.="(SELECT DISTINCT ".call_user_func(Array('RBCallBack'.$val['plugin'], 'getImageId'))." AS imageId
1263                          FROM ".call_user_func(Array('RBCallBack'.$val['plugin'], 'getFrom'));
1264            if($val['valueWhere']!='') $returnedS.=" WHERE ".$val['valueWhere'];
1265            if($val['valueHaving']!='')
1266              $returnedS.=" GROUP BY imageId
1267                            HAVING ".$val['valueHaving'];
1268            $returnedS.=") t".self::$tGlobalId." ";
1269          }
1270          else
1271          {
1272            $returnedS.="(".$val['value'].") t".self::$tGlobalId." ";
1273          }
1274
1275          if($tId>0) $returnedS.=" ON t".(self::$tGlobalId-1).".imageId = t".self::$tGlobalId.".imageId ";
1276          $tId++;
1277          self::$tGlobalId++;
1278        }
1279        $returnedS="SELECT DISTINCT '$requestNumber', t".(self::$tGlobalId-$tId).".imageId FROM ".$returnedS;
1280      }
1281      else
1282      {
1283        foreach($returned as $key=>$val)
1284        {
1285          if($returnedS!='') $returnedS.=" UNION DISTINCT ";
1286
1287          if($val['mode']=='item')
1288          {
1289            $returnedS.="SELECT DISTINCT '$requestNumber', t".self::$tGlobalId.".imageId
1290                          FROM (SELECT ".call_user_func(Array('RBCallBack'.$val['plugin'], 'getImageId'))." AS imageId
1291                                FROM ".call_user_func(Array('RBCallBack'.$val['plugin'], 'getFrom'));
1292            if($val['valueWhere']!='') $returnedS.=" WHERE ".$val['valueWhere'];
1293            if($val['valueHaving']!='')
1294              $returnedS.=" GROUP BY imageId
1295                            HAVING ".$val['valueHaving'];
1296            $returnedS.=") t".self::$tGlobalId." ";
1297          }
1298          else
1299          {
1300            $returnedS.="SELECT DISTINCT '$requestNumber', t".self::$tGlobalId.".imageId FROM (".$val['value'].") t".self::$tGlobalId;
1301          }
1302
1303          self::$tGlobalId++;
1304        }
1305      }
1306    }
1307
1308    return($returnedS);
1309  }
1310
1311
1312  /**
1313   * convert a list of images to HTML
1314   *
1315   * @param Array $imagesList : list of images id & associated datas
1316   * @return String : list formatted into HTML code
1317   */
1318  static protected function toHtml($imagesList)
1319  {
1320    global $template;
1321
1322    $template->set_filename('result_items',
1323                dirname(dirname(__FILE__)).'/templates/GPCRequestBuilder_result.tpl');
1324
1325
1326
1327    $template->assign('datas', $imagesList);
1328
1329    return($template->parse('result_items', true));
1330  }
1331
1332
1333  /**
1334   * returns allowed (or not allowed) categories for a user
1335   *
1336   * used the USER_CACHE_TABLE if possible
1337   *
1338   * @param Integer $userId : a valid user Id
1339   * @return String : IN(...), NOT IN(...) or nothing if there is no restriction
1340   *                  for the user
1341   */
1342  public function getUserCategories($userId)
1343  {
1344/*
1345    $returned='';
1346    if($user['forbidden_categories']!='')
1347    {
1348      $returned=Array(
1349        'JOIN' => 'AND ('.IMAGE_CATEGORY.'.category_id NOT IN ('.$user['forbidden_categories'].') ) ',
1350        'FROM' => IMAGE_CATEGORY
1351      );
1352
1353
1354    }
1355    *
1356    *
1357    */
1358  }
1359
1360
1361  /**
1362   * display search page
1363   *
1364   * @param Array $filter : an array of string ; each item is the name of a
1365   *                        registered plugin
1366   *                        if no parameters are given, no filter is applied
1367   *                        otherwise only plugin wich name is given are
1368   *                        accessible
1369   */
1370  static public function displaySearchPage($filter=array())
1371  {
1372    global $template, $lang;
1373
1374    if(is_string($filter)) $filter=array($filter);
1375    $filter=array_flip($filter);
1376
1377    GPCCore::addHeaderJS('jquery.ui', 'themes/default/js/ui/packed/ui.core.packed.js');
1378    GPCCore::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/packed/ui.dialog.packed.js');
1379    GPCCore::addHeaderJS('gpc.pagesNavigator', 'plugins/'.$baseName.'/js/pagesNavigator'.GPCCore::getMinified().'.js');
1380    GPCCore::addHeaderJS('gpc.rbSearch', 'plugins/'.$baseName.'/js/rbSearch'.GPCCore::getMinified().'.js');
1381
1382
1383    $template->set_filename('gpc_search_page',
1384                dirname(dirname(__FILE__)).'/templates/GPCRequestBuilder_search.tpl');
1385
1386    $registeredPlugin=self::getRegistered();
1387    $dialogBox=Array();
1388    foreach($registeredPlugin as $key=>$val)
1389    {
1390      if(array_key_exists($key, $registeredPlugin) and
1391         (count($filter)==0 or array_key_exists($key, $filter)))
1392      {
1393        if(file_exists($registeredPlugin[$key]['fileName']))
1394        {
1395          include_once($registeredPlugin[$key]['fileName']);
1396
1397          $dialogBox[]=Array(
1398            'handle' => $val['name'].'DB',
1399            'dialogBoxClass' => call_user_func(Array('RBCallBack'.$key, 'getInterfaceDBClass')),
1400            'label' => call_user_func(Array('RBCallBack'.$key, 'getInterfaceLabel')),
1401            'content' => call_user_func(Array('RBCallBack'.$key, 'getInterfaceContent')),
1402          );
1403        }
1404      }
1405    }
1406
1407    $datas=Array(
1408      'dialogBox' => $dialogBox,
1409      'themeName' => defined('IN_ADMIN')?$template->get_themeconf('name'):'',
1410    );
1411
1412    $template->assign('datas', $datas);
1413
1414    return($template->parse('gpc_search_page', true));
1415  } //displaySearchPage
1416
1417}
1418
1419
1420?>
Note: See TracBrowser for help on using the repository browser.