Valider ca56b2ef rédigé par marcimat's avatar marcimat
Parcourir les fichiers

Modification des itérateurs :

- on déclare le décorateur en extension de FilterIterator, puisque c'est effectivement le cas maintenant, et on enlève donc le code redondant avec l'extension
- on déclare dans la description des tables les méthodes des objets d'iteration appelés, de telle sorte qu'on puisse les utiliser en critère de boucle et en balise

- SQL me retournait brusquement des : «[function.mysql-data-seek]: Offset 0 is invalid for MySQL result index» sans trouver l'origine qui les produit... mais appeler mysql_data_seek() sur une requete n'ayant pas de résultat est logique d'echouer dikit http://php.net/manual/fr/function.mysql-data-seek.php . On teste donc que la requête a donné des réponses, mais ce changement me parait étrange.


Exemple boucler les répertoires accessibles en écriture :
{{{
<h1>DirectoryIterator</h1>
<B_directoryIterator>
	<ul>
		<BOUCLE_directoryIterator(iter:DirectoryIterator){args #EVAL{_ROOT_RACINE}}{iswritable=1}>
			<li>#CLE => #VALEUR [ est un répertoire. (#ISDIR|oui)]</li>
		</BOUCLE_directoryIterator>
	</ul>
	Total : #TOTAL_BOUCLE<br />
	Grand Total : #GRAND_TOTAL
</B_directoryIterator>
}}}

Affiche :
{{{
DirectoryIterator

    * 7 => sites est un répertoire.
    * 9 => tests est un répertoire.
    * 19 => mutualisation est un répertoire.
    * 23 => lib est un répertoire.

Total : 4
Grand Total : 4 
}}}

Reste que la #CLE n'est pas encore bien comptée.
parent 0163e1fe
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+4 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -85,6 +85,10 @@ class IterateurDATA implements Iterator {
		list($this->cle, $this->valeur) = each($this->tableau);
	}

	public function exception_des_criteres() {
		return array('tableau');
	}
	
	protected function select($command) {
		// les commandes connues pour l'iterateur POUR
		// sont : tableau=#ARRAY ; cle=...; valeur=...
+8 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -23,6 +23,14 @@ function iterateur_iter_dist($b, $iteratorName) {
			'valeur' => 'STRING',
		)
	);
	foreach (get_class_methods($iteratorName) as $method) {
		$b->show['field'][ strtolower($method) ] = 'METHOD';
	}
	/*
	foreach (get_class_vars($iteratorName) as $property) {
		$b->show['field'][ strtolower($property) ] = 'PROPERTY';
	}
	*/
	return $b;
}

+168 −77
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -54,7 +54,8 @@ class IterFactory{
}


class IterDecorator implements Iterator {

class IterDecorator extends FilterIterator {
	private $iter;

	/**
@@ -70,97 +71,165 @@ class IterDecorator implements Iterator {
	 */
	protected $func_filtre = null;

	protected function ajouter_filtre($com) {
		if (!in_array($com[1], array('cle', 'valeur')))
			return;

		$op = '';
		if ($com[0] == 'REGEXP')
			$filtre = '@preg_match("/". '.str_replace('\"', '"', $com[2]).'."/", $'.$com[1].')';
		else if ($com[0] == '=')
			$op = '==';
		else if (in_array($com[0], array('<','<=', '>', '>=')))
			$op = $com[0];
	
		if ($op)
			$filtre = '$'.$com[1].$op.str_replace('\"', '"', $com[2]);

		if ($com['not'])
			$filtre = "!($filtre)";

		$this->filtre[] = $filtre;
	}

	public function __construct(Iterator $iter, $command, $info){
		$this->iter = $iter;
		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;
		$this->info = $info;
		$this->pos = 0;

		if (is_array($this->command['where'])) {
			foreach ($this->command['where'] as $k => $com) {
				if ($com[0] == 'NOT') {
					$com = $com[1];
					$com['not'] = true;
		// chercher la liste des champs a retournes par
		// fetch si l'objet ne les calcule pas tout seul
		if (!method_exists($this->iter, 'fetch')) {
			$this->calculer_select();
			$this->calculer_filtres();
		}
				$this->ajouter_filtre($com);

		$this->total = $this->count();
	}


	// calcule les elements a retournes par fetch()
	// enleve les elements inutiles du select()
	// 
	private function calculer_select() {
		$select = &$this->command['select'];
		foreach($select as $s) {
			// /!\ $s = '.nom'
			if ($s[0] == '.') {
				$s = substr($s, 1);
			}
			$this->select[] = $s;
		}
	}

		// Appliquer les filtres sur (valeur)
		if ($this->filtre) {
			$this->func_filtre = create_function('$cle,$valeur', $b = 'return ('.join(') AND (', $this->filtre).');');
	// recuperer la valeur d'une balise #X
	// en fonction des methodes 
	// et proprietes disponibles
	public function get_select($nom) {
		if (method_exists($this->iter, $nom)) {
			return $this->iter->$nom();
		}
		/*
		if (property_exists($this->iter, $nom)) {
			return $this->iter->$nom;
		}*/
		// cle et valeur par defaut
		if (method_exists($this, $nom)) {
			return $this->$nom();
		}
		// big erreur ...
		return '';
	}

		$this->total = $this->count();
	
	private function calculer_filtres() {
		
		// Issu de calculer_select() de public/composer L.519
		// [todo] externaliser...
		//
		// retirer les criteres vides:
		// {X ?} avec X absent de l'URL
		// {par #ENV{X}} avec X absent de l'URL
		// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
		$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')) {
				unset($where[$k]);
				$menage = true;
			}
		}
		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}
			// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y

	public function next(){
		$this->pos++;
		$this->iter->next();
			// 1 : forcement traite par un critere, on passe
			if (count($v) == 1) {
				continue;
			}
			if (count($v) == 2) {
				$this->ajouter_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
			}
			if (count($v) == 3) {
				$this->ajouter_filtre($v[1], $v[0], $v[2]);
			}
		}

		while ($this->valid() AND !$this->accept()) {
			$this->iter->next();
		// Appliquer les filtres sur (valeur)
		if ($this->filtre) {
			$this->func_filtre = create_function('$me', $b = 'return ('.join(') AND (', $this->filtre).');');
		}
	}

	/**
	 * revient au depart
	 * @return void
	 */
	public function rewind() {
		$this->pos = 0;
		$this->iter->rewind();


	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;
			}
		}
		# [todo ?] analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
		# mais c'est normalement deja opere par calculer_critere_infixe()
		# 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;
		
	/**
	 * avons-nous un element
	 * @return void
	 */
	public function valid() {
		return $this->iter->valid();
		$filtre = '';
		
		if ($op == 'REGEXP')
			$filtre = '@preg_match("/". '.str_replace('\"', '"', $valeur).'."/", $'.$cle.')';
		else if ($op == '=')
			$op = '==';
		else if (!in_array($op, array('<','<=', '>', '>='))) {
			spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
			$op = '';
		}
	
	/**
	 * Valeur courante
	 * @return void
	 */
	public function current() {
		return $this->iter->current();
		if ($op)
			$filtre = '$me->get_select(\''.$cle.'\')'.$op.str_replace('\"', '"', $valeur);

		if ($not)
			$filtre = "!($filtre)";
			
		if ($filtre) {
			$this->filtre[] = $filtre;
		}
	}

	
	public function next(){
		$this->pos++;
		parent::next();
	}

	/**
	 * Cle courante
	 * revient au depart
	 * @return void
	 */
	public function key() {
		return $this->iter->key();
	public function rewind() {
		$this->pos = 0;
		parent::rewind();
	}



	# Extension SPIP des iterateurs PHP
	/**
	 * type de l'iterateur
@@ -198,6 +267,14 @@ class IterDecorator implements Iterator {
	 */
	 protected $max=100000;


	/**
	 * Liste des champs a inserer dans les $row
	 * retournes par ->fetch()
	 */
	 protected $select=array();

	 
	/**
	 * aller a la position absolue n,
	 * comptee depuis le debut
@@ -210,7 +287,7 @@ class IterDecorator implements Iterator {
	 *   success or fail if not implemented
	 */
	public function seek($n=0, $continue=null) {
		if (!method_exists($this->iter, 'seek') OR !$this->iter->seek($n)) {
		if ($this->func_filtre OR !method_exists($this->iter, 'seek') OR !$this->iter->seek($n)) {
			$this->seek_loop($n);
		}
		$this->pos = $n;
@@ -277,6 +354,23 @@ class IterDecorator implements Iterator {
				return false;
			}

			$r = array();
			foreach ($this->select as $nom) {
				$r[$nom] = $this->get_select($nom);
			}

			$this->next(); // $r['valeur'] avance aussi d'un cran avec DirectoryIterator ! fichtre !
			return $r;
		}
	}

	// retourner la cle pour #CLE
	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()
@@ -286,19 +380,16 @@ class IterDecorator implements Iterator {
			else
				$v = (array) $v;
		}
			$r = array(
				'cle' => $this->key(),
				'valeur' => $v
			);

			$this->next(); // $r['valeur'] avance aussi d'un cran avec DirectoryIterator ! fichtre !
			return $r;
		}
		return $v;
	}

	/**
	 * Accepte t'on l'entree courante lue ?
	 * On execute les filtres pour le savoir. 
	**/
	public function accept() {
		if ($f = $this->func_filtre) {
			return $f($this->key(), $this->current());
			return $f($this);
		}
		return true;
	}