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

Revision 9009, 43.2 KB checked in by grum, 9 years ago (diff)

release 3.4.1
bug:2156

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