[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / public / iterateur.php
index 3aa6711..360d262 100644 (file)
@@ -4,23 +4,25 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2016                                                *
+ *  Copyright (c) 2001-2017                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
 \***************************************************************************/
 
-if (!defined('_ECRIRE_INC_VERSION')) return;
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
 
 /**
  * Fabrique d'iterateur
  * permet de charger n'importe quel iterateur IterateurXXX
  * fourni dans le fichier iterateurs/xxx.php
- * 
+ *
  */
-class IterFactory{
-       public static function create($iterateur, $command, $info=null){
+class IterFactory {
+       public static function create($iterateur, $command, $info = null) {
 
                // cas des SI {si expression} analises tres tot
                // pour eviter le chargement de tout iterateur
@@ -38,24 +40,34 @@ class IterFactory{
                // (il faudrait passer l'argument ->sql_serveur
                // pour etre certain qu'on est sur un "php:")
                if (class_exists($iterateur)) {
-                       $a = isset($command['args']) ? $command['args'] : array() ;
+                       $a = isset($command['args']) ? $command['args'] : array();
 
                        // permettre de passer un Iterateur directement {args #ITERATEUR} :
                        // si on recoit deja un iterateur en argument, on l'utilise
-                       if (count($a)==1 and is_object($a[0]) and is_subclass_of($a[0], 'Iterator')) {
+                       if (count($a) == 1 and is_object($a[0]) and is_subclass_of($a[0], 'Iterator')) {
                                $iter = $a[0];
 
-                       // sinon, on cree un iterateur du type donne
-                       } else {                                                        
+                               // sinon, on cree un iterateur du type donne
+                       } else {
                                // arguments de creation de l'iterateur...
                                // (pas glop)
                                try {
                                        switch (count($a)) {
-                                               case 0:    $iter = new $iterateur();  break;
-                                               case 1:    $iter = new $iterateur($a[0]);  break;
-                                               case 2:    $iter = new $iterateur($a[0], $a[1]);  break;
-                                               case 3:    $iter = new $iterateur($a[0], $a[1], $a[2]);  break;
-                                               case 4:    $iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);  break;
+                                               case 0:
+                                                       $iter = new $iterateur();
+                                                       break;
+                                               case 1:
+                                                       $iter = new $iterateur($a[0]);
+                                                       break;
+                                               case 2:
+                                                       $iter = new $iterateur($a[0], $a[1]);
+                                                       break;
+                                               case 3:
+                                                       $iter = new $iterateur($a[0], $a[1], $a[2]);
+                                                       break;
+                                               case 4:
+                                                       $iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
+                                                       break;
                                        }
                                } catch (Exception $e) {
                                        spip_log("Erreur de chargement de l'iterateur $iterateur");
@@ -67,10 +79,11 @@ class IterFactory{
                        // chercher la classe d'iterateur
                        // IterateurXXX
                        // definie dans le fichier iterateurs/xxx.php
-                       $class = "Iterateur".$iterateur;
-                       if (!class_exists($class)){
+                       $class = "Iterateur" . $iterateur;
+                       if (!class_exists($class)) {
                                if (!include_spip("iterateur/" . strtolower($iterateur))
-                                       OR !class_exists($class)) {
+                                       or !class_exists($class)
+                               ) {
                                        die("Iterateur $iterateur non trouvé");
                                        // si l'iterateur n'existe pas, on se rabat sur le generique
                                        # $iter = new EmptyIterator();
@@ -78,31 +91,33 @@ class IterFactory{
                        }
                        $iter = new $class($command, $info);
                }
+
                return new IterDecorator($iter, $command, $info);
        }
 }
 
 
-
-
 class IterDecorator extends FilterIterator {
        private $iter;
 
        /**
         * Conditions de filtrage
         * ie criteres de selection
+        *
         * @var array
         */
        protected $filtre = array();
 
        /**
         * Fonction de filtrage compilee a partir des criteres de filtre
+        *
         * @var string
         */
        protected $func_filtre = null;
 
        /**
         * Critere {offset, limit}
+        *
         * @var int
         * @var int
         */
@@ -112,15 +127,16 @@ class IterDecorator extends FilterIterator {
        /**
         * nombre d'elements recuperes depuis la position 0,
         * en tenant compte des filtres
+        *
         * @var int
         */
-       protected $fetched=0;
+       protected $fetched = 0;
 
        /**
         * Y a t'il une erreur ?
-        * 
+        *
         * @var bool
-       **/
+        **/
        protected $err = false;
 
        /**
@@ -128,17 +144,20 @@ class IterDecorator extends FilterIterator {
         * (select SQL errone, non chargement des DATA, etc)
         */
        public function err() {
-               if (method_exists($this->iter, 'err'))
+               if (method_exists($this->iter, 'err')) {
                        return $this->iter->err();
-               if (property_exists($this->iter, 'err'))
+               }
+               if (property_exists($this->iter, 'err')) {
                        return $this->iter->err;
+               }
+
                return false;
        }
 
-       public function __construct(Iterator $iter, $command, $info){
+       public function __construct(Iterator $iter, $command, $info) {
                parent::__construct($iter);
                parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
-               
+
                // recuperer l'iterateur transmis
                $this->iter = $this->getInnerIterator();
                $this->command = $command;
@@ -168,7 +187,7 @@ class IterDecorator extends FilterIterator {
        // 
        private function calculer_select() {
                if ($select = &$this->command['select']) {
-                       foreach($select as $s) {
+                       foreach ($select as $s) {
                                // /!\ $s = '.nom'
                                if ($s[0] == '.') {
                                        $s = substr($s, 1);
@@ -183,13 +202,15 @@ class IterDecorator extends FilterIterator {
        // et proprietes disponibles
        public function get_select($nom) {
                if (is_object($this->iter)
-               AND method_exists($this->iter, $nom)) {
+                       and method_exists($this->iter, $nom)
+               ) {
                        try {
                                return $this->iter->$nom();
-                       } catch(Exception $e) {
+                       } catch (Exception $e) {
                                // #GETCHILDREN sur un fichier de DirectoryIterator ...
                                spip_log("Methode $nom en echec sur " . get_class($this->iter));
                                spip_log("Cela peut ĂȘtre normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
+
                                return '';
                        }
                }
@@ -200,7 +221,8 @@ class IterDecorator extends FilterIterator {
                // cle et valeur par defaut
                // ICI PLANTAGE SI ON NE CONTROLE PAS $nom
                if (in_array($nom, array('cle', 'valeur'))
-               AND method_exists($this, $nom)) {
+                       and method_exists($this, $nom)
+               ) {
                        return $this->$nom();
                }
 
@@ -208,9 +230,9 @@ class IterDecorator extends FilterIterator {
                return table_valeur($this->valeur(), $nom, null);
        }
 
-       
+
        private function calculer_filtres() {
-               
+
                // Issu de calculer_select() de public/composer L.519
                // TODO: externaliser...
                //
@@ -220,13 +242,19 @@ class IterDecorator extends FilterIterator {
                // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
                if ($where = &$this->command['where']) {
                        $menage = false;
-                       foreach($where as $k => $v) { 
-                               if (is_array($v)){
-                                       if ((count($v)>=2) && ($v[0]=='REGEXP') && ($v[2]=="'.*'")) $op= false;
-                                       elseif ((count($v)>=2) && ($v[0]=='LIKE') && ($v[2]=="'%'")) $op= false;
-                                       else $op = $v[0] ? $v[0] : $v;
-                               } else $op = $v;
-                               if ((!$op) OR ($op==1) OR ($op=='0=0')) {
+                       foreach ($where as $k => $v) {
+                               if (is_array($v)) {
+                                       if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
+                                               $op = false;
+                                       } elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
+                                               $op = false;
+                                       } else {
+                                               $op = $v[0] ? $v[0] : $v;
+                                       }
+                               } else {
+                                       $op = $v;
+                               }
+                               if ((!$op) or ($op == 1) or ($op == '0=0')) {
                                        unset($where[$k]);
                                        $menage = true;
                                }
@@ -235,17 +263,18 @@ class IterDecorator extends FilterIterator {
                                // produites par sql_in quand plus de 255 valeurs passees a IN
                                if (preg_match_all(',\s+IN\s+(\(.*\)),', $op, $s_req)) {
                                        $req = '';
-                                       foreach($s_req[1] as $key => $val) {
+                                       foreach ($s_req[1] as $key => $val) {
                                                $req .= trim($val, '(,)') . ',';
                                        }
                                        $req = '(' . rtrim($req, ',') . ')';
                                }
-                               if (preg_match(',^\(\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)(?:\s+(AND|OR)\s+\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\))*\)$,', $op, $regs)) {
+                               if (preg_match(',^\(\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)(?:\s+(AND|OR)\s+\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\))*\)$,',
+                                       $op, $regs)) {
                                        $this->ajouter_filtre($regs[1], 'IN', strlen($req) ? $req : $regs[3], $regs[2]);
                                        unset($op);
                                }
                        }
-                       foreach($where as $k => $v) {
+                       foreach ($where as $k => $v) {
                                // 3 possibilites : count($v) =
                                // * 1 : {x y} ; on recoit $v[0] = y
                                // * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
@@ -265,21 +294,20 @@ class IterDecorator extends FilterIterator {
                }
 
                // critere {2,7}
-               if (isset($this->command['limit']) AND $this->command['limit']) {
-                       $limit = explode(',',$this->command['limit']);
+               if (isset($this->command['limit']) and $this->command['limit']) {
+                       $limit = explode(',', $this->command['limit']);
                        $this->offset = $limit[0];
                        $this->limit = $limit[1];
                }
 
                // Creer la fonction de filtrage sur $this
                if ($this->filtre) {
-                       $this->func_filtre = create_function('$me', $b = 'return ('.join(') AND (', $this->filtre).');');
+                       $this->func_filtre = create_function('$me', $b = 'return (' . join(') AND (', $this->filtre) . ');');
                }
        }
 
 
-
-       protected function ajouter_filtre($cle, $op, $valeur, $not=false) {
+       protected function ajouter_filtre($cle, $op, $valeur, $not = false) {
                if (method_exists($this->iter, 'exception_des_criteres')) {
                        if (in_array($cle, $this->iter->exception_des_criteres())) {
                                return;
@@ -290,50 +318,61 @@ class IterDecorator extends FilterIterator {
                # qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
                # ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
                # il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
-               
+
                # if (!in_array($cle, array('cle', 'valeur')))
                #       return;
 
-               $a = '$me->get_select(\''.$cle.'\')';
+               $a = '$me->get_select(\'' . $cle . '\')';
 
                $filtre = '';
-               
+
                if ($op == 'REGEXP') {
-                       $filtre = 'match('.$a.', '.str_replace('\"', '"', $valeur).')';
-                       $op = '';
-               } else if ($op == 'LIKE') {
-                       $valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur));
-                       $filtre = 'match('.$a.', '.$valeur.')';
-                       $op = '';
-               } else if ($op == '=') {
-                       $op = '==';
-               } else if ($op == 'IN') {
-                       $filtre = 'in_array('.$a.', array'.$valeur.')';
-                       $op = '';
-               } else if (!in_array($op, array('<','<=', '>', '>='))) {
-                       spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
+                       $filtre = 'match(' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
                        $op = '';
+               } else {
+                       if ($op == 'LIKE') {
+                               $valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur));
+                               $filtre = 'match(' . $a . ', ' . $valeur . ')';
+                               $op = '';
+                       } else {
+                               if ($op == '=') {
+                                       $op = '==';
+                               } else {
+                                       if ($op == 'IN') {
+                                               $filtre = 'in_array(' . $a . ', array' . $valeur . ')';
+                                               $op = '';
+                                       } else {
+                                               if (!in_array($op, array('<', '<=', '>', '>='))) {
+                                                       spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
+                                                       $op = '';
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if ($op) {
+                       $filtre = $a . $op . str_replace('\"', '"', $valeur);
                }
-       
-               if ($op)
-                       $filtre = $a.$op.str_replace('\"', '"', $valeur);
 
-               if ($not)
+               if ($not) {
                        $filtre = "!($filtre)";
-                       
+               }
+
                if ($filtre) {
                        $this->filtre[] = $filtre;
                }
        }
 
-       
-       public function next(){
+
+       public function next() {
                $this->pos++;
                parent::next();
        }
 
        /**
         * revient au depart
+        *
         * @return void
         */
        public function rewind() {
@@ -346,48 +385,53 @@ class IterDecorator extends FilterIterator {
        # Extension SPIP des iterateurs PHP
        /**
         * type de l'iterateur
+        *
         * @var string
         */
        protected $type;
 
        /**
         * parametres de l'iterateur
+        *
         * @var array
         */
        protected $command;
 
        /**
         * infos de compilateur
+        *
         * @var array
         */
        protected $info;
 
        /**
         * position courante de l'iterateur
+        *
         * @var int
         */
-       protected $pos=null;
+       protected $pos = null;
 
        /**
         * nombre total resultats dans l'iterateur
+        *
         * @var int
         */
-       protected $total=null;
+       protected $total = null;
 
        /**
         * nombre maximal de recherche pour $total
         * si l'iterateur n'implemente pas de fonction specifique
         */
-        protected $max=100000;
+       protected $max = 100000;
 
 
        /**
         * Liste des champs a inserer dans les $row
         * retournes par ->fetch()
         */
-        protected $select=array();
+       protected $select = array();
+
 
-        
        /**
         * aller a la position absolue n,
         * comptee depuis le debut
@@ -399,12 +443,13 @@ class IterDecorator extends FilterIterator {
         * @return bool
         *   success or fail if not implemented
         */
-       public function seek($n=0, $continue=null) {
-               if ($this->func_filtre OR !method_exists($this->iter, 'seek') OR !$this->iter->seek($n)) {
+       public function seek($n = 0, $continue = null) {
+               if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) {
                        $this->seek_loop($n);
                }
                $this->pos = $n;
                $this->fetched = $n;
+
                return true;
        }
 
@@ -413,10 +458,11 @@ class IterDecorator extends FilterIterator {
         * un par un tous les elements
         */
        private function seek_loop($n) {
-               if ($this->pos > $n)
+               if ($this->pos > $n) {
                        $this->rewind();
+               }
 
-               while ($this->pos < $n AND $this->valid()) {
+               while ($this->pos < $n and $this->valid()) {
                        $this->next();
                }
 
@@ -425,27 +471,33 @@ class IterDecorator extends FilterIterator {
 
        /**
         * Avancer de $saut pas
+        *
         * @param  $saut
         * @param  $max
         * @return int
         */
-       public function skip($saut, $max=null){
+       public function skip($saut, $max = null) {
                // pas de saut en arriere autorise pour cette fonction
-               if (($saut=intval($saut))<=0) return $this->pos;
+               if (($saut = intval($saut)) <= 0) {
+                       return $this->pos;
+               }
                $seek = $this->pos + $saut;
                // si le saut fait depasser le maxi, on libere la resource
                // et on sort
-               if (is_null($max))
+               if (is_null($max)) {
                        $max = $this->count();
+               }
 
-               if ($seek>=$max OR $seek>=$this->count()) {
+               if ($seek >= $max or $seek >= $this->count()) {
                        // sortie plus rapide que de faire next() jusqu'a la fin !
                        $this->free();
-                 return $max;
+
+                       return $max;
                }
 
-         $this->seek($seek);
-         return $this->pos;
+               $this->seek($seek);
+
+               return $this->pos;
        }
 
        /**
@@ -462,24 +514,29 @@ class IterDecorator extends FilterIterator {
                } else {
 
                        while ($this->valid()
-                       AND (
-                               !$this->accept()
-                               OR (isset($this->offset) AND $this->fetched++ < $this->offset)
-                       ))
+                               and (
+                                       !$this->accept()
+                                       or (isset($this->offset) and $this->fetched++ < $this->offset)
+                               )) {
                                $this->next();
+                       }
 
-                       if (!$this->valid())
+                       if (!$this->valid()) {
                                return false;
+                       }
 
                        if (isset($this->limit)
-                       AND $this->fetched > $this->offset + $this->limit)
+                               and $this->fetched > $this->offset + $this->limit
+                       ) {
                                return false;
+                       }
 
                        $r = array();
                        foreach ($this->select as $nom) {
                                $r[$nom] = $this->get_select($nom);
                        }
                        $this->next();
+
                        return $r;
                }
        }
@@ -488,34 +545,38 @@ class IterDecorator extends FilterIterator {
        public function cle() {
                return $this->key();
        }
-       
+
        // retourner la valeur pour #VALEUR
        public function valeur() {
                # attention PHP est mechant avec les objets, parfois il ne les
                # clone pas proprement (directoryiterator sous php 5.2.2)
                # on se rabat sur la version __toString()
                if (is_object($v = $this->current())) {
-                       if (method_exists($v, '__toString'))
+                       if (method_exists($v, '__toString')) {
                                $v = $v->__toString();
-                       else
-                               $v = (array) $v;
+                       } else {
+                               $v = (array)$v;
+                       }
                }
+
                return $v;
        }
 
        /**
         * Accepte-t-on l'entree courante lue ?
-        * On execute les filtres pour le savoir. 
-       **/
+        * On execute les filtres pour le savoir.
+        **/
        public function accept() {
                if ($f = $this->func_filtre) {
                        return $f($this);
                }
+
                return true;
        }
 
        /**
         * liberer la ressource
+        *
         * @return bool
         */
        public function free() {
@@ -523,18 +584,21 @@ class IterDecorator extends FilterIterator {
                        $this->iter->free();
                }
                $this->pos = $this->total = 0;
+
                return true;
        }
 
        /**
         * Compter le nombre total de resultats
         * pour #TOTAL_BOUCLE
+        *
         * @return int
         */
        public function count() {
                if (is_null($this->total)) {
                        if (method_exists($this->iter, 'count')
-                       AND !$this->func_filtre) {
+                               and !$this->func_filtre
+                       ) {
                                return $this->total = $this->iter->count();
                        } else {
                                // compter les lignes et rembobiner
@@ -551,8 +615,5 @@ class IterDecorator extends FilterIterator {
 
                return $this->total;
        }
-       
-}
 
-
-?>
+}