You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
570 lines
16 KiB
570 lines
16 KiB
<?php |
|
namespace formidable_ts; |
|
if (!defined('_ECRIRE_INC_VERSION')) { |
|
return; |
|
} |
|
include_spip('inc/sql'); |
|
include_spip('inc/saisies'); |
|
include_spip('inc/cextras'); |
|
include_spip('saisies/afficher_si_php'); |
|
/* |
|
* La classe principale |
|
* qui cherche les données en base |
|
* et retourne un tableau json si besoin |
|
*/ |
|
class table { |
|
private $size; |
|
private $page; |
|
private $id_formulaire; |
|
private $filter; |
|
private $sort; |
|
private $rows; |
|
private $headers; |
|
private $champs; |
|
private $champs_finaux; |
|
private $champs_finaux_par_nom; |
|
private $cextras; |
|
private $cextras_finaux; |
|
private $cextras_finaux_par_nom; |
|
private $statut; |
|
private $totalRows; |
|
private $columns; |
|
/** |
|
* @param array $env |
|
* L'env du squelette |
|
**/ |
|
public function __construct($env) { |
|
$this->id_formulaire = sql_quote($env['id_formulaire'] ?? null); |
|
$this->totalRows=0; |
|
// Transformer les filtres en pseudo afficher_si |
|
$this->filter = $env['filter'] ?? array(); |
|
if (!$this->filter) {// Peut être '' |
|
$this->filter = array(); |
|
} |
|
$this->filter = array_map(function($a) { |
|
$a = strtolower($a); |
|
if (!preg_match('#(=|>|<|MATCH)#', $a)) { |
|
$a = " MATCH '/$a/'"; |
|
} |
|
$a = rawurldecode($a); |
|
return $a; |
|
}, |
|
$this->filter |
|
); |
|
$this->sort = $env['sort'] ?? array(); |
|
if (!$this->sort) { |
|
$this->sort = array();//Ne pas autoriser '' |
|
} |
|
$env['statut'] = $env['statut'] ?? null; |
|
$this->statut = \sql_quote($env['statut'] ? $env['statut'] : '.*'); |
|
|
|
$formulaire_detail = sql_fetsel('saisies, traitements', 'spip_formulaires', "id_formulaire=$this->id_formulaire"); |
|
include_spip('formidable_fonctions'); |
|
if (function_exists('\formidable_deserialize')) { |
|
$this->champs = \formidable_deserialize($formulaire_detail['saisies']); |
|
} else { |
|
$this->champs = \unserialize($formulaire_detail['saisies']); |
|
} |
|
// Afficher les ip ? |
|
if (lire_config('formidable/exporter_adresses_ip')) { |
|
$this->ip = true; |
|
} else { |
|
$this->ip = false; |
|
} |
|
$this->champs_finaux = \saisies_lister_finales($this->champs); |
|
$this->champs_finaux_par_nom = \saisies_lister_par_nom($this->champs_finaux); |
|
if (\test_plugin_actif('cextras')) { |
|
include_spip('cextras_pipelines'); |
|
$champs = \champs_extras_objet('spip_formulaires_reponses'); |
|
$champs = \champs_extras_autorisation( |
|
'voir', |
|
'formulaires_reponse', |
|
$champs, |
|
['id_objet' => sql_getfetsel('id_formulaires_reponse', 'spip_formulaires_reponses', 'id_formulaire='.$this->id_formulaire, '', '', '0,1')]//Pour l'autorisation de voir, prendre un réponse au pif dans le formulaire |
|
); |
|
$this->cextras = $champs; |
|
$this->cextras_finaux = \saisies_lister_finales($this->cextras); |
|
$this->cextras_finaux_par_nom = \saisies_lister_par_nom($this->cextras_finaux); |
|
} else { |
|
$this->cextras_finaux = array(); |
|
$this->cextras_finaux_par_nom = array(); |
|
} |
|
if (!$this->cextras) { |
|
$this->cextras = array(); |
|
} |
|
$this->rows = array(); |
|
$this->headers = array(); |
|
$this->page = $env['page_ts'] ?? 1 ; |
|
$this->size = $env['size'] ?? 100; |
|
$this->setColumns($env['order'] ?? array()); |
|
} |
|
|
|
/** |
|
* Définir les colonnes et leur ordre |
|
* @param array $order ordre des colonnes envoyé; |
|
* @return array |
|
**/ |
|
function setColumns($order = array()) { |
|
$columns = array(); |
|
$columns[] = 'natif-statut'; |
|
$columns[] = 'natif-id_formulaires_reponse'; |
|
$columns[] = 'natif-date_envoi'; |
|
if ($this->ip) { |
|
$columns[] = 'natif-ip'; |
|
} |
|
foreach ($this->cextras_finaux as $extra) { |
|
if ($extra['saisie'] == 'explication') { |
|
continue; |
|
} |
|
$columns[] = 'extra-'.$extra['options']['nom']; |
|
} |
|
foreach ($this->champs_finaux as $champ) { |
|
if ($champ['saisie'] == 'explication') { |
|
continue; |
|
} |
|
$columns[] = 'champ-'.$champ['options']['nom']; |
|
} |
|
// Ajouter les nouvelles colonnes à la fin, et soustraire celles qui n'existent plus |
|
$diff = array_diff($columns, $order); |
|
$this->columns = array_merge($order, $diff); |
|
$this->columns = array_intersect($this->columns, $columns); |
|
} |
|
|
|
/** |
|
* Peupler headers et rows |
|
**/ |
|
public function setData() { |
|
$this->setRows(); |
|
$this->setHeaders(); |
|
} |
|
|
|
/** |
|
* Peupler les headers à partir de la base SQL |
|
**/ |
|
public function setHeaders() { |
|
$headers = &$this->headers; |
|
foreach ($this->columns as $column) { |
|
list($type, $nom) = explode('-', $column); |
|
if ($type === 'natif') { |
|
if ($nom === 'statut') { |
|
$headers[] = new header([ |
|
'table' => $this, |
|
'type' => 'natif', |
|
'nom' => 'statut', |
|
'value' => '#' |
|
]); |
|
} elseif ($nom === 'id_formulaires_reponse') { |
|
$headers[] = new header([ |
|
'table' => $this, |
|
'type' => 'natif', |
|
'nom' => 'id_formulaires_reponse', |
|
'value' => _T('info_numero_abbreviation') |
|
]); |
|
} elseif ($nom === 'date_envoi') { |
|
$headers[] = new header ([ |
|
'table' => $this, |
|
'type' => 'natif', |
|
'nom' => 'date_envoi', |
|
'value' => _T('formidable:date_envoi') |
|
]); |
|
} elseif ($nom === 'ip') { |
|
$headers[] = new header ([ |
|
'table' => $this, |
|
'type' => 'natif', |
|
'nom' => 'ip', |
|
'value' => _T('formidable:reponses_ip') |
|
]); |
|
} |
|
} else { |
|
if ($type === 'extra') { |
|
$saisies = $this->cextras; |
|
} else { |
|
$saisies = $this->champs; |
|
} |
|
$saisie = \saisies_chercher($saisies, $nom); |
|
$chemin = \saisies_chercher($saisies, $nom, true); |
|
if (count($chemin) > 1) { |
|
$fieldset = $saisies[$chemin[0]]; |
|
$fieldset = $fieldset['options']['label']; |
|
} else { |
|
$fieldset = ''; |
|
} |
|
$label = $saisie['options']['label'] ?? $saisie['options']['label_case'] ?? $saisie['options']['nom']; |
|
if ($fieldset) { |
|
$label .= " <span class='fieldset_label'>($fieldset)</span>"; |
|
} |
|
$headers[] = new header ([ |
|
'table' => $this, |
|
'type' => $type, |
|
'nom' => $saisie['options']['nom'], |
|
'value' => $label |
|
]); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Peupler les lignes à partir de la base SQL |
|
**/ |
|
private function setRows() { |
|
$res_reponse = \sql_select('*', |
|
'spip_formulaires_reponses', |
|
array( |
|
"id_formulaire= $this->id_formulaire", |
|
"statut REGEXP $this->statut" |
|
), |
|
'', |
|
'DATE DESC' |
|
); |
|
|
|
|
|
while ($row_reponse = \sql_fetch($res_reponse)) { |
|
$id_formulaires_reponse = $row_reponse['id_formulaires_reponse']; |
|
$row_ts = []; |
|
$this->totalRows++; |
|
foreach ($this->columns as $column) { |
|
list($type, $nom) = explode('-', $column); |
|
if ($type === 'natif') { |
|
if ($nom === 'statut') { |
|
$value = \liens_absolus(\appliquer_filtre($row_reponse['statut'], 'puce_statut', 'formulaires_reponse', $row_reponse['id_formulaires_reponse'], true)); |
|
$row_ts[] = new cell([ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => 'statut', |
|
'value' => $value, |
|
'sort_value' => $row_reponse['statut'], |
|
'filter_value' => $row_reponse['statut'], |
|
'crayons' => false, |
|
'type' => 'natif' |
|
]); |
|
} elseif ($nom === 'id_formulaires_reponse') { |
|
$value = '<a href="'.\generer_url_ecrire('formulaires_reponse', 'id_formulaires_reponse='.$row_reponse['id_formulaires_reponse']).'">'.$row_reponse['id_formulaires_reponse'].'</a>'; |
|
$row_ts[] = new cell([ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => 'id_formulaires_reponse', |
|
'value' => $value, |
|
'sort_value' => intval($row_reponse['id_formulaires_reponse']), |
|
'filter_value' => $row_reponse['id_formulaires_reponse'], |
|
'crayons' => false, |
|
'type' => 'natif' |
|
]); |
|
} elseif ($nom === 'date_envoi') { |
|
$value = \affdate_heure($row_reponse['date_envoi']); |
|
$row_ts[] = new cell([ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => 'date_envoi', |
|
'value' => $value, |
|
'sort_value' => \strtotime($row_reponse['date_envoi']), |
|
'filter_value' => $value, |
|
'crayons' => false, |
|
'type' =>'natif' |
|
]); |
|
} elseif ($nom === 'ip') { |
|
$value = $row_reponse['ip']; |
|
$row_ts[] = new cell([ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => 'date_envoi', |
|
'value' => $value, |
|
'sort_value' => $value, |
|
'filter_value' => $value, |
|
'crayons' => false, |
|
'type' =>'natif' |
|
]); |
|
} |
|
} else { |
|
if ($type === 'extra') { |
|
$champ = $this->cextras_finaux_par_nom[$nom]; |
|
$crayons = false; |
|
$nom = $champ['options']['nom']; |
|
if (test_plugin_actif('crayons')) { |
|
$opt = array( |
|
'saisie' => $champ, |
|
'type' => 'formulaires_reponse', |
|
'champ' => $nom, |
|
'table' => table_objet_sql('formulaires_reponse'), |
|
); |
|
if (autoriser('modifierextra', 'formulaires_reponse', $id_formulaires_reponse, '', $opt)) { |
|
$crayons = true; |
|
} |
|
} |
|
if (isset($champ['options']['traitements'])) { |
|
$value = \appliquer_traitement_champ($row_reponse[$nom], $nom, 'formulaires_reponse'); |
|
} else { |
|
$value = implode(\calculer_balise_LISTER_VALEURS('formulaires_reponses', $nom, $row_reponse[$nom]), ', '); |
|
} |
|
$row_ts[] = new cell( |
|
[ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => $nom, |
|
'value' => $value, |
|
'sort_value' => sort_value($value, $champ, 'extra'), |
|
'filter_value' => null, |
|
'crayons' => $crayons, |
|
'type' => 'extra' |
|
] |
|
); |
|
} else { // Réponse de l'internaute |
|
$value = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'valeur_uniquement'); |
|
$value_raw = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'brut'); |
|
$champ = $this->champs_finaux_par_nom[$nom]; |
|
$row_ts[] = new cell( |
|
[ |
|
'table' => $this, |
|
'id_formulaires_reponse' => $id_formulaires_reponse, |
|
'nom' => $nom, |
|
'value' => $value, |
|
'sort_value' => sort_value($value_raw, $champ, 'champ'), |
|
'filter_value' => null, |
|
'crayons' => true, |
|
'type' => 'champ' |
|
] |
|
); |
|
} |
|
} |
|
} |
|
// Vérifier si cela passe le filtres: |
|
if ($this->checkFilter($row_ts)) { |
|
$this->rows[] = $row_ts; |
|
} |
|
} |
|
$this->sortRows(); |
|
} |
|
|
|
/** |
|
* Vérifier si une ligne passe les tests de filtre |
|
* @param array $row |
|
* @return bool |
|
**/ |
|
private function checkFilter($row) { |
|
foreach ($this->filter as $col=>$filter) { |
|
$result = saisies_evaluer_afficher_si( |
|
$filter, |
|
array(), |
|
array(), |
|
$row[$col]->filter_value |
|
); |
|
if ($result == false) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
/** |
|
* Tri les lignes selon les paramètres passée en option |
|
**/ |
|
private function sortRows() { |
|
if (class_exists('Collator')) { |
|
$collator = new \Collator('fr'); |
|
} else { |
|
include_spip('inc/charsets'); |
|
} |
|
usort($this->rows, function ($a, $b) { |
|
// Trouver les cellules sur lesquelles trier |
|
foreach ($this->sort as $column => $sort) { |
|
$sort = intval($sort); |
|
$a_sort = $a[$column]->sort_value; |
|
$b_sort = $b[$column]->sort_value; |
|
if ($a_sort == $b_sort) { |
|
continue;//Si égalité sur la premièr colonne, on testera colonne suivante |
|
} else { |
|
if (is_string($a_sort)) { |
|
if (isset($collator)) { |
|
$result = $collator->compare($a_sort, $b_sort); |
|
} else { |
|
$result = (\translitteration($a_sort) < \translitteration($b_sort)) ? -1 : 1; |
|
} |
|
} else { |
|
$result = ($a_sort < $b_sort) ? -1 : 1; |
|
} |
|
if ($sort) { |
|
return -$result; |
|
} else { |
|
return $result; |
|
} |
|
} |
|
} |
|
return 0;// Si tous les tests échoue à comparaison, c'est que nos deux lignes sont identiques, en ce qui concerne les critères de tri |
|
}); |
|
} |
|
/** |
|
* Retourne le json final |
|
* @return string |
|
**/ |
|
public function getJson() { |
|
$json = array( |
|
'filteredRows' => \count($this->rows), |
|
'rows' => array_slice($this->rows, $this->page*$this->size, $this->size), |
|
'headers' => $this->headers, |
|
'total' => $this->totalRows, |
|
); |
|
return \json_encode($json); |
|
} |
|
/** |
|
* Compte le nombre d'entetes |
|
* @return int |
|
**/ |
|
public function countHeaders() { |
|
return count($this->headers); |
|
} |
|
|
|
/** |
|
* Return la propriété, permet d'y accéder mais pas de la modifier |
|
* @param string $prop |
|
**/ |
|
public function __get($prop) { |
|
return $this->$prop; |
|
} |
|
|
|
} |
|
/** |
|
* Classe représentant une cellule |
|
* @var str|int $id_formulaire |
|
* @var str|int $id_formulaires_reponse |
|
* @var str|int $nom |
|
* @var str $value valeur de la cellule, |
|
* @var str $sort_value valeur de la cellule, pour le tri |
|
* @var bool $crayons est-ce crayonnable? |
|
* @var string $type natif|extra|champ |
|
**/ |
|
class cell implements \JsonSerializable{ |
|
private $table; |
|
private $id_formulaires_reponse; |
|
private $nom; |
|
private $value; |
|
private $sort_value; |
|
private $filter_value; |
|
private $crayons; |
|
private $type; |
|
|
|
public function __construct($param = array()) { |
|
$this->table = $param['table'] ?? false; |
|
$this->id_formulaires_reponse = $param['id_formulaires_reponse'] ?? false; |
|
$this->nom = $param['nom']; |
|
$this->value = $param['value']; |
|
$this->sort_value = $param['sort_value'] ?? \textebrut($this->value); |
|
if (function_exists('mb_strtolower')) { |
|
$this->filter_value = \mb_strtolower($param['filter_value'] ?? \textebrut($this->value)); |
|
} else { |
|
include_spip('inc/charsets'); |
|
$this->filter_value = \strtolower(\translitteration($param['filter_value'] ?? \textebrut($this->value))); |
|
} |
|
$this->crayons= $param['crayons'] ?? false; |
|
$this->type = $param['type'] ?? 'champ'; |
|
} |
|
|
|
/** |
|
* Returne la valeur string, avec le span englobant, pour les crayons |
|
**/ |
|
public function jsonSerialize(): string{ |
|
if ($this->crayons) { |
|
if ($this->type == 'extra') { |
|
$class = classe_boucle_crayon('formulaires_reponse', $this->nom, $this->id_formulaires_reponse); |
|
} elseif ($this->type == 'champ') { |
|
$class = \calculer_voir_reponse($this->id_formulaires_reponse, $this->table->id_formulaire, $this->nom, '', 'edit'); |
|
} |
|
$value = $this->value ? $this->value : ' '; |
|
return "<div class='$class'>$value</div>"; |
|
} else { |
|
return $this->value; |
|
} |
|
} |
|
/** |
|
* Return la propriété, permet d'y accéder mais pas de la modifier |
|
* @param string $prop |
|
**/ |
|
public function __get($prop) { |
|
return $this->$prop; |
|
} |
|
} |
|
|
|
/** |
|
* Classe implémentant un entete |
|
* C'est comme une cellule, mais ca donne en plus les flèches de déplacement + des datas attributs sur le nom |
|
**/ |
|
class header extends cell { |
|
|
|
/** |
|
* Returne la valeur string, avec le span englobant, pour les crayons |
|
**/ |
|
public function jsonSerialize(): string { |
|
$data_col = "$this->type-$this->nom"; |
|
$arrows = "<div data-col='$data_col' class='move-arrows'><a class='left'>⬅</a> <a class='right'>➡</a></div>"; |
|
return "$arrows\n\r<div class='header-title'>$this->value</div>"; |
|
} |
|
} |
|
/** |
|
* Depuis le #ENV de l'ajax appelé détermine le json à retourner |
|
* Un simple wrapper pour une classe en fait |
|
* @param array $env |
|
* @return string json |
|
**/ |
|
function formidable_ts_json($env) { |
|
$formidable_ts = new table($env); |
|
$formidable_ts->setData(); |
|
return $formidable_ts->getJson(); |
|
} |
|
|
|
|
|
/** |
|
* Appelle le pipeline formidable_ts_sort_value |
|
* Pour trouver le type de tri |
|
* @param str|int $valeur valeur brute du champ de formulaire |
|
* @param array $saisie decrit la saisie |
|
* @param string $type='champ' ou bien 'extra' |
|
* @return string valeur du data-sort-attribut |
|
**/ |
|
function sort_value($valeur, $saisie, $type = 'champ') { |
|
if ($saisie['saisie'] === 'evenements' and $valeur) { |
|
if (!is_array($valeur)) { |
|
$data = \sql_getfetsel('date_debut', 'spip_evenements', 'id_evenement='.$valeur); |
|
} else { |
|
$data = \sql_getfetsel('date_debut', 'spip_evenements', sql_in('id_evenement', $valeur), '', 'date_debut', '0,1'); |
|
} |
|
} else { |
|
$data = $valeur; |
|
} |
|
if ($type === 'extra') { |
|
if (strpos($saisie['options']['sql'], 'INT') !== false |
|
or |
|
strpos($saisie['options']['sql'], 'FLOAT') !== false |
|
or |
|
strpos($saisie['options']['sql'], 'DATE') !== false |
|
) { |
|
$data = $valeur; |
|
} |
|
} |
|
$array = false; |
|
if (is_array($data)) { |
|
$data = \json_encode($data); |
|
$array = true; |
|
} |
|
$data = trim($data); |
|
if (function_exists('mb_strtolower')) { |
|
$data = mb_strtolower($data); |
|
} else { |
|
include_spip('inc/charsets'); |
|
$data = \strtolower(\translitteration($data)); |
|
} |
|
if ($array) { |
|
$data = \json_decode($data, true); |
|
} |
|
|
|
if (is_numeric($data)) { |
|
$data = floatval($data); |
|
} |
|
|
|
|
|
return pipeline ('formidable_ts_sort_value', array( |
|
'args' => array( |
|
'valeur' => $valeur, |
|
'saisie' => $saisie, |
|
'type' => $type |
|
), |
|
'data' => $data |
|
)); |
|
}
|
|
|