diff --git a/build/api/core/ModuleResponse.php b/build/api/core/ModuleResponse.php index b7bc899..17c570e 100644 --- a/build/api/core/ModuleResponse.php +++ b/build/api/core/ModuleResponse.php @@ -141,7 +141,7 @@ ManagerError::setHttpCode($this->error); // Type de contenu - // header('Content-Type: application/json'); + header('Content-Type: application/json; charset=utf-8'); // On rajoute l'erreur au message $returnData = array_merge( diff --git a/build/database/core/DatabaseDriver.php b/build/database/core/DatabaseDriver.php index acecd7f..0240bbc 100644 --- a/build/database/core/DatabaseDriver.php +++ b/build/database/core/DatabaseDriver.php @@ -208,8 +208,10 @@ for( $i = 0 ; $i < count($fetchData) ; $i++ ) // pour tout les utilisateurs foreach($fetchData[$i] as $col => $val){ // pour toutes les entrées - if( !\mb_detect_encoding($val, 'UTF-8') ) + if( \mb_detect_encoding($val) === 'UTF-8' ) $fetchData[$i][$col] = utf8_encode($val); + else + $fetchData[$i][$col] = utf8_encode(utf8_decode($val)); if( is_int($col) ){ // Si indice numerique if( $nextEquivalent ) // Si suit un indice textuel @@ -229,8 +231,10 @@ // on supprime les doublons des entrées (indice numérique) foreach($fetchData as $i=>$val){ // pour toutes les entrées - if( !\mb_detect_encoding($val, 'UTF-8') ) + if( \mb_detect_encoding($val) === 'UTF-8' ) $fetchData[$i] = utf8_encode($val); + else + $fetchData[$i] = utf8_encode(utf8_decode($val)); if( is_int($i) ){ // Si indice numerique if( $nextEquivalent ) // Si suit un indice textuel diff --git a/build/orm/core/Rows.php b/build/orm/core/Rows.php index f47d8c5..9c7397b 100644 --- a/build/orm/core/Rows.php +++ b/build/orm/core/Rows.php @@ -31,6 +31,10 @@ const SEL_DISTINCT = true; + // {3} Gestion du Order By // + const ORDER_ASC = '__ASC__'; + const ORDER_DESC = '__DESC__'; + // {3} Constantes d'insertion // const INSERT_DEFAULT = '__DEFAULT__'; // Valeur DEFAULT (pour insertion) @@ -38,6 +42,7 @@ private $driver; // Database driver label private $where; // Tableau associatif contenant les conditions private $select; // Tableau contenant la liste des champs à afficher + private $orderby; // Tableau contenant la liste des orderby private $unique; // VRAI si on attend une valeur unique private $schema; // Tableau contenant les informations associées aux données private $joined; // Tableau contenant les Rows liés @@ -50,7 +55,7 @@ * */ public function __construct($schema, $driver=null){ - /* (1) On enregistre le driver */ + /* (1) Database Driver */ $this->driver = $driver; /* (2) On récupère les informations */ @@ -62,10 +67,13 @@ /* (4) On initialise les champs à retourner */ $this->select = []; - /* (5) On initialise le caractère 'unique' du résultat */ + /* (5) On initialise l'ordonnancement' */ + $this->orderby = []; + + /* (6) On initialise le caractère 'unique' du résultat */ $this->unique = false; - /* (6) On initialise les jointures */ + /* (7) On initialise les jointures */ $this->joined = []; } @@ -240,11 +248,12 @@ * @field Libellé du champ à afficher * @func Fonction d'aggrégation (ou NULL) * @distinct Clause DISTINCT + * @alias Alias du champ * * @return this Retourne l'object courant * */ - public function select($field=null, $func=null, $distinct=false){ + public function select($field=null, $func=null, $distinct=false, $alias=null){ /* [1] On formatte les champs =========================================================*/ /* (1) On vérifie le type de @field */ @@ -265,6 +274,9 @@ /* (4) On met la valeur par défaut à @distinct si type mauvais */ $distinct = !is_bool($distinct) ? false : $distinct; + /* (5) Si @alias incorrect, on met @field par défaut */ + if( !is_string($alias) ) + $alias = $field; /* [2] On enregistre le champ =========================================================*/ @@ -273,13 +285,13 @@ foreach($this->schema['columns'] as $f=>$c) if( !isset($this->select[$f]) ) - $this->select[$f] = [$func, $distinct]; + $this->select[$f] = [$func, $distinct, $alias]; /* (2) Si aucun SELECT pour ce champ, on le crée */ }else{ if( !isset($this->select[$field]) ) - $this->select[$field] = [$func, $distinct]; + $this->select[$field] = [$func, $distinct, $alias]; } @@ -289,6 +301,48 @@ } + /* SELECTIONNE L'ORDONNANCEMENT DES RESULTATS + * + * @field Libellé du champ à afficher + * @order Gestion de l'ordre ASC/DESC (ou NULL) + * + * @return this Retourne l'object courant + * + */ + public function orderby($field=null, $order=null){ + /* [1] On formatte les champs + =========================================================*/ + /* (1) On vérifie le type de @field */ + if( !is_string($field) ) + return $this; + + /* (2) On vérifie que la colonne @field existe, sinon on quitte */ + if( !isset($this->schema['columns'][$field]) && $field != '*' ) + return $this; + + /* (3) On vérifie @order */ + $orderList = [self::ORDER_ASC, self::ORDER_DESC]; + + // Valeur si NULL + $order = is_null($order) ? $orderList[0] : $order; + + // Si ordre non référencée, on quitte + if( !in_array($order, $orderList) ) + return $this; + + + /* [2] On enregistre le champ + =========================================================*/ + /* (1) On crée le ORDER_BY pour ce champ */ + $this->orderby[$field] = $order; + + + /* [3] On retourne l'object courant + =========================================================*/ + return $this; + } + + /* JOINT UNE SECONDE TABLE () * * @localField Nom d'une colonne locale @@ -513,7 +567,6 @@ return $updated; } - /* AJOUTE UNE ENTREE DANS LA TABLE * * @entry Tableau associatif de la forme (colonne => valeur) @@ -726,7 +779,7 @@ /* RETOURNE LES DONNEES / NULL si une erreur survient * - * @execute VRAI si on veut exécuter la requête, sinon renvoie [requete, boundParams] + * @execute VRAI si on veut exécuter la requête, sinon renvoie [requete, boundParams] * * @return data Tableau contenant les champs sélectionnés * @return data Valeur du champ sélectionné (si 1 seul champ) @@ -748,7 +801,6 @@ $joinedFetched[$field] = $data['object']->fetch(false); - /* [1] On rédige la clause SELECT =========================================================*/ /* (1) On formatte les données */ @@ -774,7 +826,6 @@ $requestS['SELECT'] = SQLBuilder::SELECT($selectTables); - /* [2] On rédige la clause FROM ========================================================*/ /* (0) On initialise la clause */ @@ -790,7 +841,6 @@ $requestS['FROM'] = array_merge($data['request']['FROM'], $requestS['FROM']); - /* [5] On rédige la clause WHERE/AND =========================================================*/ /* (1) On met les conditions locales */ @@ -823,8 +873,6 @@ } - - /* [6] Clause GROUP BY =========================================================*/ /* (0) On initialise la liste des @rows non aggrégés */ @@ -856,7 +904,27 @@ if( count($groupBy) > 0) $requestS['GROUPBY'] = SQLBuilder::GROUPBY($groupBy); + /* [6] Clause ORDER BY + =========================================================*/ + /* (1) On formatte les données */ + $orderTables = []; + /* (2) On ajoute les champs locaux */ + if( count($this->orderby) > 0 ) + $orderTables[$this->schema['table']] = $this->orderby; + + /* (4) On ajoute les champs des jointures (récursif)*/ + foreach($joinedFetched as $field=>$data){ + foreach($data['request']['ORDERBY'] as $table=>$fields) // pour chaque ensemble de champ de chaque table + foreach($fields as $field=>$orderBy) // Pour chaque orderby de chaque champ + + if( count($orderBy) > 0 ) + $orderTables[$table][$field] = $orderBy; + + } + + /* (3) On génère la clause SELECT */ + $requestS['ORDERBY'] = SQLBuilder::ORDERBY($orderTables); /* [6] Clause LIMIT =========================================================*/ @@ -876,6 +944,7 @@ $request = DatabaseDriver::getPDO($this->driver)->prepare($requestString); // var_dump($requestString); + /* [8] On exécute la requête et retourne le résultat =========================================================*/ /* (1) On exécute la requête */ @@ -937,32 +1006,45 @@ if( !$twoDimensions ) $formatted = [$formatted]; - /* (2) On retire les indices numériques */ + + /* (2) On récupère les noms des champs à partir des select (alias) */ // {1} On récupère les colonnes locales // - $existingColumns = $this->schema['columns']; + $existingColumns = []; + + foreach($this->select as $field=>$data) + $existingColumns[$data[2]] = $this->schema['columns'][$field]; + // {2} On ajoute les colonnes des jointures // foreach($this->joined as $j) - $existingColumns = array_merge( $existingColumns, $j['object']->schema['columns'] ); + foreach($j['object']->select as $field=>$data) + $existingColumns[$data[2]] = $j['object']->schema['columns'][$field]; + // {3} On vérifie chaque clé, si c'est une colonne qui existe // foreach($formatted as $i=>$entry) // Pour chaque champ - foreach($entry as $index=>$value) + foreach($entry as $index=>$value){ // Si la colonne existe on applique le type if( isset($existingColumns[$index]) ){ if( $existingColumns[$index]['type'] == 'int' ) $formatted[$i][$index] = intval( $value ); - else if( $existingColumns[$index]['type'] == 'float' ) + elseif( $existingColumns[$index]['type'] == 'float' ) $formatted[$i][$index] = floatval( $value ); + // String utf8 management + elseif( \mb_detect_encoding($value) === 'UTF-8' ) + $formatted[$i][$index] = utf8_encode($value); + else + $formatted[$i][$index] = utf8_encode(utf8_decode($value)); // Si pas non plus une aggrégation et si indice numérique, on le retire - }else if( !preg_match('/^agg_.+/', $index) && is_numeric($index) ) + }else if( !preg_match('/^agg_.+/', $index) && is_numeric($index) ) unset($formatted[$i][$index]); + } /* (3) On remet 1 dimension si 1 dimension à la base */ if( !$twoDimensions ) diff --git a/build/orm/core/SQLBuilder.php b/build/orm/core/SQLBuilder.php index fd22412..99bc59f 100644 --- a/build/orm/core/SQLBuilder.php +++ b/build/orm/core/SQLBuilder.php @@ -21,10 +21,16 @@ } - - - - + /* CONSTRUIT LA REQUETE FORMATTEE "ORDER BY" AVEC UNE LISTE DE CHAMPS + * + * @tables Liste de champs : [table => fields] + * + * @return sql Renvoie un tableau formatté + * + */ + public static function ORDERBY($tables){ + return $tables; + } /* CONSTRUIT LA REQUETE FORMATTEE "GROUP BY" AVEC UNE LISTE DE CHAMPS * @@ -38,10 +44,6 @@ } - - - - /* CONSTRUIT LA REQUETE FORMATTEE "FROM" AVEC UNE LISTE DE TABLES * * @tables Liste de tables OU SQL PUR @@ -54,10 +56,6 @@ } - - - - /* CONSTRUIT LA REQUETE FORMATTEE "UPDATE" AVEC LA TABLE EN QUESTION * * @table Table en question @@ -70,10 +68,6 @@ } - - - - /* CONSTRUIT LA REQUETE FORMATTEE "DELETE" AVEC LA TABLE EN QUESTION * * @table Table en question @@ -86,10 +80,6 @@ } - - - - /* CONSTRUIT LA REQUETE TEXTUELLE "IN" AVEC UNE LISTE DE TABLES * * @field Tableau contenant [table, field] @@ -123,13 +113,7 @@ } return $sql.")"; - } - - - - - - /* CONSTRUIT LA REQUETE TEXTUELLE "WHERE" AVEC UNE LISTE DE TABLES + } /* CONSTRUIT LA REQUETE TEXTUELLE "WHERE" AVEC UNE LISTE DE TABLES * * @field Tableau contenant [table, field] * @valeur Valeurs de la clause WHERE [valeur, opérateur] @@ -160,13 +144,7 @@ return $sql; - } - - - - - - /* CONSTRUIT LA REQUETE FORMATTEE "SET" AVEC UNE LISTE DE TABLES + } /* CONSTRUIT LA REQUETE FORMATTEE "SET" AVEC UNE LISTE DE TABLES * * @values Tableau de la forme [ field=>value, field2=>value2 ] * @bound Tableau associatif contenant les variables "bindés" -> ajout des champs @@ -196,13 +174,7 @@ } return $sql; - } - - - - - - /* CONSTRUIT LA REQUETE FORMATTEE "LIMIT" AVEC UN NOMBRE D'ENTREES + } /* CONSTRUIT LA REQUETE FORMATTEE "LIMIT" AVEC UN NOMBRE D'ENTREES * * @count Nombre limite * @@ -223,18 +195,6 @@ return $sql; } - - - - - - - - - - - - /* CONSTRUIT LA REQUETE A PARTIR D'UNE REQUETTE FORMATTEE * * @request Requête formattée @@ -258,7 +218,7 @@ case 'SELECT': $sql .= "SELECT "; $c = 0; - foreach($statements as $table=>$fields) + foreach($statements as $table=>$fields){ foreach($fields as $field=>$select){ /* (1) On construit le nom du champ */ @@ -274,7 +234,11 @@ /* (4) On ajoute l'alias */ - if( isset($select[0]) && !is_null($select[0]) ) + // si défini + if( isset($select[2]) ) + $fieldStr = "$fieldStr as ".$select[2]; + // si func et non défini + elseif( isset($select[0]) && !is_null($select[0]) ) $fieldStr = "$fieldStr as agg_$field"; else $fieldStr = "$fieldStr"; @@ -283,6 +247,7 @@ $c++; } + } $sql .= "\n"; break; @@ -336,7 +301,6 @@ case 'UPDATE': $sql .= "UPDATE $statements\n"; break; - break; /* (7) Clause SET @@ -364,17 +328,35 @@ $sql .= "\n"; break; + + /* (9) Clause ORDER BY + ---------------------------------------------------------*/ + case 'ORDERBY': + + // si aucun ORDER BY, on quitte + if( count($statements) == 0 ) + continue; + + $sql .= 'ORDER BY '; + + $c = 0; + foreach($statements as $table=>$fields) + foreach($fields as $field=>$order){ + + if( $c > 0 ) $sql .= ', '; + + $sql .= "$table.$field ". substr($order, 2, -2); + + $c++; + } + + $sql .= "\n"; + break; } } - - - - - - /* [2] On retourne le résultat =========================================================*/ return $sql; diff --git a/public_html/index.php b/public_html/index.php index e054b9c..3f07ce7 100644 --- a/public_html/index.php +++ b/public_html/index.php @@ -81,7 +81,7 @@ $R->get('(.+)@([a-f0-9]{6})(\.svg)', function($matches){ $path = __PUBLIC__.'/'.$matches[0].$matches[2]; - header('Content-Type: image/svg+xml'); + header('Content-Type: image/svg+xml; charset=utf-8'); // On crée la partie ajoutée $stylesheet = "\n