539 lines
18 KiB
PHP
539 lines
18 KiB
PHP
<?php
|
||
|
||
|
||
namespace App\Models;
|
||
|
||
use CodeIgniter\Model;
|
||
use Config\Database;
|
||
class EventsModel extends Model
|
||
{
|
||
protected $table = 'reader_config'; // table bidon
|
||
protected $primaryKey = 'con_id';
|
||
|
||
protected $allowedFields = [
|
||
'name',
|
||
'location',
|
||
'date',
|
||
];
|
||
|
||
// ---------------------------------------------------------
|
||
// Lire un événement selon l'ID
|
||
// ---------------------------------------------------------
|
||
public function getEvent(int $id): ?array
|
||
{
|
||
return $this->asArray()->find($id);
|
||
}
|
||
public function getLinkedData(int $id): array
|
||
{
|
||
// 1) Lire la config dans la DB par défaut
|
||
$config = $this->asArray()->find($id);
|
||
|
||
if (!$config) {
|
||
return [];
|
||
}
|
||
|
||
// 2) Connexion à la base MS1Timing
|
||
$db = \Config\Database::connect('ms1timing');
|
||
|
||
// 3) Lire Course
|
||
$course = $db->table('courses')
|
||
->where('cou_id', $config['cou_id'])
|
||
->get()
|
||
->getRowArray();
|
||
|
||
// 4) Lire Event
|
||
$event = $db->table('evenements')
|
||
->where('eve_id', $config['eve_id'])
|
||
->get()
|
||
->getRowArray();
|
||
|
||
return [
|
||
'config' => $config,
|
||
'course' => $course,
|
||
'event' => $event,
|
||
];
|
||
}
|
||
|
||
public function getLinkedDatatimingpoint(int $id): array
|
||
{
|
||
$db = \Config\Database::connect();
|
||
|
||
// 1) Lire les timing points pour cette course
|
||
$timingpoints = $db->table('reader_config_timingpoint')
|
||
->where('con_id', $id)
|
||
->orderBy('tp_trie', 'ASC')
|
||
->get()
|
||
->getResultArray();
|
||
|
||
// Si aucun TP, on retourne vide
|
||
if (empty($timingpoints)) {
|
||
return ['timingpoint' => []];
|
||
}
|
||
|
||
// 2) Préparer liste des tp_id
|
||
$tpIds = array_column($timingpoints, 'tp_id');
|
||
|
||
// 3) Construire nom de la table dynamic
|
||
$detailTable = "resultv2_{$id}_detail";
|
||
|
||
// 4) UNE SEULE requête SQL pour compter par TP (optimisation majeure)
|
||
$counts = $db->table($detailTable)
|
||
->select('tp_id, COUNT(*) as total')
|
||
->whereIn('tp_id', $tpIds)
|
||
->groupBy('tp_id')
|
||
->get()
|
||
->getResultArray();
|
||
|
||
// 5) Convertir le résultat en tableau associatif: [tp_id => count]
|
||
$countMap = [];
|
||
foreach ($counts as $row) {
|
||
$countMap[$row['tp_id']] = (int) $row['total'];
|
||
}
|
||
|
||
// 6) Injecter le count dans chaque timing point
|
||
foreach ($timingpoints as &$tp) {
|
||
$tpId = $tp['tp_id'];
|
||
$tp['lecture_count'] = $countMap[$tpId] ?? 0;
|
||
}
|
||
|
||
return [
|
||
'timingpoint' => $timingpoints
|
||
];
|
||
}
|
||
|
||
public function getProcessStatus($con_id)
|
||
{
|
||
$table = "resultv2_{$con_id}_lecture";
|
||
|
||
$row = $this->db->query("SELECT process_status FROM `$table` LIMIT 1")->getRow();
|
||
|
||
return $row ? $row->process_status : null;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public function getStatsByEventName(string $eventName): array
|
||
{
|
||
$db = \Config\Database::connect(); // DB par défaut
|
||
|
||
$results = $db->table('reader_lectures')
|
||
->select('chrinfo_location, COUNT(*) AS total, MIN(chrinfo_time) AS start_time, MAX(chrinfo_time) AS end_time')
|
||
->where('chrinfo_event_name', $eventName)
|
||
->where('chrinfo_type_transaction !=', 'NEW LOCATION')
|
||
->groupBy('chrinfo_location')
|
||
->get()
|
||
->getResultArray();
|
||
|
||
// Transformer en tableau avec clé 1,2,3...
|
||
$final = [];
|
||
$i = 1;
|
||
|
||
foreach ($results as $row) {
|
||
$final[$i] = [
|
||
'location' => $row['chrinfo_location'],
|
||
'count' => (int)$row['total'],
|
||
'start_time' => $row['start_time'],
|
||
'end_time' => $row['end_time'],
|
||
'icon' => 'lucide--eye',
|
||
'bg_color' => '#F7B6A8'
|
||
];
|
||
$i++;
|
||
}
|
||
|
||
return $final;
|
||
}
|
||
public function getEventList(): array
|
||
{
|
||
// 1) Lire tous les événements
|
||
$events = $this->asArray()
|
||
|
||
->findAll();
|
||
|
||
$final = [];
|
||
|
||
// 2) Ajouter les données liées pour chaque ligne
|
||
foreach ($events as $event) {
|
||
|
||
$linked = $this->getLinkedData($event['con_id']);
|
||
|
||
$final[] = [
|
||
'config' => $linked['config'],
|
||
'course' => $linked['course'],
|
||
'event' => $linked['event'],
|
||
];
|
||
}
|
||
|
||
// 3) Trier par eve_date_debut DESC (du plus récent au plus ancien)
|
||
usort($final, function($a, $b) {
|
||
return strcmp($b['event']['eve_date_debut'], $a['event']['eve_date_debut']);
|
||
});
|
||
|
||
return $final;
|
||
}
|
||
|
||
/**
|
||
* Duplique les tables de résultats sur la connexion ms1timing_slave
|
||
* à partir des tables *_template vers *_{$courseId}.
|
||
*
|
||
* @param int $courseId ex: 2152
|
||
* @return array liste des statuts par table
|
||
*/
|
||
|
||
public function duplicateResultTables(int $courseId): array
|
||
{
|
||
// Connexion à la base ms1timing_slave (déjà définie dans Database.php)
|
||
$db = \Config\Database::connect();
|
||
|
||
// Suffixes des tables
|
||
$suffixes = [
|
||
'classement',
|
||
'detail',
|
||
'log',
|
||
'pause',
|
||
'lecture',
|
||
'lecture_statut'
|
||
];
|
||
|
||
$results = [];
|
||
|
||
foreach ($suffixes as $suffix) {
|
||
|
||
// Nouveau format demandé
|
||
$templateTable = "resultv2_template_{$suffix}";
|
||
$newTable = "resultv2_{$courseId}_{$suffix}";
|
||
|
||
// Vérifier que la table template existe
|
||
if (! $db->tableExists($templateTable)) {
|
||
$results[] = [
|
||
'table' => $newTable,
|
||
'status' => 'template_missing',
|
||
'message'=> "La table template {$templateTable} n’existe pas.",
|
||
];
|
||
continue;
|
||
}
|
||
|
||
// Si la nouvelle table existe déjà, on ne la touche pas
|
||
if ($db->tableExists($newTable)) {
|
||
$results[] = [
|
||
'table' => $newTable,
|
||
'status' => 'exists',
|
||
'message'=> "La table {$newTable} existe déjà. Aucune action.",
|
||
];
|
||
continue;
|
||
}
|
||
|
||
// Création + remplissage dans une transaction
|
||
$db->transStart();
|
||
|
||
// CREATE TABLE nouveau LIKE template
|
||
$db->query(
|
||
"CREATE TABLE `{$newTable}` LIKE `{$templateTable}`"
|
||
);
|
||
|
||
// Cas particulier pour la table lecture : on met directement les bonnes valeurs initiales
|
||
if ($suffix === 'lecture') {
|
||
$db->query("
|
||
INSERT INTO `{$newTable}` (
|
||
id,
|
||
last_processed_read_id,
|
||
config_hash,
|
||
needs_rebuild,
|
||
process_status,
|
||
backup_flag,
|
||
last_rebuild_ts,
|
||
last_backup_ts,
|
||
moteur_version,
|
||
created_at,
|
||
updated_at
|
||
) VALUES (
|
||
1,
|
||
0,
|
||
'',
|
||
0,
|
||
'IDLE',
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
'1.0',
|
||
NOW(),
|
||
NOW()
|
||
)
|
||
");
|
||
} else {
|
||
// INSERT INTO new SELECT * FROM template (comportement existant)
|
||
$db->query(
|
||
"INSERT INTO `{$newTable}` SELECT * FROM `{$templateTable}`"
|
||
);
|
||
}
|
||
|
||
$db->transComplete();
|
||
|
||
if ($db->transStatus() === false) {
|
||
$results[] = [
|
||
'table' => $newTable,
|
||
'status' => 'error',
|
||
'message'=> "Erreur lors de la duplication de {$newTable}.",
|
||
];
|
||
} else {
|
||
$results[] = [
|
||
'table' => $newTable,
|
||
'status' => 'created',
|
||
'message'=> "Table {$newTable} créée et remplie à partir de {$templateTable}.",
|
||
];
|
||
}
|
||
}
|
||
|
||
return $results;
|
||
}
|
||
|
||
|
||
/**
|
||
* Récupère les timingpoints + toutes les configurations associées
|
||
* à partir de la table reader_config_detail.
|
||
*
|
||
* @param int $id ID du contrôleur (con_id)
|
||
* @return array Tableau final des timingpoints enrichis
|
||
*/
|
||
public function getLinkedDatatimingpointWithConfig(int $id)
|
||
{
|
||
//----------------------------------------------------------------------
|
||
// 1. Récupération des timingpoints existants (déjà fonctionnel chez toi)
|
||
//----------------------------------------------------------------------
|
||
$data = $this->getLinkedDatatimingpoint($id);
|
||
|
||
// Sécurité : si aucun timingpoint, on retourne tout de suite
|
||
if (!isset($data['timingpoint']) || empty($data['timingpoint'])) {
|
||
return $data;
|
||
}
|
||
|
||
//----------------------------------------------------------------------
|
||
// 2. Boucle sur chaque timingpoint (un tp_id à la fois)
|
||
//----------------------------------------------------------------------
|
||
foreach ($data['timingpoint'] as $index => $tp) {
|
||
|
||
$tp_id = $tp['tp_id'];
|
||
|
||
//------------------------------------------------------------------
|
||
// 3. Aller chercher toutes les lignes reader_config_detail
|
||
// où det_ref1_id = tp_id
|
||
//------------------------------------------------------------------
|
||
$builder = $this->db->table('reader_config_detail');
|
||
$builder->where('det_ref1_id', $tp_id);
|
||
$builder->orderBy('det_trie', 'ASC');
|
||
|
||
$rows = $builder->get()->getResultArray();
|
||
|
||
//------------------------------------------------------------------
|
||
// 4. Aucune config → on continue au suivant
|
||
//------------------------------------------------------------------
|
||
if (empty($rows)) {
|
||
continue;
|
||
}
|
||
|
||
//------------------------------------------------------------------
|
||
// 5. Préparation des conteneurs de regroupement
|
||
//------------------------------------------------------------------
|
||
$configSets = [];
|
||
|
||
//------------------------------------------------------------------
|
||
// 6. Boucle à travers chaque config trouvée
|
||
//------------------------------------------------------------------
|
||
foreach ($rows as $row) {
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.1 Extraction du groupe (ex: configs-tp, configs-tp-interval)
|
||
// → conversion en identifiant propre pour le tableau final
|
||
//--------------------------------------------------------------
|
||
$groupName = !empty($row['det_groupe'])
|
||
? str_replace('-', '_', $row['det_groupe'])
|
||
: 'configs_generic'; // fallback, jamais vide
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.2 La clef interne (ex: clef_controleur)
|
||
//--------------------------------------------------------------
|
||
$clef = $row['det_clef'];
|
||
|
||
if (empty($clef)) {
|
||
// Si jamais c'est vide, on ignore cette ligne
|
||
continue;
|
||
}
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.3 Préparer la structure si elle n'existe pas encore
|
||
//--------------------------------------------------------------
|
||
if (!isset($configSets[$groupName])) {
|
||
$configSets[$groupName] = [];
|
||
}
|
||
if (!isset($configSets[$groupName][$clef])) {
|
||
$configSets[$groupName][$clef] = [];
|
||
}
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.4 Ajouter la ligne de configuration
|
||
//--------------------------------------------------------------
|
||
$configSets[$groupName][$clef][] = [
|
||
'value1' => $row['det_value1'],
|
||
'value2' => $row['det_value2'],
|
||
'value3' => $row['det_value3'],
|
||
];
|
||
}
|
||
|
||
//------------------------------------------------------------------
|
||
// 7. Injection dans le timingpoint final
|
||
//------------------------------------------------------------------
|
||
$data['timingpoint'][$index] = array_merge(
|
||
$data['timingpoint'][$index],
|
||
$configSets
|
||
);
|
||
}
|
||
|
||
//----------------------------------------------------------------------
|
||
// 8. Retour final
|
||
//----------------------------------------------------------------------
|
||
return $data;
|
||
}
|
||
|
||
public function getcourseConfig(int $id)
|
||
{
|
||
|
||
|
||
|
||
|
||
|
||
//------------------------------------------------------------------
|
||
$builder = $this->db->table('reader_config_detail');
|
||
$builder->where('det_ref1_id', $id);
|
||
$builder->where('det_type', 2);
|
||
$builder->orderBy('det_trie', 'ASC');
|
||
|
||
$rows = $builder->get()->getResultArray();
|
||
|
||
//------------------------------------------------------------------
|
||
// 5. Préparation des conteneurs de regroupement
|
||
//------------------------------------------------------------------
|
||
$configSets = [];
|
||
|
||
//------------------------------------------------------------------
|
||
// 6. Boucle à travers chaque config trouvée
|
||
//------------------------------------------------------------------
|
||
foreach ($rows as $row) {
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.1 Extraction du groupe (ex: configs-tp, configs-tp-interval)
|
||
// → conversion en identifiant propre pour le tableau final
|
||
//--------------------------------------------------------------
|
||
$groupName = !empty($row['det_groupe'])
|
||
? str_replace('-', '_', $row['det_groupe'])
|
||
: 'configs_generic'; // fallback, jamais vide
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.2 La clef interne (ex: clef_controleur)
|
||
//--------------------------------------------------------------
|
||
$clef = $row['det_clef'];
|
||
|
||
if (empty($clef)) {
|
||
// Si jamais c'est vide, on ignore cette ligne
|
||
continue;
|
||
}
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.3 Préparer la structure si elle n'existe pas encore
|
||
//--------------------------------------------------------------
|
||
if (!isset($configSets[$groupName])) {
|
||
$configSets[$groupName] = [];
|
||
}
|
||
if (!isset($configSets[$groupName][$clef])) {
|
||
$configSets[$groupName][$clef] = [];
|
||
}
|
||
|
||
//--------------------------------------------------------------
|
||
// 6.4 Ajouter la ligne de configuration
|
||
//--------------------------------------------------------------
|
||
$output=$row['det_value1'];
|
||
if($row['det_type_output']!='')
|
||
$output=format_output($row['det_value1'], $row['det_type_output']);
|
||
|
||
$configSets[$groupName][$clef][] = [
|
||
'value1' => $row['det_value1'],
|
||
'value2' => $row['det_value2'],
|
||
'value3' => $row['det_value3'],
|
||
'output' => $output,
|
||
|
||
];
|
||
}
|
||
|
||
|
||
|
||
|
||
//--------------------------------------------------------------
|
||
|
||
//----------------------------------------------------------------------
|
||
// 8. Retour final
|
||
//----------------------------------------------------------------------
|
||
return $configSets;
|
||
}
|
||
public function resetCourse($con_id)
|
||
{
|
||
$lectureTable = "resultv2_{$con_id}_lecture";
|
||
$detailTable = "resultv2_{$con_id}_detail";
|
||
|
||
// -------------------------------------------------
|
||
// 1) Demander la pause (PAUSE_REQUEST)
|
||
// -------------------------------------------------
|
||
$this->db->query("UPDATE `$lectureTable` SET process_status = 'PAUSE_REQUEST'");
|
||
|
||
// -------------------------------------------------
|
||
// 2) Attendre que Python applique PAUSE
|
||
// -------------------------------------------------
|
||
$timeoutSeconds = 20 * 60; // 20 minutes
|
||
$waitInterval = 500000; // 0.5 seconde
|
||
$attempts = ($timeoutSeconds * 1000000) / $waitInterval;
|
||
|
||
$isPaused = false;
|
||
|
||
for ($i = 0; $i < $attempts; $i++) {
|
||
|
||
$row = $this->db->query("SELECT process_status FROM `$lectureTable` LIMIT 1")->getRow();
|
||
|
||
if ($row && strtoupper($row->process_status) === 'PAUSE') {
|
||
$isPaused = true;
|
||
break;
|
||
}
|
||
|
||
// Attendre 0.5 sec avant de rechecker
|
||
usleep($waitInterval);
|
||
}
|
||
|
||
if (!$isPaused) {
|
||
return "ERREUR : Impossible d'obtenir PAUSE (timeout). Base NON modifiée.";
|
||
}
|
||
|
||
// -------------------------------------------------
|
||
// 3) TRUNCATE de la table detail (sécurisé)
|
||
// -------------------------------------------------
|
||
$this->db->query("TRUNCATE TABLE `$detailTable`");
|
||
|
||
// -------------------------------------------------
|
||
// 4) Remettre last_processed_read_id à 0
|
||
// -------------------------------------------------
|
||
$this->db->query("
|
||
UPDATE `$lectureTable`
|
||
SET last_processed_read_id = 0
|
||
");
|
||
|
||
// -------------------------------------------------
|
||
// 5) Remettre la course en IDLE pour que Python puisse repartir
|
||
// -------------------------------------------------
|
||
$this->db->query("UPDATE `$lectureTable` SET process_status = 'IDLE'");
|
||
|
||
return "OK : Course réinitialisée.";
|
||
}
|
||
|
||
|
||
|
||
}
|