Dotclear

source: inc/admin/class.dc.filter.php @ 886:0aace9ddf8a1

Revision 886:0aace9ddf8a1, 19.9 KB checked in by franck <carnet.franck.paul@…>, 13 years ago (diff)

Oops, should works too with standard admin modules

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12
13
14/**
15@ingroup DC_CORE
16@nosubgrouping
17@brief Interface to add extra data to filterset.
18
19Note : the instance will be cloned to ensure dual filter edit fields / displayed fields
20Be sure to enable correct object cloning then, using the __clone method
21*/
22interface dcFilterExtraInterface {
23     /**
24     Return extra data to display in right column
25     
26     @param    core      <b>dcCore</b>       Dotclear core reference
27     @param    form_prefix    <b>string</b>       form prefix to use for parameters
28     */
29     public function getFormContent();
30
31     /**
32     Set dedicated data from form submission
33     (either $_GET or $_POST depending on the context
34     
35     @param    data      <b>array</b>        Data to retrieve information from
36     */
37     public function initializeFromData($data);
38     
39     /**
40     Save data to configuration
41     */
42     public function save();
43     
44     /**
45     Load data from configuration
46     */
47     public function load();
48         
49     /**
50     Update query parameters with given settings
51     @param    params         <b>ArrayObject</b>       Params being sent to query
52     */
53     public function applyFilters($params);
54     
55     
56     /**
57     Update parameters that will be used for inter-forms communications
58     (either query string or hidden fields).
59     The associative has to be updated with $param['key']='value'
60     @param    params         <b>ArrayObject</b>       Params to update
61     */
62     public function updateRequestParams($params);
63}
64
65/**
66@ingroup DC_CORE
67@nosubgrouping
68@brief Dotclear FilterSet class.
69
70Dotclear FilterSet handles filters and columns when displaying items lists.
71*/
72class dcFilterSet {
73
74     protected $lfilters;          /// <b>array</b> lists of defined filters
75     protected $efilters;          /// <b>array</b> lists of defined filters
76     protected $form_prefix;       /// <b>string</b> displayed form prefix
77     protected $action;            /// <b>string</b> form action page
78     protected $hideform;          /// <b>boolean</b> start form display hidden by default or not
79     protected $lextra;            /// <b>string</b> columns form
80     protected $eextra;            /// <b>string</b> columns form
81     protected $name;              /// <b>string</b> fieldset name
82     
83     /**
84     Inits dcFilterSet object
85     
86     @param    core      <b>dcCore</b>       Dotclear core reference
87     @param    form_prefix    <b>string</b>       form prefix to use for parameters
88     */
89     public function __construct($name,$action,$form_prefix="f_") {
90          $this->name = $name;
91          $this->form_prefix=$form_prefix;
92          $this->lfilters = new ArrayObject();
93          $this->efilters = new ArrayObject();
94          $this->action = $action;
95          $this->lextra = null;
96          $this->eextra = null;
97          $this->filtered = false;
98     }
99     
100     /**
101     Adds a new filter to list
102     
103     @param    filter         <b>dcFilter</b>          the filter to add
104     */
105     public function addFilter (Filter $filter) {
106          $filter->setFormPrefix($this->form_prefix);
107          $filter->setFilterSet($this);
108          $this->efilters[$filter->id] = $filter;
109          $this->lfilters[$filter->id] = clone $filter;
110          return $this;
111     }
112     
113     /**
114     Saves user filters to preferences
115     */
116     protected function saveFilters() {
117          $ser = array();
118          $ws = $GLOBALS['core']->auth->user_prefs->addWorkspace('filters');
119          $data = new ArrayObject();
120          $data= $this->getFiltersAsParams($this->efilters);
121          $ws->put($this->name,serialize($data->getArrayCopy()),'string');
122          return $data;
123     }
124     
125     /**
126     Loads user filters from preferences
127     */
128     protected function loadFilters() {
129          $ws = $GLOBALS['core']->auth->user_prefs->addWorkspace('filters');
130          $data = (!is_null($ws->{$this->name})) ? unserialize($ws->{$this->name}) : array();
131          if (is_array($data))
132               return $data;
133          else
134               return array();
135     }
136     
137     /**
138     Updates filters values according to form_data
139     To be called before any call to display() or getForm()
140     
141     @param    form_data <b>array</b>   form values (usually $_GET or $_POST)
142     */
143     protected function initializeFromData ($filters, $extra, $form_data) {
144          $this->hideform = true;
145          foreach ($filters as $filter) {
146               $filter->initializeFromData ($form_data);
147          }
148          if ($extra != null) {
149               $extra-> initializeFromData ($form_data);
150          }
151     }
152     
153     /**
154     Defines additional form in layout (right column)
155     
156     @param    html <b>string</b>       the code to add
157     */
158     public function setExtra($extra)
159     {
160          $this->lextra = $extra;
161          $this->eextra = clone $extra;
162         
163     }
164     
165     /**
166     Returns form fields as hidden fields
167     
168     @return   <b>string</b>  the corresponding html code
169     */
170     public function getFormFieldsAsHidden() {
171          $ret='';
172          $arr = new ArrayObject();
173          foreach ($this->lfilters as $f) {
174               if ($f->isEnabled())
175                    $f->updateRequestParams($arr);
176          }
177          if ($this->lextra != null) {
178               $this->lextra->updateRequestParams($arr);
179          }
180          foreach ($arr as $k=>$v) {
181               $ret.= form::hidden(array($k),$v);
182          }
183          $queryParams = $this->getFiltersAsParams($this->lfilters);
184          if ($this->lextra != null) {
185               $this->lextra->updateRequestParams($queryParams);
186          }
187          $ret .= form::hidden(array($this->form_prefix."query"), http_build_query($queryParams));
188          return $ret;
189     }
190
191     /**
192     Sets up filterset from $get and $post parameters
193     
194     */
195     public function setup($get,$post) {
196          /* Use cases :
197               (1) $post not empty for formfilter fields :
198                    * efilters are set from $post
199                    * lfilters are set from $get
200                    * keep filters div shown
201               (2) $post empty :
202                    * both efilters and lfilters are set from $get
203                    * hide filter div
204          */
205          $action = false;
206          $allowed_actions = array('clear_filters','add','del_','apply','reset');
207          // Fetch each $post parameter to see whether filters are concerned.
208          // Only 1 action at a time is allowed.
209          foreach ($post as $k => $v) {
210               if (strpos($k,$this->form_prefix)===0) {
211                    $tmp = substr($k,strlen($this->form_prefix));
212                    foreach ($allowed_actions as $a) {
213                         if (strpos($tmp,$a)===0) {
214                              $action = $tmp;
215                              break;
216                         }
217                    }
218               }
219          }
220          if ($action !== false) {
221               // Use case (1)
222               if ($action != 'clear_filters' && $action != 'reset')  {
223                    $this->initializeFromData($this->efilters,$this->eextra, $post);
224                    if ($action == 'add'){
225                         if (isset($post['add_filter']) 
226                              && isset($this->efilters[$post['add_filter']])) {
227                         $this->efilters[$post['add_filter']]->add();
228                         }
229                    } elseif (strpos($action,'del_') === 0) {
230                         $count = preg_match('#del_(.+)_([0-9]+)#',$action,$match);
231                         if (($count == 1) && isset($this->efilters[$match[1]])) {
232                              $this->efilters[$match[1]]->remove($match[2]);
233                         }
234                    } elseif ($action=="apply") {
235                         $data = $this->saveFilters();
236                         if ($this->eextra != null) {
237                              $this->eextra->save();
238                         }
239                         $query = http_build_query($data,'','&');
240                         if ($query != '') {
241                              $query = (strpos($this->action,'?') === false ? '?' : '&').$query;
242                         }
243                         http::redirect($this->action.$query);
244                         exit;
245                    }
246               }
247               if (isset($post[$this->form_prefix."query"])) {
248                    parse_str($post[$this->form_prefix."query"],$out);
249                    $this->initializeFromData($this->lfilters,$this->lextra, $out);
250                    if ($action == 'reset') {
251                         $this->initializeFromData($this->efilters,$this->eextra, $out);
252                    }
253               }
254               $this->hideform=false;
255          } else {
256               // Use case (2)
257               $load_from_settings = true;
258               foreach($get as $k=>$v) {
259                    if (strpos($k,$this->form_prefix)===0) {
260                         $load_from_settings=false;
261                         break;
262                    }
263               }
264               if ($load_from_settings) {
265                    $get = new ArrayObject(array_merge($this->loadFilters(),$get));
266               }
267               $this->initializeFromData($this->efilters, $this->eextra, $get);
268               $this->initializeFromData($this->lfilters, $this->lextra, $get);
269
270          }
271     }
272     /**
273     Retrieves filterset generated form
274     
275     @param    method    <b>string</b>       form method to use (default: "get")
276     */
277     public function getForm() {
278          $ret = '';
279         
280          if ($this->hideform) {
281               $formclass = ' class="hidden"';
282               $toggleclass = '';
283          } else {
284               $formclass='';
285               $toggleclass = ' class="opened"';
286          }
287         
288          $ret .= '<p>'.
289               '<a href="#" id="toggle-filters"'.$toggleclass.'>'.
290               __('Toggle filters and display options').
291               '</a></p>'.
292               '<div class="two-cols">'.
293               '<form id="filters" action="'.$this->action.'" method="post"'.$formclass.'>'.
294               '<div class="col70">'.
295               '<h3>'.__('Entries filters').'</h3>'.
296               '<table summary="'.__('Query filters').'" id="tfilters">'.
297               '<tbody>';
298          $count=0;
299          $form_combo=array();
300          $form_combo['-']='';
301          if (count($this->efilters)) {
302               foreach ($this->efilters as $filter) {
303                    if ($filter->isEnabled()) {
304                         $ret .= $filter->getFormLine();
305                    }
306                    $form_combo[$filter->name]=$filter->id;
307                    $count++;
308               }
309          }
310          $ret .= '</tbody></table>'.
311               '<h3 class="margintop">'.__('Add a filter').'</h3>'.
312               '<p id="available_filters">'.
313               form::combo("add_filter",$form_combo).
314               '<input type="submit" value=" + " title="'.__('Add this filter').'" name="'.$this->form_prefix.'add" />'.
315               '</p>'.
316               '<p class="clear"><input class="delete" type="submit" value="'.__('Delete all filters').'" name="'.
317               $this->form_prefix.'clear_filters" />'.
318               '&nbsp;<input  type="submit" value="'.__('Reset').'" name="'.
319               $this->form_prefix.'reset" /></p>'.
320               '</div>';
321          if ($this->eextra != '') {
322               $ret .=
323                    '<div class="col30">'.
324                    $this->eextra->getFormContent().
325                    '</div>';
326          }
327          $queryParams = $this->getFiltersAsParams($this->lfilters);
328          if ($this->lextra != null) {
329               $this->lextra->updateRequestParams($queryParams);
330          }
331         
332          $ret .=
333               '<p class="clear margintop">'.
334               '<input type="submit" value="'.__('Apply filters and display options').
335               '" name="'.$this->form_prefix.'apply" /></p>'.
336               form::hidden(array($this->form_prefix."query"),http_build_query($queryParams)).
337               $GLOBALS['core']->formNonce().
338               '</form>'.
339               '</div>';
340          return $ret;
341     }
342     /**
343     Retrieves the filters values as parameters
344     
345     @param    filters   <b>array</b>   list of concerned filters
346     
347     @return   <b>array</b>   the array of parameters
348
349     */
350
351     protected function getFiltersAsParams($filters) {
352          $arr = new ArrayObject();
353          foreach ($filters as $f) {
354               if ($f->isEnabled())
355                    $f->updateRequestParams($arr);
356          }
357          return $arr;
358     }
359     
360     public function getFiltersText() {
361          $ret = '<p>'.__('Currently applied filters :').'</p><ul>';
362          foreach ($this->lfilters as $f) {
363               if ($f->isEnabled())
364                    $ret .= '<li>'.$f->getAsText().'</li>'."\n";
365          }
366          $ret .= '</ul>';
367          return $ret;
368     }
369     
370     /**
371     Displays required fieldset http header
372     To be called in page header, of course.
373     */
374     public function header() {
375          $ret = dcPage::jsLoad('js/filters.js');
376          foreach($this->efilters as $f) {
377               $ret .= $f->header();
378          }
379          return $ret;
380     }
381     
382     
383     /**
384     Displays the fieldset
385     */
386     public function display() {
387          echo $this->getForm();
388     }
389
390     /**
391     Applies fieldset and return resulting parameters for request
392     
393     @param    method    <b>string</b>       form method to use (default: "get")
394     @param    method    <b>string</b>       form method to use (default: "get")
395     
396     */
397     public function applyFilters($params) {
398          foreach ($this->lfilters as $filter) {
399               if ($filter->isEnabled()) {
400                    $filter->applyFilter($params);
401                    $this->filtered = true;
402               }
403          }
404          if ($this->lextra != null) {
405               $this->lextra->applyFilters($params);
406          }
407          return $this->filtered;
408     }
409     
410     public function getDelName($field_id,$pos) {
411          return $this->form_prefix.'del_'.$field_id.'_'.$pos;
412     }
413}
414
415
416/**
417@ingroup DC_CORE
418@nosubgrouping
419@brief abstract filter class.
420
421Dotclear Filter handles administration filters for each list
422A filter fills in a parameter array, as defined in dcBlog class
423*/
424abstract class Filter {
425     public $filterset;            ///<b>string</b> filterset parent
426     public $id;                        ///<b>string</b> field id (local to fieldset)
427     public $name;                 ///<b>string</b> filter name
428     public $desc;                 ///<b>string</b> field description
429     protected $request_param;     ///<b>string</b> resulting parameter array key
430     protected $enabled;           ///<b>string</b> true if filter is enabled
431     protected $values;            ///<b>array</b> possible filter values
432     public $field_id;             ///<b>string</b> field id (global to the page)
433     
434     /**
435     Inits Filter object
436     
437     @param    id        <b>string</b>  field id
438     @param    form_prefix    <b>string</b>       form prefix to use for parameters
439     */
440     public function __construct ($id,$name,$desc,$request_param) {
441          $this->id = $id;
442          $this->name=$name;
443          $this->desc = $desc;
444          $this->request_param = $request_param;
445          $this->enabled=false;
446          $this->values = array();
447          $this->field_id = $this->id;
448     }
449     
450     /**
451     Defines the filterset containing this filter
452     
453     @param    prefix         <b>dcFilterset</b>  the filterset
454     */
455     public function setFilterSet($fs) {
456          $this->filterset = $fs;
457     }
458     
459     /**
460     Defines form prefix for filter
461     
462     @param    prefix         <b>string</b>  the form prefix
463     */
464     public function setFormPrefix($prefix) {
465          $this->field_id = $prefix.$this->id;
466     }
467     
468     /**
469     Get a field id
470     
471     @param    pos       <b>integer</b> position of field, in case of multiple field (0 if only 1 field set, default value)
472     @return   <b>string</b> The field ID
473     */
474     protected function getFieldId($pos=0) {
475          if ($pos == 0) {
476               return $this->field_id;
477          } else {
478               return $this->field_id.'_'.$pos;
479          }
480     }
481     
482     /**
483     Tells whether the filter is enabled or not
484     
485     @return   <b>boolean</b> true if enabled, false otherwise
486     */
487     public function isEnabled() {
488          return $this->enabled;
489     }
490     
491     /**
492     Adds the current filter to the list
493     */
494     public function add() {
495          // By default here, only 1 value allowed. Simply enable the filter
496          $this->enabled = true;
497     }
498     
499     /**
500     Removes a value from filter
501     */
502     public function remove($pos) {
503          if (isset($this->values[$pos])) {
504               array_splice($this->values,$pos,1);
505               $this->enabled = (count($this->values)!=0);
506          }
507     }
508     
509     /**
510     Returns HTML code for form field
511     
512     @param    pos       <b>integer</b> position of the field to display
513                                             (in case of multiple values)
514     @return <b>string</b> the html code
515     */
516     abstract protected function getFormFields($pos=0);
517     
518     /**
519     Extract values from data (data being an array, such as $_GET or $_POST)
520     
521     @param    $data     <b>array</b>   data to parse
522     @return   <b>array</b>   field values
523     
524     */
525     protected function getValuesFromData($data) {
526          $count=0;
527          $arr = array();
528          while (isset($data[$this->getFieldId($count)])) {
529               $arr[$count] = $data[$this->getFieldId($count)];
530               $count++;
531          }
532          return $arr;
533     }
534     
535     public function initializeFromData($form_data) {
536          $this->values = $this->getValuesFromData($form_data);
537          $this->enabled = (count($this->values)!=0);
538     }
539     
540     /**
541     Returns HTML code for the hole filter lines
542     
543     @return <b>string</b> the html code
544     */
545     
546     public function getFormLine() {
547          $ret='';
548          for ($cur=0; $cur < count($this->values); $cur++) {
549               $ret .= '<tr class="'.$this->id.'">';
550               $del_id = $this->filterset->getDelName($this->id,$cur);
551               $ret .= '<td><input id="'.$del_id.'" class="delete" '.
552                         'type="submit" title="Delete the following filter : " value=" - " name="'.$del_id.'"/></td>'.
553                         $this->getFormFields($cur);
554               $ret .= '</tr>';
555          }
556          return $ret;
557     }
558     
559     public function updateRequestParams($arr) {
560          for ($cur=0; $cur < count($this->values); $cur++) {
561               $arr[$this->getFieldId($cur)]=$this->values[$cur];
562          }
563     }
564     
565     /**
566     Convert filter values into a $param filter, used for the upcoming SQL request
567     
568     @param <b>ArrayObject</b> the parameters array to enrich
569     */
570     public function applyFilter($params) {
571     }
572     
573     public function setValues($value) {
574          $this->values = $value;
575     }
576     
577     public function getValue() {
578          return $this->values;
579     }
580
581     public function header() {
582          return '';
583     }
584     
585     public abstract function getAsText();
586
587     
588}
589
590/**
591@ingroup DC_CORE
592@nosubgrouping
593@brief abstract filter class.
594
595Handle combo filter on admin side. Can be single or multi-valued
596*/
597class comboFilter extends Filter {
598     protected $options;
599     protected $default;
600     protected $no_value;
601     protected $verb;
602     protected $extra;
603     
604     public function __construct($id,$name,$desc,$request_param,$options,$extra=array()) {
605          parent::__construct($id,$name,$desc,$request_param);
606          $this->options = $options;
607          $this->extra = $extra;
608          $this->verb = "is";
609          $this->values=array();
610     }
611     
612     protected function getValuesFromData($data) {
613          $val = parent::getValuesFromData($data);
614          if (isset($data[$this->field_id.'_v'])) {
615               $verb = $data[$this->field_id.'_v'];
616          } else {
617               $verb = "is";
618          }
619          $arr = array(
620               'values' => $val,
621               'verb' => $verb
622          );
623          return $arr;
624     }
625     
626     public function add() {
627          parent::add();
628          if (isset($this->extra['singleval']) && (count($this->values) > 0))
629               return;
630          $this->values[]=current($this->options);
631     }
632     
633     public function getType() {
634          return "combo";
635     }
636
637     public function serialize() {
638          $data = parent::serialize();
639          $data['verb'] = $this->verb;
640          return $data;
641     }
642     
643     public function unserialize ($data) {
644          parent::unserialize($data);
645          $this->verb = $data['verb'];
646     }
647     
648     public function initializeFromData($form_data) {
649          $arr = $this->getValuesFromData($form_data);
650          $this->values = $arr['values'];
651          $this->verb = $arr['verb'];
652          $this->enabled = (count($this->values) != 0);
653     }
654
655     public function getFormFields($pos=0) {
656          if ($pos == 0) {
657               $ret = '<td id="'.$this->getFieldId($pos).'" title="'.$this->desc.'" class="filter-title">'.
658                    ''.$this->desc.' : </td>'.
659                    '<td>'.
660                    form::combo($this->field_id.'_v',
661                         array(__('is')=>'is',__('is not')=>'isnot'),$this->verb,'','',
662                         false,'title="'.sprintf(__('%s is or is not'),$this->desc).'"').
663                    '</td>';
664          } else {
665               $ret = '<td id="'.$this->getFieldId($pos).'" title="or" colspan="2" class="or">'.
666                    __('or').' : </td>';
667          };
668          $ret .= '<td>'.form::combo($this->getFieldId($pos),$this->options,$this->values[$pos],
669               '','',false,'title="'.__('Choose an option').'"').'</td>';
670          return $ret;
671     }
672     
673     public function updateRequestParams($arr) {
674          parent::updateRequestParams($arr);
675         
676          $arr[$this->field_id.'_v']=$this->verb;
677     }
678     
679     public function applyFilter($params) {
680          $attr = $this->request_param;
681          if ($this->verb != "is") {
682               $params[$attr."_not"] = true;
683          }
684          if (isset($this->extra['singleval']))
685               $params[$attr]=$this->values[0];
686          else
687               $params[$attr]=$this->values;
688}
689     
690     public function getValues() {
691          return array_merge($this->values,array($this->field_id.'_v',$this->verb));
692     }
693     
694     public function getAsText() {
695          $arr=array();
696          foreach ($this->values as $value) {
697               $arr[]=array_search($value,$this->options);
698          }
699          return sprintf("%s %s %s",$this->desc,$this->verb,join(',',$arr));
700     }
701}
702
703
704class categoryFilter extends comboFilter {
705     public function getAsText() {
706          $arr=array();
707          foreach ($this->values as $value) {
708               $cat=array_search($value,$this->options);
709               $arr[]=preg_replace("#^.* ([^ ]+) .*$#",'$1',$cat);
710          }
711          return sprintf("%s %s %s",$this->desc,$this->verb,join(',',$arr));
712     }
713}
714/**
715@ingroup DC_CORE
716@nosubgrouping
717@brief abstract filter class.
718
719Handle boolean filter on admin side.
720*/
721class booleanFilter extends Filter {
722     protected $options;
723     
724     public function __construct($id,$name,$desc,$request_param,$options) {
725          parent::__construct($id,$name,$desc,$request_param);
726          $this->options = $options;
727          $this->values=array();
728     }
729     
730     
731     public function getType() {
732          return "boolean";
733     }
734     public function add() {
735          parent::add();
736          $this->values=current($this->options);
737     }
738
739     public function getFormFields($pos=0) {
740          return '<td colspan="2">'.$this->desc.'</td><td>'.
741               form::combo($this->getFieldId($pos),$this->options,$this->values[$pos],
742                    '','',false,'title="'.__('Choose an option').'"').'</td>';
743     }
744     
745     public function applyFilter($params) {
746          $params[$this->request_param]=$this->values[0];
747     }
748     
749     public function getAsText() {
750          return sprintf("%s %s",$this->desc,$this->values[0]);
751     }
752}
753
754
755class textFilter extends Filter {
756     protected $size;
757     protected $max;
758     
759     public function __construct($id,$name,$desc,$request_param,$size,$max) {
760          parent::__construct($id,$name,$desc,$request_param);
761          $this->size = $size;
762          $this->max = $max;
763          $this->values=array();
764     }
765     
766     
767     public function getType() {
768          return "text";
769     }
770     public function add() {
771          parent::add();
772          $this->values[]='';
773     }
774
775     public function getFormFields($pos=0) {
776          return '<td colspan="2">'.$this->desc.'</td><td>'.
777               form::field($this->getFieldId($pos),$this->size,$this->max,html::escapeHTML($this->values[0])).
778               '</td>';
779     }
780     
781     public function applyFilter($params) {
782          $params[$this->request_param]=$this->values[0];
783     }
784     
785     public function setValues($value) {
786          parent::setValues(array($value));
787     }
788
789     public function getAsText() {
790          return sprintf("%s %s",$this->desc,$this->values[0]);
791     }
792     
793}
794
795
796?>
Note: See TracBrowser for help on using the repository browser.

Sites map