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 "

Debug GCal – Test de placement

"; echo "

Paramètres

";
        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 "
"; if (empty($email)) { echo "

⚠️ Fournis ?email=user@domaine.com dans l’URL.

"; $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 "

Librairie GCalService

";
        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 "
"; // ===== Introspection des propriétés de la librairie ===== $props = get_object_vars($this->gcalservice); echo "

Propriétés de GCalService

"; if (empty($props)) { echo "
(aucune propriété publique/protégée visible)
"; } else { echo ""; 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 ""; } echo "
NomTypeDétail
".htmlspecialchars($k)."$type".htmlspecialchars($detail)."
"; } // 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 "

getClient() a levé: ".htmlspecialchars($e->getMessage())."

"; } } // 4) Fabrique un service si on a un client if (!$calendarService && $googleClient && class_exists('Google_Service_Calendar')) { $calendarService = new Google_Service_Calendar($googleClient); } echo "

Détection de service

";
        echo "calendarService: ".($calendarService ? ('OK ('.get_class($calendarService).')') : 'non')."\n";
        echo "googleClient   : ".($googleClient    ? ('OK ('.get_class($googleClient).')')     : 'non')."\n";
        echo "
"; // ==== 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 "

freeBusy() via service détecté

"; 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 "

(aucun busy remonté)

"; $this->print_busy($busyIntervals, $tzObj); } catch (Exception $e) { echo "
Exception: ".htmlspecialchars($e->getMessage())."
"; } } else { echo "

freeBusy() via service détecté

service indisponible

"; } // listEvents via service direct (si dispo) if ($calendarService && method_exists($calendarService->events, 'listEvents')) { echo "

listEvents() via service détecté

"; 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 "

(aucun événement)

"; $this->print_events($events, $tzObj); } catch (Exception $e) { echo "
Exception: ".htmlspecialchars($e->getMessage())."
"; } } else { echo "

listEvents() via service détecté

service indisponible

"; } // 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 "

freeBusy() via librairie

"; 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 "

(aucun busy via librairie)

"; $this->print_busy($busyIntervals, $tzObj); } } catch (Exception $e) { echo "
Exception: ".htmlspecialchars($e->getMessage())."
"; } } if (empty($events) && method_exists($this->gcalservice, 'listEvents')) { echo "

listEvents() via librairie

"; try { $events = $this->gcalservice->listEvents($email, $calId, $dayStart->format(DateTime::RFC3339), $dayEnd->format(DateTime::RFC3339)); $this->print_events($events, $tzObj); } catch (Exception $e) { echo "
Exception: ".htmlspecialchars($e->getMessage())."
"; } } // Normalisation finale des intervals occupés echo "

Busy normalisés (utilisés pour la simulation)

"; $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 "

Simulation de placement

";
        echo "Candidat retenu : " . $slot['startIso'] . " → " . $slot['endIso'] . "\n";
        echo "
"; $this->print_usage(); } private function print_busy(array $busy, DateTimeZone $tzObj) { if (empty($busy)) { echo "
(aucun)
"; return; } echo ""; echo ""; $i = 1; foreach ($busy as $pair) { $s = $pair[0]; $e = $pair[1]; $mins = round(($e->getTimestamp() - $s->getTimestamp()) / 60); echo ""; } echo "
#Start (".$tzObj->getName().")End (".$tzObj->getName().")Durée (min)
".$i++."".$s->format('Y-m-d H:i:s')."".$e->format('Y-m-d H:i:s')."".$mins."
"; } private function print_events(array $events, DateTimeZone $tzObj) { if (empty($events)) { echo "
(aucun)
"; return; } echo ""; echo ""; $i = 1; foreach ($events as $ev) { $sdt = $ev['start']['dateTime'] ?? ''; $sd = $ev['start']['date'] ?? ''; $edt = $ev['end']['dateTime'] ?? ''; $ed = $ev['end']['date'] ?? ''; echo ""; } echo "
#start.dateTimestart.dateend.dateTimeend.date
".$i++."".htmlspecialchars($sdt)."".htmlspecialchars($sd)."".htmlspecialchars($edt)."".htmlspecialchars($ed)."
"; } 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 "

Usage

";
        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 "
"; } }