Create class UserFilterBuilder
authorRaphaël Barrois <raphael.barrois@polytechnique.org>
Mon, 25 Jan 2010 15:18:22 +0000 (16:18 +0100)
committerRaphaël Barrois <raphael.barrois@polytechnique.org>
Sat, 13 Feb 2010 23:33:56 +0000 (00:33 +0100)
Used to create (basic) UserFilter, reading values from Get/Post
Should evolve into a much more powerful tool later...

Signed-off-by: Raphaël Barrois <raphael.barrois@polytechnique.org>
include/ufbuilder.php [new file with mode: 0644]

diff --git a/include/ufbuilder.php b/include/ufbuilder.php
new file mode 100644 (file)
index 0000000..528759a
--- /dev/null
@@ -0,0 +1,320 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+class UserFilterBuilder
+{
+    private $envprefix;
+    private $fields;
+    private $valid = true;
+    private $ufc = null;
+
+    /** Constructor
+     * @param $fields An array of UFB_Field objects
+     * @param $envprefix Prefix to use for parts of the query
+     */
+    public function __construct($fields, $envprefix = '')
+    {
+        $this->fields = $fields;
+        $this->envprefix   = $envprefix;
+    }
+
+    /** Builds the UFC; returns as soon as a field says it is invalid
+     */
+    private function buildUFC()
+    {
+        if ($this->ufc != null) {
+            return;
+        }
+        $this->ufc = new PFC_And();
+
+        foreach ($this->fields as $field) {
+            $this->valid = $field->apply(&$this);
+            if (!$this->valid) {
+                return;
+            }
+        }
+    }
+
+    public function addCond(PlFilterCondition &$cond)
+    {
+        $this->ufc->addChild($cond);
+    }
+
+    public function isValid()
+    {
+        $this->buildUFC();
+        return $this->valid;
+    }
+
+    /** Returns the built UFC
+     * @return The UFC, or PFC_False() if an error happened
+     */
+    public function &getUFC()
+    {
+        $this->buildUFC();
+        if ($this->valid) {
+            return $this->ufc;
+        } else {
+            return new PFC_False();
+        }
+    }
+
+    /** Wrappers around Env::i/s/..., to add envprefix
+     */
+    public function s($key, $def) {
+        return trim(Env::s($this->envprefix . $key, $def));
+    }
+
+    public function i($key, $def) {
+        return intval(trim(Env::i($this->envprefix . $key, $def)));
+    }
+
+    public function v($key, $def) {
+        return Env::v($this->envprefix . $key, $def);
+    }
+
+    public function has($key) {
+        return Env::has($this->envprefix . $key);
+    }
+}
+
+abstract class UFB_Field
+{
+    protected $envfield;
+    protected $formtext;
+
+    protected $empty = false;
+    protected $val = null;
+
+    /** Constructor
+     * @param $envfield Name of the field in the environment
+     * @param $formtext User-friendly name of that field
+     */
+    public function __construct($envfield, $formtext = '')
+    {
+        $this->envfield = $envfield;
+        if ($formtext != '') {
+            $this->formtext = $formtext;
+        } else {
+            $formtext = ucfirst($envfield);
+        }
+    }
+
+    /** Prints the given error message to the user, and returns false
+     * in order to be used as return $this->raise('ERROR');
+     *
+     * All %s in the $msg will be replaced with the formtext.
+     */
+    protected function raise($msg)
+    {
+        Platal::page()->trigError(str_replace('%s', $this->formtext, $msg));
+        return false;
+    }
+
+    public function apply(UserFilterBuilder &$ufb) {
+        if (!$this->check($ufb)) {
+            return false;
+        }
+
+        if (!$this->empty) {
+            $ufc = $this->buildUFC($ufb);
+            if ($ufc != null) {
+                $ufb->addCond($ufc);
+            }
+        }
+        return true;
+    }
+
+    /** Create the UFC associated to the field; won't be called
+     * if the field is "empty"
+     * @param &$ufb UFB to which fields must be added
+     * @return UFC
+     */
+    abstract protected function buildUFC(UserFilterBuilder &$ufb);
+
+    /** This function is intended to run consistency checks on the value
+     * @return boolean Whether the input is valid
+     */
+    abstract protected function check(UserFilterBuilder &$ufb);
+}
+
+abstract class UFBF_Text extends UFB_Field
+{
+    private $forbiddenchars;
+    private $minlength;
+    private $maxlength;
+
+    public function __construct($envfield, $formtext = '', $forbiddenchars = '', $minlength = 2, $maxlength = 255)
+    {
+        parent::__construct($envfield, $formtext);
+        $this->forbiddenchars = $forbiddenchars;
+        $this->minlength      = $minlength;
+        $this->maxlength      = $maxlength;
+    }
+
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if (!$ufb->has($this->envfield)) {
+            $this->empty = true;
+            return true;
+        }
+
+        $this->val = $ufb->s($this->envfield);
+        if (strlen($this->val) < $this->minlength) {
+            return $this->raise("Le champ %s est trop court (minimum {$this->minlength}).");
+        } else if (strlen($this->val) > $this->maxlength) {
+            return $this->raise("Le champ %s est trop long (maximum {$this->maxlength}).");
+        }
+        return true;
+    }
+}
+
+/** Subclass to use for fields which only allow integers within a range
+ */
+abstract class UFBF_Range extends UFB_Field
+{
+
+    private $min;
+    private $max;
+
+    public function __construct($envfield, $formtext = '', $min = 0, $max = 65535)
+    {
+        parent::__construct($envfield, $formtext);
+        $this->min = $min;
+        $this->max = $max;
+    }
+
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if (!$ufb->has($this->envfield)) {
+            $this->empty = true;
+            return true;
+        }
+
+        $this->val = $ufb->i($this->envfield);
+        if ($this->val < $this->min) {
+            return $this->raise("Le champs %s est inférieur au minimum ({$this->min}).");
+        } else if ($this->val > $this->max) {
+            return $this->raise("Le champ %s est supérieur au maximum ({$this->max}).");
+        }
+        return true;
+    }
+}
+
+/** Subclass to use for indexed fields
+ */
+abstract class UFBF_Index extends UFB_Field
+{
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if (!$ufb->has($this->envfield)) {
+            $this->empty = true;
+        }
+        return true;
+    }
+}
+
+/** Subclass to use for fields whose value must belong to a specific set of values
+ */
+abstract class UFBF_Enum extends UFB_Field
+{
+    public function __construct($envfield, $formtext = '', $allowedvalues = array())
+    {
+        parent::__construct($envfield, $formtext);
+        $this->allowedvalues = $allowedvalues;
+    }
+
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if (!$ufb->has($this->envfield)) {
+            $this->empty = true;
+            return true;
+        }
+
+        $this->val = $ufb->v($this->envfield);
+        if (! in_array($this->val, $this->allowedvalues)) {
+            return $this->raise("La valeur {$this->val} n'est pas valide pour le champ %s.");
+        }
+        return true;
+    }
+}
+
+class UFBF_Name extends UFBF_Text
+{
+    private $type;
+
+    public function __construct($envfield, $type, $formtext = '', $forbiddenchars = '', $minlength = 2, $maxlength = 255)
+    {
+        parent::__construct($envfield, $formtext, $forbiddenchars, $minlength, $maxlength);
+        $this->type = $type;
+    }
+
+    protected function buildUFC(UserFilterBuilder &$ufb)
+    {
+        if ($ufb->i('exact')) {
+            return new UFC_Name($this->type, $this->val, UFC_Name::VARIANTS);
+        } else {
+            return new UFC_Name($this->type, $this->val, UFC_Name::VARIANTS | UFC_Name::CONTAINS);
+        }
+    }
+}
+
+class UFBF_Promo extends UFB_Field
+{
+    private static $validcomps = array('<', '<=', '=', '>=', '>');
+    private $comp;
+    private $envfieldcomp;
+
+    public function __construct($envfield, $fromtext = '', $envfieldcomp)
+    {
+        parent::__construct($envfield, $fromtext);
+        $this->envfieldcomp = $envfieldcomp;
+    }
+
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if (!$ufb->has($this->envfield) || !$ufb->has($this->envfieldcomp)) {
+            $this->empty = true;
+            return true;
+        }
+
+        $this->val  = $ubf->i($this->envfield);
+        $this->comp = $ubf->v($this->envfieldcomp);
+
+        if (!in_array($this->comp, self::$validcomps)) {
+            return $this->raise("Le critère {$this->comp} n'est pas valide pour le champ %s");
+        }
+
+        if (preg_match('/^[0-9]{2}$/', $this->val)) {
+            $this->val += 1900;
+        }
+        if ($this->val < 1900 || $this->val > 9999) {
+            return $this->raise("Le champ %s doit être une année à 4 chiffres.");
+        }
+        return true;
+    }
+
+    protected function buildUFC(UserFilterBuilder &$ufb) {
+        return new UFC_Promo($this->comp, UserFilter::DISPLAY, 'X' . $this->val);
+    }
+}
+
+?>