Des types dans les tuples

But du chapitre

Dans ce chapitre nous allons voir comment adresser la sortie des différents types oracle sous forme de texte (pour ceux qui le sont) et éviter ainsi les sorties troquées des types longs par exemple. Le code qui va être produit ici sera adaptable aux autres types de données par la suite. On se concentre sur les type CLOB et NCLOB.

Une classe pour gérer les résultats de requêtes

Cette classe aura comme propriétés les noms des colonnes, leurs types et le contenu de chaque ligne.

class queryResult {
  private $types=array();
  private $cols=array();
  private $lines=array();
    
/**
  * Constructeur de classe.
  *
  * @param  object $cursor
  * @return queryResult
  */

  function __construct($cursor) {
    $nbFields=oci_num_fields($cursor);
    for ($i = 1; $i <= $nbFields; ++$i) {
      $this->cols[$i-1]=oci_field_name($cursor, $i);
      $this->types[$i-1]=oci_field_type($cursor, $i);
    }

    while ($cRow = oci_fetch_array( $cursor, OCI_NUM+OCI_RETURN_NULLS )) {
     ...
    }

    return($this);
  }
}

C’est dans le constructeur, lors de la pahe de fetch, qu’on va analyser les lignes et les stocker sous forme de tableau de chaînes dans la propriété $lines après avoir pris les informations de type et de noms des colonnes dans les propriétés $cols et $types.Pur ce faire, pour chaque colonne de chaque ligne on va décider de la sortie en fonction du type de l’élément adressé. On crée une fonction privée poru cela, elle pourra être enrichie par la suite pour d’autres types.

/**
  * transforme un élément d'une ligne ent chaine en fonction de son type
  *
  * @param  array $row
  * @param  int $i
  * @return string
  */
  private function tToStr(array $row, int $i): string {
    switch ( $this->types[$i] ) {
      case('CLOB'):
        return $row[$i]->load();
      case('NCLOB'):
        return $row[$i]->load();
      case('BLOB'):
        return 'Binary Lob';
      case ('RAW'):
        return 'Type - RAW';
      case ('LONG RAW'):
        return 'Type - RAW';
      default:
      return $row[$i];
    }
  }

Ensuite oncrée des “getters” pour obtenir un tableau 2D qui pourra être adressé par notre classe table2DOut écrite au chapitre 3. J’en ai écrit un classique, qui redonne un tableau associatif et une autre qui ne donne qu’un tableau dont la première ligne contient le nom de colonnes.

/**
  * Retourne le tableau du contenu des lignes indexé par les nos de colonnes
  *
  * @return array
  */
  function renderAll(): array {
    $ret=array();
    foreach( $this->lines as $line) {
      $ret[]=array_combine($this->cols, $line);
    }

    return $ret ;
  }

/**
  * Retourne le tableau du contenu avec en ligne 0 les noms des colonnes
  *
  * @return array
  */
  function renderHAndD(): array {
    $ret=$this->lines;
    array_unshift($ret, $this->cols);
    return $ret;
  }

J’ai donc enrichi la classe table2DOut de deux fonctions de sortie pour prendre en compte ce second type de tableau.

/**
  * Transforme une table PHP à deux dimensions en chaine CSV
  *
  * @param  array $a
  * @param  string $colSep
  * @return string
  */
  static function csvHFirstLine (array $a, ? string $colSep = ','): string {
    return table2DOut::csv($a,FALSE,$colSep);
  }
  
/**
  * Transforme une table PHP à deux dimensions dont la première ligne contient 
  * le titres des colonnes, en table HTML
  *
  * @param  array $a
  * @return string
  */
  static function htmlHFirstLine (array $a): string {
    $out='<table "class="table">
  <thead>
    <tr>'.PHP_EOL;
    $out.='      <th>'.implode('</th><th>', array_shift($a) ).'</th>
    </tr>
  </thead>
  <tbody>'.PHP_EOL;
    

    foreach ($a as $v) {
      $out.='    <tr>
      <td>'.implode('</td><td>', $v).'</td>
    </tr>'.PHP_EOL;
    }
    $out.='  </tbody>
</table>'.PHP_EOL;

    return $out;
  }

Un petit test:

$user='myUser';
$password='myPassword';
$tns='myDBAlias';

$ora=new oracle ;
$ora->connect( $user, $password, $tns, OCI_DEFAULT );

$out=$ora->execSqlFromFile( 'query' );
var_dump($out);

echo table2DOut::html($out->renderAll());
echo table2DOut::htmlHFirstLine($out->renderHandD());
echo "<pre>".PHP_EOL;
echo table2DOut::csvHFirstLine($out->renderHandD());
echo "</pre>".PHP_EOL;

On obtient la sortie attendue suivante:

D:\DevsGit\wp-lessons\lessons\Chapitre-0005\index.php:15:
object(queryResult)[3]
  private 'types' => 
    array (size=3)
      0 => string 'VARCHAR2' (length=8)
      1 => string 'CLOB' (length=4)
      2 => string 'NUMBER' (length=6)
  private 'cols' => 
    array (size=3)
      0 => string 'SQL_ID' (length=6)
      1 => string 'SQL_FULLTEXT' (length=12)
      2 => string 'SHARABLE_MEM' (length=12)
  private 'lines' => 
    array (size=2)
      0 => 
        array (size=3)
          0 => string 'gr4whhk4ds00a' (length=13)
          1 => string 'LOCK TABLE "WRH$_CELL_DISK_SUMMARY" PARTITION ("WRH$_CELL_DISK_SUMMARY_473438319_72")  IN EXCLUSIVE MODE  NOWAIT ' (length=113)
          2 => string '36258' (length=5)
      1 => 
        array (size=3)
          0 => string '2a16cph744016' (length=13)
          1 => string 'LOCK TABLE "SYS"."ORA_TEMP_2_DS_100266" IN EXCLUSIVE MODE  NOWAIT ' (length=66)
          2 => string '16243' (length=5)
SQL_ID SQL_FULLTEXT SHARABLE_MEM
gr4whhk4ds00a LOCK TABLE “WRH$_CELL_DISK_SUMMARY” PARTITION (“WRH$_CELL_DISK_SUMMARY_473438319_72”) IN EXCLUSIVE MODE NOWAIT 36258
2a16cph744016 LOCK TABLE “SYS”.”ORA_TEMP_2_DS_100266″ IN EXCLUSIVE MODE NOWAIT 16243
SQL_ID SQL_FULLTEXT SHARABLE_MEM
gr4whhk4ds00a LOCK TABLE “WRH$_CELL_DISK_SUMMARY” PARTITION (“WRH$_CELL_DISK_SUMMARY_473438319_72”) IN EXCLUSIVE MODE NOWAIT 36258
2a16cph744016 LOCK TABLE “SYS”.”ORA_TEMP_2_DS_100266″ IN EXCLUSIVE MODE NOWAIT 16243
SQL_ID,SQL_FULLTEXT,SHARABLE_MEM
gr4whhk4ds00a,LOCK TABLE "WRH$_CELL_DISK_SUMMARY" PARTITION ("WRH$_CELL_DISK_SUMMARY_473438319_72")  IN EXCLUSIVE MODE  NOWAIT ,36258
2a16cph744016,LOCK TABLE "SYS"."ORA_TEMP_2_DS_100266" IN EXCLUSIVE MODE  NOWAIT ,16243

Le code cette leçon est disponible sur notre gitlab (Chapitre-0005). il doit évidemment être adapté pour pouvoir se connecter à votre base.