@ -1,23 +1,23 @@
<?php
namespace formidable_ts;
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/sql');
namespace Formidable_ts;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Common\Entity\Style\Color;
include_spip('inc/saisies');
include_spip('inc/cextra s');
include_spip('saisies/afficher_si_php ');
include_spip('public/fonction s');
include_spip('inc/filtres ');
/*
* La classe principale
* qui cherche les données en base
* et retourne un tableau json si besoin
*/
class t able {
class T able {
private $size;
private $page;
private $id_formulaire;
private $filter;
private $sort;
private $filters;
private $rows;
private $headers;
private $champs;
@ -29,42 +29,28 @@ class table {
private $statut;
private $totalRows;
private $columns;
private $setting;
private $identifiant;
/**
* @param array $env
* @param array $statut
* L'env du squelette
**/
public function __construct($env) {
$this->id_formulaire = sql_quote($env['id_formulaire'] ?? null);
public function __construct($statut, $setting) {
$this->id_formulaire = $setting->get('id_formulaire');
$this->setting = $setting;
$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();
$this->sort = $setting->get('sort') ?? array();
if (!$this->sort) {
$this->sort = array();//Ne pas autoriser ''
}
$env['statut'] = $env['statut'] ?? null;
$this->statut = \sql_quote($env['statut'] ? $env['statut'] : '.*');
$this->statut = \sql_quote($statut ? $statut : '.*');
$formulaire_detail = sql_fetsel('saisies, traitements, identifiant', 'spip_formulaires', "id_formulaire=$this->id_formulaire");
$this->identifiant = $formulaire_detail['identifiant'];
$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']);
}
$this->champs = \formidable_deserialize($formulaire_detail['saisies']);
// Afficher les ip ?
if (lire_config('formidable/exporter_adresses_ip')) {
$this->ip = true;
@ -94,17 +80,41 @@ class table {
}
$this->rows = array();
$this->headers = array();
$this->page = $env['page_ts'] ?? 1 ;
$this->size = $env['size'] ?? 100;
$this->setColumns($env['order'] ?? array());
$this->page = $setting->get('page');
$this->size = $setting->get('size');
$this->setColumns();
$this->setFilters();
}
/**
* Ajuster les filtres
**/
private function setFilters() : void {
// En base les filtres sont stockés par nom de column, mais pour tablesorter il faut les indiquer par position de column -> on converti
$filters = $this->setting->get('filters') ?? array();
$this->raw_filters = array();
foreach ($filters as $f => $filter) {
$this->raw_filters[array_search($f, $this->columns)] = $filter;
}
// Transformer les filtres en pseudo afficher_si
$this->filters = array_map(function($a) {
$a = strtolower($a);
if (!preg_match('#(=|>|< |MATCH)#', $a) and $a) {
$a = " MATCH '/$a/'";
}
$a = rawurldecode($a);
return $a;
},
$this->raw_filters
);
}
/**
* Définir les colonnes et leur ordre
* @param array $order ordre des colonnes envoyé;
* @return array
**/
function setColumns($order = array()) {
private function setColumns() : void {
$columns = array();
$columns[] = 'natif-statut';
$columns[] = 'natif-id_formulaires_reponse';
@ -124,14 +134,17 @@ 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);
$this->setting->set(
[
'action' => 'columns',
'value' => $columns
]
);
$this->columns = $this->setting->get('order');
}
/**
* Peupler h eaders et rows
* Peupler H eaders et rows
**/
public function setData() {
$this->setRows();
@ -139,7 +152,7 @@ continue;
}
/**
* Peupler les h eaders à partir de la base SQL
* Peupler les H eaders à partir de la base SQL
**/
public function setHeaders() {
$headers = &$this->headers;
@ -147,28 +160,28 @@ continue;
list($type, $nom) = explode('-', $column);
if ($type === 'natif') {
if ($nom === 'statut') {
$headers[] = new h eader([
$headers[] = new H eader([
'table' => $this,
'type' => 'natif',
'nom' => 'statut',
'value' => '#'
]);
} elseif ($nom === 'id_formulaires_reponse') {
$headers[] = new h eader([
$headers[] = new H eader([
'table' => $this,
'type' => 'natif',
'nom' => 'id_formulaires_reponse',
'value' => _T('info_numero_abbreviation')
]);
} elseif ($nom === 'date_envoi') {
$headers[] = new h eader ([
$headers[] = new H eader ([
'table' => $this,
'type' => 'natif',
'nom' => 'date_envoi',
'value' => _T('formidable:date_envoi')
]);
} elseif ($nom === 'ip') {
$headers[] = new h eader ([
$headers[] = new H eader ([
'table' => $this,
'type' => 'natif',
'nom' => 'ip',
@ -193,7 +206,7 @@ continue;
if ($fieldset) {
$label .= " < span class = 'fieldset_label' > ($fieldset)< / span > ";
}
$headers[] = new h eader ([
$headers[] = new H eader ([
'table' => $this,
'type' => $type,
'nom' => $saisie['options']['nom'],
@ -222,13 +235,16 @@ continue;
$id_formulaires_reponse = $row_reponse['id_formulaires_reponse'];
$row_ts = [];
$this->totalRows++;
$column_range = -1;
foreach ($this->columns as $column) {
list($type, $nom) = explode('-', $column);
$column_range++;
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 c ell([
$Cell = new C ell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'statut',
'value' => $value,
@ -239,8 +255,9 @@ continue;
]);
} 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 c ell([
$Cell = new C ell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'id_formulaires_reponse',
'value' => $value,
@ -251,8 +268,9 @@ continue;
]);
} elseif ($nom === 'date_envoi') {
$value = \affdate_heure($row_reponse['date_envoi']);
$row_ts[] = new c ell([
$Cell = new C ell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'date_envoi',
'value' => $value,
@ -263,8 +281,9 @@ continue;
]);
} elseif ($nom === 'ip') {
$value = $row_reponse['ip'];
$row_ts[] = new c ell([
$Cell = new C ell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'date_envoi',
'value' => $value,
@ -274,8 +293,7 @@ continue;
'type' =>'natif'
]);
}
} else {
if ($type === 'extra') {
} elseif ($type === 'extra') {
$champ = $this->cextras_finaux_par_nom[$nom];
$crayons = false;
$nom = $champ['options']['nom'];
@ -295,63 +313,106 @@ continue;
} else {
$value = implode(\calculer_balise_LISTER_VALEURS('formulaires_reponses', $nom, $row_reponse[$nom]), ', ');
}
$row_ts[] = new c ell(
$Cell = new C ell(
[
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => $nom,
'value' => $value,
'sort_value' => sort_value($value, $champ, 'extra'),
'sort_value' => $this-> 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'
]
);
}
} 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];
$Cell = new Cell(
[
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => $nom,
'value' => $value,
'sort_value' => $this->sort_value($value_raw, $champ, 'champ'),
'filter_value' => null,
'crayons' => true,
'type' => 'champ'
]
);
}
// Verifier si la Cellulle passe le test
if ($Cell->checkFilter()) {
$row_ts[] = $Cell;
} else {
continue 2;
}
}
// Vérifier si cela passe le filtres:
if ($this->checkFilter($row_ts)) {
$this->rows[] = $row_ts;
}
$this->rows[] = $row_ts;
}
$this->sortRows();
}
/**
* Vérifier si une ligne passe les tests de filtre
* @param array $row
* @return bool
* 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
**/
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;
private 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;
}
}
return true;
$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
));
}
/**
@ -364,7 +425,7 @@ continue;
include_spip('inc/charsets');
}
usort($this->rows, function ($a, $b) {
// Trouver les c ellules sur lesquelles trier
// Trouver les C ellules sur lesquelles trier
foreach ($this->sort as $column => $sort) {
$sort = intval($sort);
$a_sort = $a[$column]->sort_value;
@ -401,9 +462,11 @@ continue;
'rows' => array_slice($this->rows, $this->page*$this->size, $this->size),
'headers' => $this->headers,
'total' => $this->totalRows,
'filters' => array_replace(array_fill(0, count($this->headers), ''), $this->raw_filters)
);
return \json_encode($json);
}
/**
* Compte le nombre d'entetes
* @return int
@ -420,151 +483,42 @@ continue;
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
* Exporte les données sous forme de tableu
* @param string type: csv|xlsx|ods
* @return void
**/
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;
}
}
public function export(string $type = 'csv') {
/**
* 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 {
require_once find_in_path('lib/Spout/Autoloader/autoload.php');
$filename = $this->identifiant;
/**
* 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();
}
$style_headers = (new StyleBuilder())
->setFontBold()
->build();
/**
* 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');
}
if ($type == 'csv') {
$writer = WriterEntityFactory::createCSVWriter();
} elseif ($type == 'ods') {
$writer = WriterEntityFactory::createODSWriter();
} 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;
}
$writer = WriterEntityFactory::createXLSXWriter();
}
$array = false;
if (is_array($data)) {
$data = \json_encode($data);
$array = true;
}
$data = trim($data);
if (function_exists('mb_strtolower')) {
$data = mb_strtolower($data);
$writer->openToBrowser("$filename.$type_export");
$headers = array_map('strval', $this->headers);
if ($type === 'csv') {
$writer->addRow(WriterEntityFactory::createRowFromArray($headers));
} else {
include_spip('inc/charsets');
$data = \strtolower(\translitteration($data));
$writer->addRow(WriterEntityFactory::createRowFromArray($headers, $style_headers));
}
if ($array) {
$data = \json_decode($data, true);
foreach ($this->rows as $content) {
$content = array_map('strval', $content);
if ($type === 'csv') {
$writer->addRow(WriterEntityFactory::createRowFromArray($content));
} else {
$writer->addRow(WriterEntityFactory::createRowFromArray($content, $style_entete));
}
}
if (is_numeric($data)) {
$data = floatval($data);
$writer->close();
}
return pipeline ('formidable_ts_sort_value', array(
'args' => array(
'valeur' => $valeur,
'saisie' => $saisie,
'type' => $type
),
'data' => $data
));
}