150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur;
 | |
| 
 | |
| use nur\b\ui\IContent;
 | |
| use nur\b\ui\IPrintable;
 | |
| 
 | |
| /**
 | |
|  * Class c: gestion de contenu iterable, {@link IPrintable}, {@link IContent}
 | |
|  *
 | |
|  * @see co
 | |
|  */
 | |
| class c {
 | |
|   /**
 | |
|    * quoter $vs si c'est un scalaire non nul.
 | |
|    * retourner null si $vs vaut null ou false.
 | |
|    * sinon retourner le tableau tel quel
 | |
|    */
 | |
|   static final function qnz($vs): ?iterable {
 | |
|     if ($vs === null || $vs === false) return null;
 | |
|     elseif ($vs instanceof IPrintable) return [$vs];
 | |
|     elseif ($vs instanceof IContent) return [$vs];
 | |
|     elseif (is_iterable($vs)) return $vs;
 | |
|     else return [htmlspecialchars(strval($vs))];
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * quoter $vs si c'est un scalaire. sinon retourner le tableau tel quel
 | |
|    *
 | |
|    * NB: cette méthode est accessible via la fonction globale {@link q()}
 | |
|    */
 | |
|   static final function q($vs): iterable {
 | |
|     if ($vs === null || $vs === false) return [];
 | |
|     elseif ($vs instanceof IPrintable) return [$vs];
 | |
|     elseif ($vs instanceof IContent) return [$vs];
 | |
|     elseif (is_iterable($vs)) return $vs;
 | |
|     else return [htmlspecialchars(strval($vs))];
 | |
|   }
 | |
| 
 | |
|   /** retourner un tableau pour $vs sans le quoter si c'est un scalaire */
 | |
|   static final function nq($vs): iterable {
 | |
|     if ($vs === null || $vs === false) return [];
 | |
|     elseif ($vs instanceof IPrintable) return [$vs];
 | |
|     elseif ($vs instanceof IContent) return [$vs];
 | |
|     elseif (is_iterable($vs)) return $vs;
 | |
|     else return [strval($vs)];
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * s'assurer que la valeur est une chaine si elle n'est pas nulle et que ce
 | |
|    * n'est pas déjà une instance de {@link IPrintable} ou {@link IContent}
 | |
|    */
 | |
|   private static function _strval($value) {
 | |
|     if ($value === null) { #NOP
 | |
|     } elseif ($value instanceof IPrintable) { #NOP
 | |
|     } elseif ($value instanceof IContent) { #NOP
 | |
|     } else $value = strval($value);
 | |
|     return $value;
 | |
|   }
 | |
| 
 | |
|   /** fusionner deux valeurs */
 | |
|   private static function _merge($pvalue, $value) {
 | |
|     if (!$pvalue) {
 | |
|       # prendre $value
 | |
|       if (!is_iterable($value)) $value = self::_strval($value);
 | |
|       return $value;
 | |
|     } elseif (!$value) {
 | |
|       # garder $pvalue
 | |
|       return $pvalue;
 | |
|     } else {
 | |
|       if (!is_iterable($value)) $value = self::_strval($value);
 | |
|       return array_merge(A::with($pvalue), A::with($value));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Applatir le tableau $values
 | |
|    *
 | |
|    * - [a, [b]] devient [a, b]
 | |
|    * - [a => x, [a => y]] devient [a => [x, y]]
 | |
|    *
 | |
|    * si $recursive==true, alors
 | |
|    * - [a => [x, [y]]] devient [a => [x, y]]
 | |
|    */
 | |
|   static final function flatten(?iterable $values, bool $recursive=true): array {
 | |
|     $flattened = [];
 | |
|     if ($values !== null) {
 | |
|       $index = 0;
 | |
|       foreach ($values as $key => $value) {
 | |
|         if ($key === $index) {
 | |
|           # valeurs séquentielles
 | |
|           # elles ne sont jamais quotées
 | |
|           $index++;
 | |
|           if (is_iterable($value)) {
 | |
|             $value = self::flatten($value);
 | |
|             $index2 = 0;
 | |
|             foreach ($value as $key2 => $value2) {
 | |
|               if ($key2 === $index2) {
 | |
|                 # sequentiel
 | |
|                 $index2++;
 | |
|                 $flattened[] = $value2;
 | |
|               } else {
 | |
|                 if (array_key_exists($key2, $flattened)) {
 | |
|                   $pvalue2 = $flattened[$key2];
 | |
|                   $value2 = self::_merge($pvalue2, $value2);
 | |
|                 }
 | |
|                 $flattened[$key2] = $value2;
 | |
|               }
 | |
|             }
 | |
|           } else {
 | |
|             $flattened[] = self::_strval($value);
 | |
|           }
 | |
|         } else {
 | |
|           # valeurs associatives
 | |
|           # la valeur est quotée si elle n'est pas dans un tableau
 | |
|           if (array_key_exists($key, $flattened)) {
 | |
|             $value = self::_merge($flattened[$key], $value);
 | |
|           }
 | |
|           if ($recursive && is_array($value)) {
 | |
|             $value = self::flatten($value, true);
 | |
|           }
 | |
|           $flattened[$key] = $value;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return $flattened;
 | |
|   }
 | |
| 
 | |
|   /** méthode de convenance pour quoter puis applatir $vs */
 | |
|   static final function fq($vs): array {
 | |
|     return self::flatten(self::q($vs));
 | |
|   }
 | |
| 
 | |
|   /** retourner la chaine correspondant au tableau $vs applati */
 | |
|   static final function string(iterable $vs): string {
 | |
|     $pieces = [];
 | |
|     foreach (c::flatten($vs) as $v) {
 | |
|       if ($v instanceof IContent) {
 | |
|         $pieces[] = self::string($v->getContent());
 | |
|       } elseif ($v instanceof IPrintable) {
 | |
|         ob_start(null, 0, PHP_OUTPUT_HANDLER_STDFLAGS ^ PHP_OUTPUT_HANDLER_FLUSHABLE);
 | |
|         $v->print();
 | |
|         $pieces[] = ob_get_clean();
 | |
|       } else {
 | |
|         $pieces[] = $v;
 | |
|       }
 | |
|     }
 | |
|     return implode("", $pieces);
 | |
|   }
 | |
| }
 |