Files
crm-ms1/application/controllers/DebugGcal.php
2026-05-27 11:44:10 -04:00

312 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class DebugGcal extends CI_Controller
{
public function index()
{
$email = $this->input->get('email', true) ?: '';
$dateYmd = $this->input->get('date', true) ?: date('Y-m-d');
$tz = $this->input->get('tz', true) ?: 'America/Toronto';
$base = $this->input->get('base', true) ?: '08:00';
$dur = (int)($this->input->get('dur', true) ?: 1);
$calId = $this->input->get('calendar', true) ?: 'primary';
header('Content-Type: text/html; charset=utf-8');
echo "<h1>Debug GCal Test de placement</h1>";
echo "<h2>Paramètres</h2><pre>";
echo "email : $email\n";
echo "date : $dateYmd\n";
echo "timezone : $tz\n";
echo "base : $base\n";
echo "dur(min) : $dur\n";
echo "calendar : $calId\n";
echo "</pre>";
if (empty($email)) {
echo "<p style='color:red'>⚠️ Fournis ?email=user@domaine.com dans lURL.</p>";
$this->print_usage(); return;
}
// Fenêtre de la journée
try { $tzObj = new DateTimeZone($tz); } catch (Exception $e) { $tzObj = new DateTimeZone('America/Toronto'); }
$dayStart = new DateTime("$dateYmd 00:00:00", $tzObj);
$dayEnd = new DateTime("$dateYmd 23:59:59", $tzObj);
// Charge la lib telle quen prod
$this->load->library('GCalService');
echo "<h2>Librairie GCalService</h2><pre>";
echo "Class: " . get_class($this->gcalservice) . "\n";
echo "Méthodes disponibles:\n";
echo " - freeBusy : " . (method_exists($this->gcalservice, 'freeBusy') ? 'OUI' : 'non') . "\n";
echo " - listEvents : " . (method_exists($this->gcalservice, 'listEvents') ? 'OUI' : 'non') . "\n";
echo "Classes Google connues:\n";
echo " - Google_Service_Calendar: " . (class_exists('Google_Service_Calendar') ? 'OUI' : 'non') . "\n";
echo " - Google_Client : " . (class_exists('Google_Client') ? 'OUI' : 'non') . "\n";
echo "</pre>";
// ===== Introspection des propriétés de la librairie =====
$props = get_object_vars($this->gcalservice);
echo "<h2>Propriétés de GCalService</h2>";
if (empty($props)) {
echo "<pre>(aucune propriété publique/protégée visible)</pre>";
} else {
echo "<table border='1' cellspacing='0' cellpadding='4'><tr><th>Nom</th><th>Type</th><th>Détail</th></tr>";
foreach ($props as $k => $v) {
$type = gettype($v);
$detail = '';
if (is_object($v)) {
$cls = get_class($v);
$type = "object";
$detail = $cls;
} elseif (is_array($v)) {
$detail = 'array('.count($v).')';
} else {
$detail = htmlspecialchars(var_export($v, true));
}
echo "<tr><td>".htmlspecialchars($k)."</td><td>$type</td><td>".htmlspecialchars($detail)."</td></tr>";
}
echo "</table>";
}
// Tente de découvrir un service Calendar déjà initialisé
$calendarService = null;
$googleClient = null;
// 1) Cherche un objet déjà de type Google_Service_Calendar
foreach ($props as $v) {
if (is_object($v) && class_exists('Google_Service_Calendar') && $v instanceof Google_Service_Calendar) {
$calendarService = $v; break;
}
}
// 2) Sinon, cherche un Google_Client
if (!$calendarService && class_exists('Google_Client')) {
foreach ($props as $v) {
if (is_object($v) && $v instanceof Google_Client) {
$googleClient = $v; break;
}
}
}
// 3) Sinon, si la lib expose une méthode getClient(), on lessaie
if (!$calendarService && !$googleClient && method_exists($this->gcalservice, 'getClient')) {
try {
$maybeClient = $this->gcalservice->getClient(); // sans effet de bord
if (is_object($maybeClient) && class_exists('Google_Client') && $maybeClient instanceof Google_Client) {
$googleClient = $maybeClient;
}
} catch (Exception $e) {
echo "<p style='color:red'><b>getClient()</b> a levé: ".htmlspecialchars($e->getMessage())."</p>";
}
}
// 4) Fabrique un service si on a un client
if (!$calendarService && $googleClient && class_exists('Google_Service_Calendar')) {
$calendarService = new Google_Service_Calendar($googleClient);
}
echo "<h2>Détection de service</h2><pre>";
echo "calendarService: ".($calendarService ? ('OK ('.get_class($calendarService).')') : 'non')."\n";
echo "googleClient : ".($googleClient ? ('OK ('.get_class($googleClient).')') : 'non')."\n";
echo "</pre>";
// ==== Appels en lecture en utilisant, si possible, le service détecté ====
$busyIntervals = [];
$events = [];
// FreeBusy via service direct (si dispo)
if ($calendarService && method_exists($calendarService->freebusy, 'query')) {
echo "<h2>freeBusy() via service détecté</h2>";
try {
$fbReq = new Google_Service_Calendar_FreeBusyRequest();
$fbReq->setTimeMin($dayStart->format(DateTime::RFC3339));
$fbReq->setTimeMax($dayEnd->format(DateTime::RFC3339));
$fbReq->setTimeZone($tz);
$item = new Google_Service_Calendar_FreeBusyRequestItem();
$item->setId($calId);
$fbReq->setItems([$item]);
$resp = $calendarService->freebusy->query($fbReq);
$cals = $resp->getCalendars();
if (isset($cals[$calId])) {
$blocks = $cals[$calId]['busy'] ?? [];
foreach ($blocks as $b) {
$s = new DateTime($b['start']);
$e = new DateTime($b['end']);
$s->setTimezone($tzObj);
$e->setTimezone($tzObj);
$busyIntervals[] = [$s, $e];
}
}
if (empty($busyIntervals)) echo "<p><i>(aucun busy remonté)</i></p>";
$this->print_busy($busyIntervals, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
} else {
echo "<h2>freeBusy() via service détecté</h2><p><i>service indisponible</i></p>";
}
// listEvents via service direct (si dispo)
if ($calendarService && method_exists($calendarService->events, 'listEvents')) {
echo "<h2>listEvents() via service détecté</h2>";
try {
$opt = [
'timeMin' => $dayStart->format(DateTime::RFC3339),
'timeMax' => $dayEnd->format(DateTime::RFC3339),
'singleEvents' => true,
'orderBy' => 'startTime',
'maxResults' => 2500,
];
$resp = $calendarService->events->listEvents($calId, $opt);
foreach ($resp->getItems() as $ev) {
$start = $ev->getStart();
$end = $ev->getEnd();
$events[] = [
'start' => [
'dateTime' => $start ? $start->getDateTime() : null,
'date' => $start ? $start->getDate() : null,
],
'end' => [
'dateTime' => $end ? $end->getDateTime() : null,
'date' => $end ? $end->getDate() : null,
],
];
}
if (empty($events)) echo "<p><i>(aucun événement)</i></p>";
$this->print_events($events, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
} else {
echo "<h2>listEvents() via service détecté</h2><p><i>service indisponible</i></p>";
}
// Si rien via service, on retombe sur tes méthodes existantes (si présentes) pour comparer
if (empty($busyIntervals) && method_exists($this->gcalservice, 'freeBusy')) {
echo "<h2>freeBusy() via librairie</h2>";
try {
$busyLib = $this->gcalservice->freeBusy($email, $calId, $dayStart->format(DateTime::RFC3339), $dayEnd->format(DateTime::RFC3339), $tz);
if (is_array($busyLib)) {
// On accepte deux formats: paires [DateTime, DateTime] ou tableaux ['start'=>..., 'end'=>...]
foreach ($busyLib as $pair) {
if (is_array($pair) && count($pair) === 2 && $pair[0] instanceof DateTime) {
$s = $pair[0]; $e = $pair[1];
} else {
$s = isset($pair['start']) ? new DateTime($pair['start']) : null;
$e = isset($pair['end']) ? new DateTime($pair['end']) : null;
}
if ($s && $e) {
$s->setTimezone($tzObj);
$e->setTimezone($tzObj);
$busyIntervals[] = [$s, $e];
}
}
if (empty($busyIntervals)) echo "<p><i>(aucun busy via librairie)</i></p>";
$this->print_busy($busyIntervals, $tzObj);
}
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
}
if (empty($events) && method_exists($this->gcalservice, 'listEvents')) {
echo "<h2>listEvents() via librairie</h2>";
try {
$events = $this->gcalservice->listEvents($email, $calId, $dayStart->format(DateTime::RFC3339), $dayEnd->format(DateTime::RFC3339));
$this->print_events($events, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
}
// Normalisation finale des intervals occupés
echo "<h2>Busy normalisés (utilisés pour la simulation)</h2>";
$normBusy = [];
foreach ($busyIntervals as $pair) {
if (!is_array($pair) || count($pair) !== 2) continue;
$s = $pair[0]; $e = $pair[1];
if (!($s instanceof DateTime) || !($e instanceof DateTime)) continue;
$normBusy[] = [$s, $e];
}
$this->print_busy($normBusy, $tzObj);
// Simulation locale (ne crée rien)
$slot = $this->simulate_slot($normBusy, $dateYmd, $tzObj, $base, $dur);
echo "<h2>Simulation de placement</h2><pre>";
echo "Candidat retenu : " . $slot['startIso'] . "" . $slot['endIso'] . "\n";
echo "</pre>";
$this->print_usage();
}
private function print_busy(array $busy, DateTimeZone $tzObj)
{
if (empty($busy)) { echo "<pre>(aucun)</pre>"; return; }
echo "<table border='1' cellpadding='4' cellspacing='0'>";
echo "<tr><th>#</th><th>Start (".$tzObj->getName().")</th><th>End (".$tzObj->getName().")</th><th>Durée (min)</th></tr>";
$i = 1;
foreach ($busy as $pair) {
$s = $pair[0]; $e = $pair[1];
$mins = round(($e->getTimestamp() - $s->getTimestamp()) / 60);
echo "<tr><td>".$i++."</td><td>".$s->format('Y-m-d H:i:s')."</td><td>".$e->format('Y-m-d H:i:s')."</td><td style='text-align:right'>".$mins."</td></tr>";
}
echo "</table>";
}
private function print_events(array $events, DateTimeZone $tzObj)
{
if (empty($events)) { echo "<pre>(aucun)</pre>"; return; }
echo "<table border='1' cellpadding='4' cellspacing='0'>";
echo "<tr><th>#</th><th>start.dateTime</th><th>start.date</th><th>end.dateTime</th><th>end.date</th></tr>";
$i = 1;
foreach ($events as $ev) {
$sdt = $ev['start']['dateTime'] ?? '';
$sd = $ev['start']['date'] ?? '';
$edt = $ev['end']['dateTime'] ?? '';
$ed = $ev['end']['date'] ?? '';
echo "<tr><td>".$i++."</td><td>".htmlspecialchars($sdt)."</td><td>".htmlspecialchars($sd)."</td><td>".htmlspecialchars($edt)."</td><td>".htmlspecialchars($ed)."</td></tr>";
}
echo "</table>";
}
private function simulate_slot(array $busyIntervals, string $dateYmd, DateTimeZone $tzObj, string $baseTime, int $durationMin): array
{
$candidate = new DateTime("$dateYmd $baseTime:00", $tzObj);
$dayEnd = new DateTime("$dateYmd 23:59:59", $tzObj);
usort($busyIntervals, function($a,$b){ return $a[0] <=> $b[0]; });
for ($i=0; $i<1440; $i++) {
if ($candidate > $dayEnd) break;
$candEnd = (clone $candidate)->modify("+$durationMin minutes");
$conflict = false;
foreach ($busyIntervals as $pair) {
$bs = $pair[0]; $be = $pair[1];
if ($candidate < $be && $candEnd > $bs) { $conflict = true; break; }
}
if (!$conflict) {
return [
'startIso' => $candidate->format(DateTime::RFC3339),
'endIso' => $candEnd->format(DateTime::RFC3339),
];
}
$candidate->modify('+1 minute');
}
$fallbackStart = new DateTime("$dateYmd $baseTime:00", $tzObj);
$fallbackEnd = (clone $fallbackStart)->modify("+$durationMin minutes");
return [
'startIso' => $fallbackStart->format(DateTime::RFC3339),
'endIso' => $fallbackEnd->format(DateTime::RFC3339),
];
}
private function print_usage()
{
echo "<h2>Usage</h2><pre>";
echo "GET /index.php/debug-gcal?email=prenom.nom@domaine.com&date=2025-09-23&tz=America/Toronto&base=08:00&dur=1&calendar=primary\n";
echo "</pre>";
}
}