<commit_before><?php
/**
	Copyright (C) 2015  Polosson

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * SQL TABLE LISTING abstraction layer, with advanced filters
 */
class Liste {
	/**
	 * @var STRING Résultat de la chaine compilée par getListe() au moment de la requête SQL
	 */
	public $request;
	/**
	 * @var ARRAY Résultat des entrées retournées par getListe()
	 */
	public $listResult;
	/**
	 * @var OBJECT Instance PDO pour la connexion SQL
	 */
	protected $bddCx;
	/**
	 * @var STRING Nom de la table courante
	 */
	protected $table;

	private $what;
	private $tri;
	private $ordre;
	private $filtre_key;
	private $filtre;
	private $lastLogiquefiltre;
	private $isFiltred = false;
	private $filtres = Array();
	private $filtreSQL;

	/**
	 * LISTING de table SQL
	 * @param OBJECT $pdoInstance Une instance de PDO préinitialisée (optionnel)
	 */
	public function __construct ($pdoInstance=false) {
		if (!$pdoInstance || !is_object($pdoInstance))
			$this->initPDO();
		else
			$this->bddCx = $pdoInstance;
	}
	public function __destruct () {
		$this->bddCx = null;
	}

	/**
	 * Initialise une liste de données à récupérer pour une table donnée
	 * @param STRING $table Le nom de la table
	 * @param STRING $want Une liste de colonnes à retourner (default '*' (tout))
	 * @param STRING $tri La colonne à utiliser pour le tri (default 'id')
	 * @param STRING $ordre La direction du tri (default 'ASC')
	 * @param STRING $filtre_key La colonne à utiliser pour filtrer les résultats (default FALSE (pas de filtre))
	 * @param STRING $filtre_comp La comparaison à effectuer pour le filtrage (default '=')
	 * @param STRING $filtre La valeur à utiliser pour filtrer les résultats (default null)
	 * @param INT $limit Nombre maximum de données à retourner (default FALSE (pas de limite)
	 * @param BOOLEAN $decodeJson TRUE pour décoder les champs contenant du JSON automatiquement. FALSE pour avoir les champs JSON au format STRING (default TRUE)
	 * @return ARRAY Le tableau des résultats, ou FALSE si aucune donnée
	 */
	public function getListe ($table, $want='*', $tri='id', $ordre='ASC', $filtre_key=false, $filtre_comp='=', $filtre=null, $limit=false, $withFK=true, $decodeJson=true, $parseDatesJS=true) {
		global $DATE_FIELDS;
		$this->table = $table;
		$this->what  = $want;
		$this->tri	 = $tri;
		$this->ordre = $ordre;
		// Check si table existe
		if (!$this->check_table_exist($table))
			throw new Exception("Liste::getListe() : La table '$table' n'existe pas");
		// pour chaque filtre défini par Liste::addFiltre()
		if (is_array($this->filtres) && count($this->filtres) > 0) {
			$FM = '' ;
			foreach ($this->filtres as $f) $FM .= $f;
			$filtrage_multiple = trim($FM, " $this->lastLogiquefiltre ");
		}
		if ($filtre_key && (string)$filtre != null ) {
			if (Liste::check_col_exist($filtre_key)) {
				$this->isFiltred  = true;
				$this->filtre_key = $filtre_key;
				$this->filtre	  = addslashes($filtre);
			}
			else return false ;
		}
		if ($this->isFiltred)
			$this->request = "SELECT $this->what FROM `$this->table` WHERE `$this->filtre_key` $filtre_comp '$this->filtre' ORDER BY `$tri` $ordre";
		elseif (isset($filtrage_multiple))
			$this->request = "SELECT $this->what FROM `$this->table` WHERE $filtrage_multiple ORDER BY `$tri` $ordre";
		elseif (isset($this->filtreSQL))
			$this->request = "SELECT $this->what FROM `$this->table` WHERE $this->filtreSQL ORDER BY `$tri` $ordre";
		else
			$this->request = "SELECT $this->what FROM `$this->table` ORDER BY `$this->tri` $this->ordre";
		if (is_int($limit))
			$this->request .= " LIMIT $limit";
		$q = $this->bddCx->prepare($this->request) ;
		$q->execute();

		if ($q->rowCount() >= 1) {							// Formatage des résultats de la requête
			$result = $q->fetchAll(PDO::FETCH_ASSOC);
			$retour = array();
			$i = 0;
			foreach ($result as $resultOK) {
				unset($resultOK['password']);
				foreach ($resultOK as $k => $v) {					// Décodage JSON le cas échéant
					if ($decodeJson && is_string($v) && preg_match('/((^\[)*(]$))|((^\{")*(}$))/', $v)) {
						$valArr = json_decode($v, true);
						if (!is_array($valArr)) continue;
						$resultOK[$k] = $valArr;
					}												// Remplacement par la Foreign Key le cas échéant
					if ($withFK && preg_match("/^".FOREIGNKEYS_PREFIX."/", $k)) {
						$fk = $this->getForeignKey($k, $v, $decodeJson, $parseDatesJS);
						if (!is_array($fk)) continue;
						$resultOK[$fk[0]] = $fk[1];
					}
					if (is_array(@$DATE_FIELDS) && $parseDatesJS) {
						if (in_array($k, $DATE_FIELDS))
							$resultOK[$k] = date("c", strtotime($v));	// Formattage de la date au format ISO 8601 (pour que JS puisse la parser)
					}
				}
				if (count($resultOK) == 1)							// Si une seule valeur demandée, pas besoin d'une dimension en plus
					$retour[$i] = reset($resultOK);
				else {
					$retour[$i] = $resultOK;
				}
				$i++;
			}
			$this->listResult = $retour ;
			return $retour;
		}
		else return false;
	}
	/**
	 * Retourne le nombre d'entrée trouvées
	 */
	public function countResults () {
		return count($this->listResult);
	}

	/**
	 * Ajoute une condition au filtre pour la requête
	 * @param STRING $filtre_key Le nom du champ pour le filtre
	 * @param STRING $filtre_comp La comparaison à utiliser pour le filtre (default "=")
	 * @param STRING $filtre La valeur à comparer
	 * @param STRING $logique Le type de logique à utiliser avec les éventuels précédents filtres (default "AND")
	 */
	public function addFiltre($filtre_key=false, $filtre_comp='=', $filtre=false , $logique='AND'){
		if (!$filtre_key) throw new Exception("Il manque le nom du champ à utiliser pour le filtre");
		$filtre = addslashes($filtre);
		$this->filtres[] = " (`$filtre_key` $filtre_comp '$filtre') $logique " ;
		$this->lastLogiquefiltre = $logique;
	}
	/**
	 * Ajoute une condition au filtre pour la requête, en mode "moins sécurisé", afin de permettre les fonctions SQL à la place d'une string pour $filtre.
	 * @param STRING $filtre_key Le nom du champ pour le filtre
	 * @param STRING $filtre_comp La comparaison à utiliser pour le filtre (default "=")
	 * @param STRING $filtre La valeur à comparer
	 * @param STRING $logique Le type de logique à utiliser avec les éventuels précédents filtres (default "AND")<commit_msg>Liste class: Fixbug count if new request after another (reset listResult prop)<commit_after><?php
/**
	Copyright (C) 2015  Polosson

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * SQL TABLE LISTING abstraction layer, with advanced filters
 */
class Liste {
	/**
	 * @var STRING Résultat de la chaine compilée par getListe() au moment de la requête SQL
	 */
	public $request;
	/**
	 * @var ARRAY Résultat des entrées retournées par getListe()
	 */
	public $listResult;
	/**
	 * @var OBJECT Instance PDO pour la connexion SQL
	 */
	protected $bddCx;
	/**
	 * @var STRING Nom de la table courante
	 */
	protected $table;

	private $what;
	private $tri;
	private $ordre;
	private $filtre_key;
	private $filtre;
	private $lastLogiquefiltre;
	private $isFiltred = false;
	private $filtres = Array();
	private $filtreSQL;

	/**
	 * LISTING de table SQL
	 * @param OBJECT $pdoInstance Une instance de PDO préinitialisée (optionnel)
	 */
	public function __construct ($pdoInstance=false) {
		if (!$pdoInstance || !is_object($pdoInstance))
			$this->initPDO();
		else
			$this->bddCx = $pdoInstance;
	}
	public function __destruct () {
		$this->bddCx = null;
	}

	/**
	 * Initialise une liste de données à récupérer pour une table donnée
	 * @param STRING $table Le nom de la table
	 * @param STRING $want Une liste de colonnes à retourner (default '*' (tout))
	 * @param STRING $tri La colonne à utiliser pour le tri (default 'id')
	 * @param STRING $ordre La direction du tri (default 'ASC')
	 * @param STRING $filtre_key La colonne à utiliser pour filtrer les résultats (default FALSE (pas de filtre))
	 * @param STRING $filtre_comp La comparaison à effectuer pour le filtrage (default '=')
	 * @param STRING $filtre La valeur à utiliser pour filtrer les résultats (default null)
	 * @param INT $limit Nombre maximum de données à retourner (default FALSE (pas de limite)
	 * @param BOOLEAN $decodeJson TRUE pour décoder les champs contenant du JSON automatiquement. FALSE pour avoir les champs JSON au format STRING (default TRUE)
	 * @return ARRAY Le tableau des résultats, ou FALSE si aucune donnée
	 */
	public function getListe ($table, $want='*', $tri='id', $ordre='ASC', $filtre_key=false, $filtre_comp='=', $filtre=null, $limit=false, $withFK=true, $decodeJson=true, $parseDatesJS=true) {
		global $DATE_FIELDS;
		$this->listResult = Array();
		$this->table = $table;
		$this->what  = $want;
		$this->tri	 = $tri;
		$this->ordre = $ordre;
		// Check si table existe
		if (!$this->check_table_exist($table))
			throw new Exception("Liste::getListe() : La table '$table' n'existe pas");
		// pour chaque filtre défini par Liste::addFiltre()
		if (is_array($this->filtres) && count($this->filtres) > 0) {
			$FM = '' ;
			foreach ($this->filtres as $f) $FM .= $f;
			$filtrage_multiple = trim($FM, " $this->lastLogiquefiltre ");
		}
		if ($filtre_key && (string)$filtre != null ) {
			if (Liste::check_col_exist($filtre_key)) {
				$this->isFiltred  = true;
				$this->filtre_key = $filtre_key;
				$this->filtre	  = addslashes($filtre);
			}
			else return false ;
		}
		if ($this->isFiltred)
			$this->request = "SELECT $this->what FROM `$this->table` WHERE `$this->filtre_key` $filtre_comp '$this->filtre' ORDER BY `$tri` $ordre";
		elseif (isset($filtrage_multiple))
			$this->request = "SELECT $this->what FROM `$this->table` WHERE $filtrage_multiple ORDER BY `$tri` $ordre";
		elseif (isset($this->filtreSQL))
			$this->request = "SELECT $this->what FROM `$this->table` WHERE $this->filtreSQL ORDER BY `$tri` $ordre";
		else
			$this->request = "SELECT $this->what FROM `$this->table` ORDER BY `$this->tri` $this->ordre";
		if (is_int($limit))
			$this->request .= " LIMIT $limit";
		$q = $this->bddCx->prepare($this->request) ;
		$q->execute();

		if ($q->rowCount() >= 1) {							// Formatage des résultats de la requête
			$result = $q->fetchAll(PDO::FETCH_ASSOC);
			$retour = array();
			$i = 0;
			foreach ($result as $resultOK) {
				unset($resultOK['password']);
				foreach ($resultOK as $k => $v) {					// Décodage JSON le cas échéant
					if ($decodeJson && is_string($v) && preg_match('/((^\[)*(]$))|((^\{")*(}$))/', $v)) {
						$valArr = json_decode($v, true);
						if (!is_array($valArr)) continue;
						$resultOK[$k] = $valArr;
					}												// Remplacement par la Foreign Key le cas échéant
					if ($withFK && preg_match("/^".FOREIGNKEYS_PREFIX."/", $k)) {
						$fk = $this->getForeignKey($k, $v, $decodeJson, $parseDatesJS);
						if (!is_array($fk)) continue;
						$resultOK[$fk[0]] = $fk[1];
					}
					if (is_array(@$DATE_FIELDS) && $parseDatesJS) {
						if (in_array($k, $DATE_FIELDS))
							$resultOK[$k] = date("c", strtotime($v));	// Formattage de la date au format ISO 8601 (pour que JS puisse la parser)
					}
				}
				if (count($resultOK) == 1)							// Si une seule valeur demandée, pas besoin d'une dimension en plus
					$retour[$i] = reset($resultOK);
				else
					$retour[$i] = $resultOK;
				$i++;
			}
			$this->listResult = $retour ;
			return $retour;
		}
		else return false;
	}
	/**
	 * Retourne le nombre d'entrées trouvées
	 */
	public function countResults () {
		if (!$this->listResult)
			return 0;
		return count($this->listResult);
	}

	/**
	 * Ajoute une condition au filtre pour la requête
	 * @param STRING $filtre_key Le nom du champ pour le filtre
	 * @param STRING $filtre_comp La comparaison à utiliser pour le filtre (default "=")
	 * @param STRING $filtre La valeur à comparer
	 * @param STRING $logique Le type de logique à utiliser avec les éventuels précédents filtres (default "AND")
	 */
	public function addFiltre($filtre_key=false, $filtre_comp='=', $filtre=false , $logique='AND'){
		if (!$filtre_key) throw new Exception("Il manque le nom du champ à utiliser pour le filtre");
		$filtre = addslashes($filtre);
		$this->filtres[] = " (`$filtre_key` $filtre_comp '$filtre') $logique " ;
		$this->lastLogiquefiltre = $logique;
	}
	/**
	 * Ajoute une condition au filtre pour la requête, en mode "moins sécurisé", afin de permettre les fonctions SQL à la place d'une string pour $filtre.
	 * @param STRING $filtre_key Le nom du champ pour le filtre
	 * @param STRING $filtre_comp La comparaison à utiliser pour le filtre (default "=")
	 * @param STRING $filtre La valeur à comparer
	 * @param STRING $logique Le type de logique à utiliser avec les éventuels précédents filtres (default "AND")
{'fraction_non_alphanumeric': 0.13790859126410182, 'fraction_numerical': 0.0022418281747179636, 'mean_word_length': 3.7984038861901457, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5359607', 'n_tokens_mistral': 5204, 'n_tokens_neox': 4787, 'n_words': 1534}