Dotclear

source: inc/admin/class.dc.filter.php @ 1152:fbd922f6ed09

Revision 1152:fbd922f6ed09, 15.5 KB checked in by Dsls <dsls@…>, 12 years ago (diff)

form filters reloaded, first try for lists (to be completed)
form fields now support multiple values.

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 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
13if (!defined('DC_RC_PATH')) { return; }
14
15
16class dcFilterSet extends dcForm {
17     protected $filters;      /// <b>array</b> lists of currently applied filters
18     protected $static_filters;
19     protected $all_filters;
20     protected $form_prefix;       /// <b>string</b> displayed form prefix
21     protected $action;            /// <b>string</b> form action page
22     protected $hideform;          /// <b>boolean</b> start form display hidden by default or not
23     protected $name;              /// <b>string</b> filterset name
24     protected $core;
25
26     public static function __init__($env) {
27          $env->getExtension('dc_form')->addTemplate('@forms/formfilter_layout.html.twig');
28          $env->addFunction(
29               new Twig_SimpleFunction(
30                    'filterset',
31                    'dcFilterSet::renderFilterSet',
32                    array(
33                         'is_safe' => array('html'),
34                         'needs_context' => true,
35                         'needs_environment' => true
36          )));
37     }
38     
39     public static function renderFilterSet($env,$context,$name,$attributes=array())
40     {
41          $context['filtersetname']=$name;
42          echo $env->getExtension('dc_form')->renderWidget(
43               'filterset',
44               $context
45          );
46     }
47     /**
48     Inits dcFilterSet object
49     
50     @param    core      <b>dcCore</b>       Dotclear core reference
51     @param    form_prefix    <b>string</b>       form prefix to use for parameters
52     */
53     public function __construct($core,$name,$action,$form_prefix="f_") {
54          $this->form_prefix=$form_prefix;
55          $this->filters = new ArrayObject();
56          $this->static_filters = new ArrayObject();
57          $this->all_filters = new ArrayObject();
58          $this->action = $action;
59          $this->filtered = false;
60          parent::__construct($core,$name,$action,'POST');
61          $this->id = "filters";
62     }
63
64     public function setup() {
65          $form_combo = array();
66          $form_combo['-'] = '';
67          foreach ($this->all_filters as $filter) {
68               $filter->init();
69          }
70          foreach ($this->filters as $filter) {
71               $form_combo[$filter->id]=$filter->name;
72          }
73          $p = $this->form_prefix;
74          $this
75               ->addField (
76                    new dcFieldCombo ($p.'add_filter','',$form_combo,array(
77                    )))
78               ->addField (
79                    new  dcFieldSubmit($p.'add',__('Add this filter'),array(
80                    )))
81               ->addField (
82                    new dcFieldSubmit($p.'clear_filters',__('Delete all filters'),array(
83                    )))
84               ->addField (
85                    new dcFieldSubmit($p.'apply',__('Apply filters and display options'),array(
86                    )))
87               ->addField (
88                    new dcFieldSubmit($p.'reset',__('Reset'),array(
89                    )))
90          ;
91          $this->setupFields();
92          /* Use cases :
93               (1) $_POST not empty for formfilter fields :
94                    * efilters are set from $_POST
95                    * lfilters are set from $_GET
96                    * keep filters div shown
97               (2) $_POST empty :
98                    * both efilters and lfilters are set from $_GET
99                    * hide filter div
100          */
101          $action = false;
102          //$allowed_actions = array('clear_filters','add','del_.*','apply','reset');
103          $allowed_actions = '#^(clear_filters|add|del_.*|apply|reset)$#';
104          // Fetch each $_POST parameter to see whether filters are concerned.
105          // Only 1 action at a time is allowed.
106
107          foreach ($_POST as $k => $v) {
108               if (strpos($k,$this->form_prefix)===0) {
109                    $tmp = substr($k,strlen($this->form_prefix));
110                    $count = preg_match($allowed_actions,$tmp,$match);
111                    if ($count==1) {
112                         $action = $match[1];
113                         break;
114                    }
115               }
116          }
117
118          if ($action !== false) {
119               // Use case (1)
120               if ($action != 'clear_filters' && $action != 'reset')  {
121                    $this->setupEditFilters($this->all_filters,$_POST);
122                    if ($action == 'add'){
123                         $fname = $p.'add_filter';
124                         if (isset($_POST[$fname])
125                              && isset($this->filters[$_POST[$fname]])) {
126                         $this->filters[$_POST[$fname]]->add();
127                         }
128                    } elseif (strpos($action,'del_') === 0) {
129                         $count = preg_match('#del_(.+)_([0-9]+)#',$action,$match);
130                         if (($count == 1) && isset($this->filters[$match[1]])) {
131                              $this->filters[$match[1]]->remove($match[2]);
132                         }
133                    } elseif ($action=="apply") {
134                         $data = $this->saveFilters();
135                         $query = http_build_query($data,'','&');
136                         if ($query != '') {
137                              $query = (strpos($this->action,'?') === false ? '?' : '&').$query;
138                         }
139                         http::redirect($this->action.$query);
140                         exit;
141                    }
142               }
143               if (isset($_POST[$p."query"])) {
144                    parse_str($_POST[$p."query"],$out);
145                    $this->setupAppliedFilters($this->all_filters,$out);
146                    if ($action == 'reset') {
147                         $this->setupEditFilters($this->all_filters,$out);
148                    } elseif ($action == 'clear_filters') {
149                         $this->setupEditFilters($this->static_filters,$out);
150                         foreach ($this->filters as $f) {
151                              $f->cleanup();
152                         }
153                    }
154               }
155               $this->hideform=false;
156          } else {
157               // Use case (2)
158               $load_from_settings = true;
159               foreach($_GET as $k=>$v) {
160                    if (strpos($k,$this->form_prefix)===0) {
161                         $load_from_settings=false;
162                         break;
163                    }
164               }
165               $get = $_GET;
166               if ($load_from_settings) {
167                    $get = new ArrayObject(array_merge($this->loadFilters(),$get));
168               }
169               $this->setupEditFilters($this->all_filters,$get);
170
171               $this->setupAppliedFilters($this->all_filters,$get);
172          }
173          foreach ($this->static_filters as $f) {
174               if (!$f->isEnabled()) {
175                    $f->add();
176               }
177          }
178          $queryParams = $this->getAppliedFilters();
179          $this->addField(
180               new dcFieldHidden($this->form_prefix.'query',
181                    http_build_query($queryParams)));
182          $this->core->tpl->addGlobal('filterset_'.$this->name,$this->getContext());
183     }
184
185     /**
186     Saves user filters to preferences
187     */
188     protected function saveFilters() {
189          $ser = array();
190          $ws = $GLOBALS['core']->auth->user_prefs->addWorkspace('filters');
191          $data = new ArrayObject();
192          $data= $this->serialize();
193          $ws->put($this->name,serialize($data->getArrayCopy()),'string');
194          return $data;
195     }
196
197     /**
198     Loads user filters from preferences
199     */
200     protected function loadFilters() {
201          $ws = $GLOBALS['core']->auth->user_prefs->addWorkspace('filters');
202          $data = (!is_null($ws->{$this->name})) ? unserialize($ws->{$this->name}) : array();
203          if (is_array($data))
204               return $data;
205          else
206               return array();
207     }
208
209     /**
210     Updates filters values according to form_data
211     To be called before any call to display() or getForm()
212     
213     @param    form_data <b>array</b>   form values (usually $_GET or $_POST)
214     */
215     protected function setupEditFilters ($filters,$form_data) {
216          $this->hideform = true;
217          foreach ($filters as $filter) {
218               $filter->setupFields ($form_data);
219          }
220     }
221     protected function setupAppliedFilters ($filters,$form_data) {
222          foreach ($filters as $filter) {
223               $filter->setupAppliedFilter ($form_data);
224          }
225     }
226     /**
227     Retrieves the filters values as parameters
228     
229     @param    filters   <b>array</b>   list of concerned filters
230     
231     @return   <b>array</b>   the array of parameters
232
233     */
234
235     protected function serialize() {
236          $arr = new ArrayObject();
237          foreach ($this->filters as $f) {
238               if ($f->isEnabled()) {
239                    $f->serialize($arr);
240               }
241          }
242          foreach ($this->static_filters as $f) {
243               $f->serialize($arr);
244          }
245          return $arr;
246     }
247     /**
248     Adds a new filter to list
249     
250     @param    filter         <b>dcFilter</b>          the filter to add
251     */
252     public function addFilter (dcFilter $filter) {
253          $filter->setFormPrefix($this->form_prefix);
254          $filter->setFilterSet($this);
255          $this->all_filters[$filter->id] = $filter;
256          if ($filter->isStatic()) {
257               $this->static_filters[$filter->id] = $filter;
258          } else {
259               $this->filters[$filter->id] = $filter;
260          }
261          return $this;
262     }
263
264     public function getContext() {
265          $fcontext = new ArrayObject();
266          $sfcontext = new ArrayObject();
267          foreach ($this->filters as $f) {
268               if($f->isEnabled()) {
269                    $f->appendEditLines($fcontext);
270               }
271          }
272          foreach ($this->static_filters as $f) {
273               $f->appendEditLines ($sfcontext);
274          }
275          return array(
276               'active_filters' => $fcontext, 
277               'static_filters' => $sfcontext,
278               'prefix'=>$this->form_prefix);
279     }
280
281     protected function getAppliedFilters() {
282          $arr = new ArrayObject();
283          foreach ($this->all_filters as $f) {
284               if ($f->isApplied())
285                    $f->updateAppliedValues($arr);
286          }
287          return $arr;
288     }
289     /**
290     Applies fieldset and return resulting parameters for request
291     
292     @param    method    <b>string</b>       form method to use (default: "get")
293     @param    method    <b>string</b>       form method to use (default: "get")
294     
295     */
296     public function applyFilters($params) {
297          foreach ($this->all_filters as $filter) {
298               if ($filter->isApplied()) {
299                    $filter->applyFilter($params);
300                    $this->filtered = true;
301               }
302          }
303          return $this->filtered;
304     }
305
306     public function getDelName($field_id,$pos) {
307          return $this->form_prefix.'del_'.$field_id.'_'.$pos;
308     }
309
310}
311
312
313
314/**
315* dcFilter - describes an abstract filter
316*
317*/
318abstract class dcFilter  {
319     public $filterset;            ///<b>string</b> filterset parent
320     public $id;                        ///<b>string</b> field id (local to fieldset)
321     public $name;                 ///<b>string</b> filter name
322     public $desc;                 ///<b>string</b> field description
323     public $filter_id;            ///<b>string</b> field id (global to the page)
324     protected $request_param;     ///<b>string</b> resulting parameter array key
325     protected $field;             ///<b>array</b> currently edited values
326     protected $avalues;           ///<b>array</b> currently applied values
327     protected $static;
328     protected $options;
329     protected $multiple;
330
331     public function __construct ($id,$name,$desc,$request_param,$options=array()) {
332          $this->id                     = $id;
333          $this->name              =$name;
334          $this->desc              = $desc;
335          $this->request_param     = $request_param;
336          $this->avalues           = array();
337          $this->filter_id         = $this->id;
338          $this->static            = false;
339          $this->multiple          = false;
340          $this->options           = $options;
341          if (isset($options['static']) && $options['static']) {
342               $this->static       = true;
343          }
344          if (isset($options['multiple']) && $options['multiple']) {
345               $this->multiple          = true;
346          }
347     }
348
349     /**
350     Extract values from data (data being an array, such as $_GET or $_POST)
351     
352     @param    $data     <b>array</b>   data to parse
353     @return   <b>array</b>   field values
354     
355     */
356     protected function parseData($data) {
357          $arr = $this->field->parseValues($data);
358          return array('values' => $arr);
359     }
360
361     public function isStatic() {
362          return $this->static;
363     }
364
365     public function setupFields($data) {
366          $this->field->setup($data);
367     }
368
369
370     public function init() {
371     }
372
373     public function cleanup() {
374          $this->field->setValues(array());
375     }
376
377     public function setupAppliedFilter($data) {
378          $this->avalues = $this->parseData($data);
379     }
380
381     public function updateAppliedValues($arr) {
382          $arr[$this->filter_id] = $this->avalues['values'];
383     }
384
385     /**
386     Defines the filterset containing this filter
387     
388     @param    prefix         <b>dcFilterset</b>  the filterset
389     */
390     public function setFilterSet($fs) {
391          $this->filterset = $fs;
392     }
393     
394     /**
395     
396     Defines form prefix for filter
397     
398     @param    prefix         <b>string</b>  the form prefix
399     */
400     public function setFormPrefix($prefix) {
401          $this->filter_id = $prefix.$this->id;
402     }
403
404     /**
405     Tells whether the filter is enabled or not
406     
407     @return   <b>boolean</b> true if enabled, false otherwise
408     */
409     public function isEnabled() {
410          return count($this->field) != 0;
411     }
412     
413     protected abstract function addValue($value=NULL);
414
415     /**
416     Adds the current filter to the list
417     */
418     public function add() {
419          if (count($this->field) > 1 && !$this->multiple)
420               return;
421          $this->addValue();
422     }
423     
424     /**
425     Removes a value from filter
426     */
427     public function remove($pos) {
428          $values = $this->field->getValues();
429          if (isset($values[$pos])) {
430               $this->field->delValue($pos);
431          }
432
433     }
434
435     abstract protected function appendSingleLine($ctx,$pos);
436
437     public function appendEditLines($ctx) {
438          foreach ($this->field->getValues() as $cur => $f) {
439               $line = new ArrayObject();
440               $line['lineclass'] = $this->id;
441               $line['del_id'] = $this->filterset->getDelName($this->id,$cur);
442               $del = new dcFieldSubmit(
443                    $this->filterset->getDelName($this->id,$cur),
444                    '-',
445                    array(
446                         'attr' => array(
447                              'title' => __('Delete the following filter')))
448               );
449               $this->filterset->addField($del);
450               $this->appendSingleLine($line,$cur);
451               $ctx[]=$line;
452          }
453     }
454
455     public function serialize($arr) {
456          if (count($this->fields) == 1) {
457               $arr[$this->filter_id]=$this->field->getValue();
458          } else {
459               $arr[$this->filter_id]=$this->field->getValues();
460          }
461     }
462     
463     public function isApplied(){
464          return (count($this->avalues['values']) != 0);
465     }
466
467     /**
468     Convert filter values into a $param filter, used for the upcoming SQL request
469     
470     @param <b>ArrayObject</b> the parameters array to enrich
471
472    @return boolean true if a filter has been applied, false otherwise
473    */
474     public function applyFilter($params) {
475          return false;
476     }
477
478     public function header() {
479          return '';
480     }
481
482}
483
484
485
486class dcFilterText extends dcFilter {
487
488     public function init() {
489          $this->field = new dcFieldText(
490               $this->filter_id,
491               NULL);
492          $this->filterset->addField($this->field);
493          $this->multiple = false;
494     }
495
496
497     public function appendSingleLine($line,$pos) {
498          $line['ffield'] = $this->field->getName();
499          if ($this->static) {
500               $line['display_inline'] = true;
501          }
502
503          if ($pos == 0) {
504               $line['fwidget']='filter_text';
505               $line['desc']=$this->desc;
506          };
507     }
508
509     protected function addValue($value=NULL) {
510          if ($value === NULL) {
511               $value = '';
512          }
513          $this->field->addValue($value);
514     }
515
516     public function applyFilter($params) {
517          $params[$this->request_param]=$this->avalues['values'][0];
518     }
519     
520}
521/**
522@ingroup DC_CORE
523@nosubgrouping
524@brief abstract filter class.
525
526Handle combo filter on admin side. Can be single or multi-valued
527*/
528class dcFilterCombo extends dcFilter {
529     protected $combo;
530     
531     public function __construct($id,$name,$desc,$request_param,$combo,$options=array()) {
532          parent::__construct($id,$name,$desc,$request_param,$options);
533          $this->combo = $combo;
534     }
535     public function init() {
536          $this->field = new dcFieldCombo(
537               $this->filter_id,
538               NULL,
539               $this->combo);
540          $this->filterset->addField($this->field);
541     }
542
543     protected function addValue($value=NULL) {
544          if ($value === NULL) {
545               $value = current($this->combo);
546          }
547          $this->field->addValue($value);
548     }
549
550     public function appendSingleLine($line,$pos) {
551          if ($this->static) {
552               $line['display_inline'] = true;
553          }
554          $line['ffield'] = $this->field->getName();
555          $line['foffset'] = $pos;
556          if ($pos == 0) {
557               $line['fwidget']='filter_combo';
558               $line['desc']=$this->desc;
559          } else {
560               $line['fwidget']='filter_combo_cont';
561          };
562     }
563     
564     public function applyFilter($params) {
565          $attr = $this->request_param;
566          if ($this->multiple)
567               $params[$attr]=$this->avalues['values'];
568          else
569               $params[$attr]=$this->avalues['values'][0];
570     }
571
572}
573
574/**
575@ingroup DC_CORE
576@nosubgrouping
577@brief abstract filter class.
578
579Handle combo filter on admin side. Can be single or multi-valued
580*/
581class dcFilterRichCombo extends dcFilterCombo {
582     protected $verb;
583
584     public function init() {
585          parent::init();
586          $this->verb = new dcFieldCombo(
587               $this->filter_id.'_v', 
588               'is',
589               array(
590                    'is'=>__('is'),
591                    'isnot'=>__('is not'))
592          );
593          $this->filterset->addField($this->verb);
594     }
595
596     protected function parseData($data) {
597          $val = parent::parseData($data);
598          $v = $this->verb->parseValues($data);
599          if (isset($v[0]) && $v[0] === 'isnot')
600               $val['verb'] = 'isnot';
601          else
602               $val['verb'] ='is';
603          return $val;
604     }
605
606     public function setupFields($data) {
607          parent::setupFields($data);
608          $this->verb->setup($data);
609     }
610
611     public function updateAppliedValues($arr) {
612          parent::updateAppliedValues($arr);
613          $arr['verb'] = $this->verb->getValue();
614     }
615
616     public function appendSingleLine($line,$pos) {
617          parent::appendSingleLine($line,$pos);
618          if ($pos == 0) {
619               $line['fverb'] = $this->verb->getName();
620               $line['fwidget']='filter_richcombo';
621          } 
622     }
623     
624     public function serialize($arr) {
625          parent::serialize($arr);
626          $arr[$this->filter_id.'_v']=$this->verb->getValue();
627     }
628     
629     public function applyFilter($params) {
630          parent::applyFilter($params);
631          $attr = $this->request_param;
632          if ($this->avalues['verb'] != "is") {
633               $params[$attr."_not"] = true;
634          }
635     }
636
637}
638
639
640
641dcFilterSet::__init__($GLOBALS['core']->tpl);
642?>
Note: See TracBrowser for help on using the repository browser.

Sites map