312 lines
14 KiB
PHP
312 lines
14 KiB
PHP
<?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 l’URL.</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 qu’en 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 l’essaie
|
||
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>";
|
||
}
|
||
}
|