From 084372dc416c88869f850d042aeffcd25df7fdff Mon Sep 17 00:00:00 2001
From: Fil <fil@rezo.net>
Date: Wed, 15 Dec 2010 23:00:43 +0000
Subject: [PATCH] reecriture de tous les iterateurs sur le mode de la class
 Iterator de PHP http://php.net/manual/fr/class.iterator.php

il devient possible de faire :

{{{
<?php
$s = new IterSQL(

array (
    'select' =>
    array (
      0 => 'articles.date',
      1 => 'articles.id_article',
      2 => 'articles.id_rubrique',
      3 => 'articles.titre',
      5 => 'articles.descriptif',
      6 => 'articles.chapo',
      7 => 'articles.lang',
    ),
    'from' =>
    array (
      'articles' => 'spip_articles',
    ),
    'type' =>
    array (
    ),
    'where' =>
    array (
      0 =>
      array (
        0 => '=',
        1 => 'articles.statut',
        2 => '\'publie\'',
      ),
      1 => '1=1',
    ),
    'join' =>
    array (
    ),
    'groupby' =>
    array (
    ),
    'orderby' =>
    array (
      0 => 'articles.date DESC',
    ),
    'limit' => '0,1',
    'having' =>
    array (
    ),
    'table' => 'articles',
    'id' => '_articles_recents',
    'connect' => '',
  )

);

foreach ($s as $k=>$v) {
	var_dump($v);
}

?>
}}}

mais aussi :

{{{
<?php

$s = new IterDATA(
	array (
	'source' => 'http://rezo.net/backend/',
	'sourcemode' => 'rss'
  )
);

foreach ($s as $k=>$v) {
	var_dump($v);
}

?>
}}}
---
 ecrire/public/compiler.php          |   8 +-
 ecrire/public/creer_boucle_data.php |   2 +-
 ecrire/public/creer_boucle_enum.php |   1 +
 ecrire/public/creer_boucle_pour.php |   2 +-
 ecrire/public/iterateur.php         | 231 +++++++++++++++++-----------
 5 files changed, 145 insertions(+), 99 deletions(-)

diff --git a/ecrire/public/compiler.php b/ecrire/public/compiler.php
index d2aa3131e7..1a7f84c7ac 100644
--- a/ecrire/public/compiler.php
+++ b/ecrire/public/compiler.php
@@ -362,7 +362,7 @@ define('CODE_CORPS_BOUCLE', '%s
 		%s,
 		array(%s)
 	);
-	if ($iter->ok) {
+	if ($iter->valid()) {
 	%s%s$SP++;
 	// RESULTATS
 	%s
@@ -472,7 +472,7 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
 			$boucle->numrows = true;
 			$corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);";
 		}
-	} else $corps = "while (\$Pile[\$SP] = \$iter->next()) {\n$corps\n	}"; 
+	} else $corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n	}"; 
 
 	$count = '';
 	if (!$boucle->select) {
@@ -490,7 +490,7 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
 	if ($boucle->numrows OR $boucle->mode_partie) {
 		if ($count == 'count(*)')
 			$count = "array_shift(\$iter->next())";
-		else $count = "\$iter->count()";
+		else $count = "\$iter->total()";
 		$nums .= "\$Numrows['$id_boucle']['total'] = @intval($count);"
 		. $boucle->mode_partie
 		. "\n\t";
@@ -523,7 +523,7 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
 		)';
 			break;
 
-		case 'IterPOUR':
+		case 'IterDATA':
 		case 'IterENUM':
 			$command = 'array("where" => $where, "source"=>$source, "sourcemode"=>$sourcemode, "limit" => $limit)';
 			break;
diff --git a/ecrire/public/creer_boucle_data.php b/ecrire/public/creer_boucle_data.php
index 28dcd84df8..6f720b9151 100644
--- a/ecrire/public/creer_boucle_data.php
+++ b/ecrire/public/creer_boucle_data.php
@@ -15,7 +15,7 @@
 // annonce au compilo les "champs" disponibles
 //
 function public_creer_boucle_DATA_dist($b) {
-	$b->iterateur = 'IterPOUR'; # designe la classe d'iterateur
+	$b->iterateur = 'IterDATA'; # designe la classe d'iterateur
 	$b->show = array(
 		'field' => array(
 			'cle' => 'STRING',
diff --git a/ecrire/public/creer_boucle_enum.php b/ecrire/public/creer_boucle_enum.php
index b970d04562..dba2766233 100644
--- a/ecrire/public/creer_boucle_enum.php
+++ b/ecrire/public/creer_boucle_enum.php
@@ -18,6 +18,7 @@ function public_creer_boucle_ENUM_dist($b) {
 	$b->iterateur = 'IterENUM'; # designe la classe d'iterateur
 	$b->show = array(
 		'field' => array(
+			'cle' => 'STRING',
 			'valeur' => 'STRING',
 		)
 	);
diff --git a/ecrire/public/creer_boucle_pour.php b/ecrire/public/creer_boucle_pour.php
index 141112006d..79e80179e1 100644
--- a/ecrire/public/creer_boucle_pour.php
+++ b/ecrire/public/creer_boucle_pour.php
@@ -15,7 +15,7 @@
 // annonce au compilo les "champs" disponibles
 //
 function public_creer_boucle_POUR_dist($b) {
-	$b->iterateur = 'IterPOUR'; # designe la classe d'iterateur
+	$b->iterateur = 'IterDATA'; # designe la classe d'iterateur
 	$b->show = array(
 		'field' => array(
 			'tableau' => 'ARRAY',
diff --git a/ecrire/public/iterateur.php b/ecrire/public/iterateur.php
index 3cb9a7fc6b..991eb129ce 100644
--- a/ecrire/public/iterateur.php
+++ b/ecrire/public/iterateur.php
@@ -16,91 +16,108 @@
 // Iterateur SQL
 //
 
-class Iter {
-	var $ok = false;
-	var $type;
-	var $command;
-	var $info;
-
-	private $result = false;
-
-	/*
-	 * array command: les commandes d'initialisation
-	 * array info: les infos sur le squelette
-	 */
-	public function Iter($command, $info=array()) {
-		$this->type = '??';
-		$this->command = $command;
-		$this->info = $info;
+class Iter implements Iterator {
+	# http://php.net/manual/fr/class.iterator.php
+	public function __construct() {} // initialise
+	public function rewind() {} // revient au depart
+	public function valid() {} // avons-nous un element
+	public function current() {} // quel est sa valeur
+	public function key() {} // quelle est sa cle
+	public function next() {} // avancer d'un cran
+
+	# Iter SPIP
+	var $type; # type de l'iterateur
+	var $command; # parametres de l'iterateur
+	var $info; # infos de compilateur
+
+	// avancer en position n
+	public function seek($n=0, $continue=null) {
+		$this->rewind();
+		while($n-->0 AND $this->valid()) $this->next();
+		return true;
+	}
+	public function fetch() {
+		if ($this->valid()) {
+			$r = array('cle' => $this->key(), 'valeur' => $this->current());
+			$this->next();
+		} else
+			$r = false;
+		return $r;
 	}
-	public function seek($n=0, $continue=null) {}
-	public function next() {}
-	public function free() {}
-	public function count() {}
+	public function free() {} // liberer la ressource
+	public function total() {} // #TOTAL_BOUCLE
 }
 
 class IterSQL extends Iter {
-	var $ok = false;
-	var $type;
-	var $command;
-	var $info;
 
-	private $result = false;
+	private $sqlresult = false; # ressource sql
+	private $row = null; # row sql courante
 
 	private function select() {
 		$v = &$this->command;
-		$this->result = calculer_select($v['select'], $v['from'], $v['type'], $v['where'], $v['join'], $v['groupby'], $v['orderby'], $v['limit'], $v['having'], $v['table'], $v['id'], $v['connect'], $this->info);
-		$this->ok = !!$this->result;
+		$this->sqlresult = calculer_select($v['select'], $v['from'], $v['type'], $v['where'], $v['join'], $v['groupby'], $v['orderby'], $v['limit'], $v['having'], $v['table'], $v['id'], $v['connect'], $this->info);
+		$this->ok = !!$this->sqlresult;
+		if ($this->ok)
+			$this->row = sql_fetch($this->sqlresult, $this->command['connect']);
 	}
 
 	/*
 	 * array command: les commandes d'initialisation
 	 * array info: les infos sur le squelette
 	 */
-	public function IterSQL($command, $info=array()) {
+	public function __construct($command, $info=array()) {
 		$this->type='SQL';
 		$this->command = $command;
 		$this->info = $info;
 		$this->select();
 	}
+	public function rewind() {
+		return $this->seek(0);
+	}
+	public function valid() {
+		return is_array($this->row);
+	}
+	public function current() {
+		return $this->row;
+	}
 	public function seek($n=0, $continue=null) {
 		# SQLite ne sait pas seek(), il faut relancer la query
-		if (!$a = sql_seek($this->result, $this->command['connect'], $n, $continue)) {
+		if (!$a = sql_seek($this->sqlresult, $this->command['connect'], $n, $continue)) {
 			$this->free();
 			$this->select();
-			return true; # ??
+			return true;
 		}
 		return $a;
 	}
 	public function next(){
-		return sql_fetch($this->result, $this->command['connect']);
+		$this->row = sql_fetch($this->sqlresult, $this->command['connect']);
+	}
+	public function fetch(){
+		if ($this->valid()) {
+			$r = $this->current();
+			$this->next();
+		} else
+			$r = false;
+		return $r;
 	}
 	public function free(){
-		return sql_free($this->result, $this->command['connect']);
+		return sql_free($this->sqlresult, $this->command['connect']);
 	}
-	public function count() {
-		return sql_count($this->result, $this->command['connect']);
+	public function total() {
+		return sql_count($this->sqlresult, $this->command['connect']);
 	}
 }
 
 class IterENUM extends Iter {
-	var $ok = true;
-	var $type;
-	var $command;
-	var $info;
-
-	var $n = 0;
-	var $max = 1000000;
-
-	var $filtre = array();
-
-	private $result = false;
-
-	/*
-	 * array command: les commandes d'initialisation
-	 * array info: les infos sur le squelette
-	 */
-	public function IterENUM($command, $info=array()) {
+	private $n = 0;
+	private $pos = 0;
+	private $start = 0;
+	private $offset = 0;
+	private $total = 1000000;
+	private $max = 1000000;
+	private $filtre = array();
+
+	public function __construct($command=array(), $info=array()) {
 		$this->type='ENUM';
 		$this->command = $command;
 		$this->info = $info;
@@ -128,60 +145,82 @@ class IterENUM extends Iter {
 		// critere {2,7}
 		if ($this->command['limit']) {
 			$limit = explode(',',$this->command['limit']);
-			$this->n = $limit[0];
-			$this->max = $limit[0]+$limit[1]-1;
+			$this->offset = $limit[0];
+			$this->total = $limit[1];
 		}
 
 
 		// Appliquer les filtres sur (valeur)
 		if ($this->filtre) {
-			$this->filtre = create_function('$valeur', $b = 'return ('.join(') AND (', $this->filtre).');');
+			$this->filtre = create_function('$cle,$valeur', $b = 'return ('.join(') AND (', $this->filtre).');');
 		}
 
 	}
-	public function seek($n=0, $continue=null) {
-		$this->n = $n;
-		return true;
+	public function rewind() {
+		$this->n = $this->start-1;
+		$this->pos = -1;
+		for ($i=0; $i<=$this->offset; $i++) {
+			$this->next(); # pour filtre
+			$this->pos=0;
+		}
+	}
+	public function valid(){
+		return
+			$this->n <= $this->max
+			AND $this->pos < $this->total;
+	}
+	public function current() {
+		return $this->n;
+	}
+	public function key() {
+		return $this->pos;
 	}
 	public function next() {
+		$this->pos++;
+		$this->n++;
 		if ($f = $this->filtre) {
 			while (
-			$this->n < $this->max
-			AND !$f($a = $this->n++)){};
-		} else
-			$a = $this->n++;
-
-		if ($this->n <= 1+$this->max)
-			return array('valeur' => $a);
+			$this->n <= $this->max
+			AND !$f($this->pos,$this->n)) {
+				$this->n++;
+			}
+		}
 	}
-	public function free(){
+
+	public function seek($n=0, $continue=null) {
+		$this->n = $this->start-1;
+		$this->pos = -1;
+		for ($i=0; $i<=$n; $i++) {
+			$this->next(); # pour filtre
+		}
+		return true;
 	}
-	public function count() {
-		return $this->max;
+	public function total() {
+		return $this->total;
 	}
 }
 
 
-class IterPOUR extends Iter {
-	var $ok = false;
-	var $type;
-	var $command;
-	var $info;
-
-	var $tableau = array();
-	var $filtre = array();
-
-	private $result = false;
+class IterDATA extends Iter {
+	private $tableau = array();
+	private $filtre = array();
+	private $cle = null;
+	private $valeur = null;
 
-	/*
-	 * array command: les commandes d'initialisation
-	 * array info: les infos sur le squelette
-	 */
-	public function IterPOUR($command, $info=array()) {
-		$this->type='POUR';
+	public function __construct($command, $info=array()) {
+		$this->type='DATA';
 		$this->command = $command;
 		$this->info = $info;
 
+		$this->select($command);
+	}
+
+	public function rewind() {
+		reset($this->tableau);
+		list($this->cle, $this->valeur) = each($this->tableau);
+	}
+
+	private function select($command) {
 		// les commandes connues pour l'iterateur POUR
 		// sont : tableau=#ARRAY ; cle=...; valeur=...
 		// source URL
@@ -305,23 +344,29 @@ class IterPOUR extends Iter {
 				$limit[0],$limit[1],true);
 		}
 
-
-		reset($this->tableau);
+		$this->rewind();
 		#var_dump($this->tableau);
 	}
 	public function seek($n=0, $continue=null) {
-		reset($this->tableau);
-		while($n-->0 AND list($cle, $valeur) = each($this->tableau)){};
+		$this->rewind();
+		while($n-->0
+		AND list($this->cle, $this->valeur) = each($this->tableau)){};
 		return true;
 	}
-	public function next(){
-		if (list($cle, $valeur) = each($this->tableau)) {
-			return array('cle' => $cle, 'valeur' => $valeur);
-		}
+	public function valid(){
+		return !is_null($this->cle);
 	}
-	public function free(){
+	public function current() {
+		return $this->valeur;
+	}
+	public function key() {
+		return $this->cle;
+	}
+	public function next(){
+		if ($this->valid())
+			list($this->cle, $this->valeur) = each($this->tableau);
 	}
-	public function count() {
+	public function total() {
 		return count($this->tableau);
 	}
 }
-- 
GitLab