Exécuter des requete style sql sur un array

Description

La classe myArray, pour l'instant en version "j'ai codé comme un cochon" permet l'exécution de requête de type sql sur un tableau (Array).

Elle peut être utile, par exemple, lorsque l'on travaille avec une DB et que des données que l'on y récupère sont stockées dans un tableau.
Ce tableau pourra ainsi être traitée via la classe myArray pour ainsi faciliter sa manipulation

la structure du tableau a traiter doit se présenter de la maniere suivante:

$toto = Array {
[x] => Array(
champ1 => x1,
champ2 => x2,
champ3 => x3
),
[y] => Array(
champ1 => y1,
champ2 => y2,
champ3 => y3
),
[z] => Array(
champ1 => z1,
champ2 => z2,
champ3 => z3
)
}

ainsi les cas d'utilisation:

- myArray::query($toto, "select champ1,champ2 ")

donnera :

Array {
[x] => Array( champ1 => x1, champ1 => x2 ),
[y] => Array( champ1 => y1, champ1 => y2 ),
[z] => Array( champ1 => z1, champ1 => z2 )
}

- myArray::query($toto, "select champ1,champ2 group by champ1")

donnera :

Array {
[x1] => Array(
[x] => Array( champ1 => x1, champ1 => x2 )
),
[y1] => Array(
[y] => Array( champ1 => y1, champ1 => y2 )
),
[z1] => Array(
[z] => Array( champ1 => z1, champ1 => z2 )
)
}

Source / Exemple :


<?
/**

  • class facilitant la manipulation de tableau
  • @author: p418
  • @version: 0.9b
    • /
class myArray { /**
  • ranger un tableau associatif par rapport a un champs
  • ne marche que sur un array de type
  • toto {
  • [x] => Array(
  • champ1 => x1,
  • champ2 => x2,
  • champ3 => x3
  • ),
  • [y] => Array(
  • champ1 => y1,
  • champ2 => y2,
  • champ3 => y3
  • ),
  • [z] => Array(
  • champ1 => z1,
  • champ2 => z2,
  • champ3 => z3
  • )
  • }
  • @access private
  • <code>
  • myArray::orderby($toto,"champ1")
  • retournera un tableau avec x,y,z ordonnés par champs1
  • @param (array) $arrayToOrder
  • @param (string) $orderBy
  • @return (array)
  • /

  • public static function orderBy($arrayToOrder,$orderBy)
    {

    $result = array();

    if(!is_array($arrayToOrder) || count($arrayToOrder) == 0)
    return $result ;
    $tmp = $arrayToOrder;
    $sorting = $tmp[0][$orderBy];
    for($i=0;$i<count($arrayToOrder);$i++)
    {
    if($tmp[$i][$orderBy]==$sorting)
    {
    $result[]=$tmp[$i];
    array_splice($tmp,$i,1);
    }
    }
    return array_merge($result,self::orderBy($tmp,$orderBy));
    }

    /**
    • semblable a array_unique mais basé sur un champs donné.
    • le tableau en entrée doit avoir la meme structure que pour la fontion orderby
    • @access private
    • @param (array) $arrayToOrder
    • @param (string) $orderBy
    • @param (bool) $distinct
    • @return array
    • /

    public static function groupBy($arrayToOrder,$orderBy,$distinct=false)
    {
    $exists = self::fieldExists($orderBy,$arrayToOrder);
    if($exists !== true)
    throw new Exception("Champs '$orderBy' inconnu dans la clause 'group by' $idx");
    $res = array();
    while(list($k,$v) = each($arrayToOrder))
    $res[$v[$orderBy]][]=$v;
    return $res;
    }

    /**
    • Interprete la requete donnée en parametre sur le tableau $myArray
    • @access private
    • @param (Array) $myArray
    • @param (string) $query
    • @return (array)
    • /

    public static function query($myArray,$query)
    {

    try
    {
    if(eregi("(select|delete) *([\*a-zA-Z,_\(\)]*) *(where)? *(.*)",$query,$reg))
    {
    $todo = array();
    $res = array();
    $columns = explode(",",str_replace(" ","",$reg[2]));

    if(empty($reg[4]))
    $reg[4]="";
    else
    {
    $groupBy = preg_split("/group by/i",$reg[4]);
    $reg[4] = empty($groupBy[0])?"":$groupBy[0];

    }

    //on exécute, la reqquete
    while(list($idx,$champs) = each($columns))
    {
    if(eregi("([0-9a-z_]*)\((.*)\)",$champs,$func))
    {
    $todo[$func[1]]=$func[2];
    continue;
    }

    if($champs=='*')
    foreach( self::getFields($myArray) as $field )
    $res=array_merge($res,self::select($myArray,$field,$reg[4]));
    else
    {
    $exists=self::fieldExists($champs,$myArray);
    if($exists!==true)
    throw new Exception("Champs '$champs' inexistant à l'index '$exists'\n".print_r($myArray,true));
    $res=array_merge($res,self::select($myArray,$champs,$reg[4]));
    }
    }
    $tmp = array();
    $size = self::getMaxSize($res);
    for($i=0;$i<$size;$i++)
    foreach($res as $nom => $tab)
    $tmp[$i][$nom]=isset($tab[$i])?$tab[$i]:'';

    /**
    *
    • action spécifique

    *
      • /


    // si on veut grouper
    if(!empty($groupBy[1]))
    $tmp=self::groupBy($tmp,trim($groupBy[1]));

    //autre actions
    if(count($todo))
    {
    foreach($todo as $func => &$do)
    if(!self::functionExists($func))
    throw new Exception("Fonction '$func()' inconnue");
    }
    //*****
    return $tmp;
    }
    else
    throw new Exception("requete incomprise");

    }
    catch(Exception $e)
    {
    throw new Exception("[myArrayError] une erreur dans la requete : '$query'\n\t{$e->getMessage()}\n");
    }
    }

    /**
    • retourne un array contenant les valeurs du champs $fieldName dans le tableau $myArray
    • une condition peut etre définie pour la récupération.
    • cette condition est évaluée par la fonction eval() de php
    • pour faire appel a la valeur d'un champs donné, il suffit dencadrer ce nom de champs par des %%
    • ainsi %mon_champs% fera référence à la valeur de $row['mon_champs']
    • @access private
    • @param (array) $myArray
    • @param (string) $fieldName
    • @param (string) $condition
    • @return (array)
    • /

    public static function getField($myArray,$fieldName,$condition=true)
    {
    try
    {

    $res = array();

    //préparation de la condition
    if(is_string($condition) && trim($condition)!="")
    {
    $patterns=array("/^(.*)$/","/\s*([\*<>=+-]{1,2})\s*/");
    $condition=preg_replace($patterns," \$1 ",$condition);
    $condition=preg_replace("/\s+=\s+/"," == ",$condition);

    if(preg_match_all("/[\s]?%?([a-z_]+[\w]+)%?[\s]+/i",$condition,$reg))
    {
    while(list($idx,$field) = each($reg[0]))
    {
    $cleanned_field = $reg[1][$idx];
    if(in_array(strtolower($cleanned_field),array("and","or","between")) or self::functionExists($cleanned_field))
    continue;

    $fieldExists = self::fieldExists($cleanned_field,$myArray);
    if($fieldExists===true)
    $condition = str_ireplace($field,' $row["'.$cleanned_field.'"] ',$condition);
    else
    throw new Exception("Champs '{$cleanned_field}' à l'index '$fieldExists' inconnu dans la clause 'where'");
    }

    }
    }
    else
    $condition = "1";

    //global $row;
    while( list($row_idx,$row) = each($myArray))
    if(isset($row[$fieldName]) && self::where($condition,array("row" => $row)))
    $res[$fieldName][]=$row[$fieldName];
    return $res;
    }
    catch(Exception $e)
    {
    throw $e;
    }
    }

    /**
    • Alias de la méthode getField
    • @see getField
    • /

    public static function select($myArray,$fieldName,$condition){ return self::getField($myArray,$fieldName,$condition);}


    /**
    • /

    private static function where($condition,$scope=null)
    {
    //on défini le scope par défaut
    $myScope = $GLOBALS;
    //si un scope a été spécifié
    if(is_array($scope))
    $myScope = $scope;
    //on charge les variables du scope pour pourvoir faire lévaluation
    extract($myScope,EXTR_OVERWRITE);

    // on utilise les saut de lignes pour pouvoir se repérer si une erreur est générée
    // car eval ne spécifie qu'un numéro de ligne pour une erreur.
    $condition = str_replace(" ","\n",$condition);

    //inhibition du mess d'erreur
    //j'ai pas trouvé de vraie méthode pour ca :( cest crade
    ob_start();
    $evaluation = eval("return $condition;");
    $errorMsg = ob_get_clean();

    if(!empty($errorMsg))
    $error = error_get_last();
    $error_msg = "Erreur de syntaxe dans la clause 'where': ";
    $arrow_pad = strlen($error_msg);

    // si une erreur à été généré lors de l'eval, on va préciser où se trouve l'erreur
    if(!empty($error['line']))
    {
    $error_line = $error['line'];

    for($i=1,$pos = strpos($condition,"\n");$i<$error_line-1;$pos=strpos($condition,"\n",$pos+1),$i++ ){}
    $condition = str_replace("\n"," ",$condition);

    $arrow_pad += ($pos-2);
    $arrow_pad += strlen($condition);

    $arrow = str_repeat(' ',$arrow_pad).'^';
    throw new Exception("$error_msg$condition \n\t $arrow ({$error['message']})");
    }

    return $evaluation;
    }


    /**
    • retourne la taille la plus grande parmis les array contenu dans $myArray

    *
    • @param (array) $myArray
    • @return (int)
    • /

    public static function getMaxSize($myArray)
    {
    $sizes = self::count($myArray);
    if(!count($sizes))
    return 0;
    return max($sizes);
    }


    /**
    • retourne l'existence d'une clé dans l'ensemble des sous tableau de $myArray

    *
    • @param (string) $aColumnName
    • @param (array) $myArray
    • @return (bool)
    • /

    public static function fieldExists($aColumnName,Array $myArray)
    {
    if(empty($myArray))
    {
    //print_r(debug_backtrace());
    throw new Exception("Erreur test d'existence");
    }
    while(list($idx,$row)=each($myArray))
    if(!array_key_exists($aColumnName,$row))
    return $idx;
    return (bool)true;
    }

    public static function functionExists($funcName)
    {
    return method_exists(get_class(),$funcName);
    }
    /**
    • retourne les champs
    • si le parametre optionel $all est définie à true (false par défaut),
    • alors ce sont tous les champs qui sont retournés
    • sans se soucier si ils sont tous commun aux sous-tableaux

    *
    • @param (array) $myArray
    • @param (bool) [$all]
    • @return (array)
      • /

    public static function getFields($myArray,$all=false)
    {
    $res= array();
    while(list($idx,$row)=each($myArray))
    $res = ($all)?$res+array_keys($row):(count($res)?array_intersect($res,array_keys($row)):array_keys($row));
    return $res;

    }


    /**
    • Fonctions type msyql
    • /



    /**
    • retourne pour chaque ligne du tableau la taille

    *
    • @param (array) $myArray
    • @return (array)
    • /

    public static function count($myArray)
    {
    $res = array();
    while(list($idx,$row) = each($myArray))
    $res[$idx] = count($row);
    return $res;
    }

    }

    ?>
    </code>

    Conclusion :


    @TODO:

    - Remettre au propre le code
    - Revoir le "moteur"
    - faire une version réellement orientée objet

    what else...

    Codes Sources

    A voir également

    Vous n'êtes pas encore membre ?

    inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

    Les membres obtiennent plus de réponses que les utilisateurs anonymes.

    Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

    Le fait d'être membre vous permet d'avoir des options supplémentaires.