diff --git a/src/Data/GoogleSearch.php b/src/Data/GoogleSearch.php index c06b1bf..1f20898 100644 --- a/src/Data/GoogleSearch.php +++ b/src/Data/GoogleSearch.php @@ -4,26 +4,56 @@ namespace Gemini\Data; +use InvalidArgumentException; use stdClass; /** - * This type has no fields. * GoogleSearch tool type. Tool to support Google Search in Model. Powered by Google. * * https://ai.google.dev/api/caching#GoogleSearch */ final class GoogleSearch { + /** + * @param Interval|null $timeRangeFilter Optional. Filter search results to a specific time range. If customers set a start time, they must set an end time (and vice versa). + * + * @throws InvalidArgumentException When timeRangeFilter has only startTime or only endTime specified + */ public function __construct( - ) {} + public readonly ?Interval $timeRangeFilter = null, + ) { + if ($this->timeRangeFilter !== null) { + $hasStartTime = $this->timeRangeFilter->startTime !== null; + $hasEndTime = $this->timeRangeFilter->endTime !== null; - public static function from(): self + // GoogleSearch requires both start and end time to be set together + if ($hasStartTime !== $hasEndTime) { + throw new InvalidArgumentException('In GoogleSearch timeRangeFilter, if you set a start time, you must set an end time (and vice versa)'); + } + } + } + + /** + * @param array{timeRangeFilter?: array{startTime?: ?string, endTime?: ?string}} $attributes + */ + public static function from(array $attributes = []): self { - return new self; + return new self( + timeRangeFilter: isset($attributes['timeRangeFilter']) ? Interval::from($attributes['timeRangeFilter']) : null, + ); } - public function toArray(): stdClass + /** + * @return stdClass|array{timeRangeFilter: array{startTime?: ?string, endTime?: ?string}|stdClass} + */ + public function toArray(): stdClass|array { - return new stdClass; + if ($this->timeRangeFilter === null) { + return new stdClass; + } + + return [ + 'timeRangeFilter' => $this->timeRangeFilter->toArray(), + ]; } } diff --git a/src/Data/Interval.php b/src/Data/Interval.php new file mode 100644 index 0000000..f96a25d --- /dev/null +++ b/src/Data/Interval.php @@ -0,0 +1,102 @@ +startTime !== null && ! $this->isValidTimestamp($this->startTime)) { + throw new InvalidArgumentException('startTime must be in RFC 3339 timestamp format'); + } + + if ($this->endTime !== null && ! $this->isValidTimestamp($this->endTime)) { + throw new InvalidArgumentException('endTime must be in RFC 3339 timestamp format'); + } + + if ($this->startTime !== null && $this->endTime !== null) { + $startTimestamp = strtotime($this->startTime); + $endTimestamp = strtotime($this->endTime); + + if ($startTimestamp === false || $endTimestamp === false) { + throw new InvalidArgumentException('Invalid timestamp format'); + } + + if ($startTimestamp > $endTimestamp) { + throw new InvalidArgumentException('startTime must be less than or equal to endTime'); + } + } + } + + /** + * @param array{startTime?: ?string, endTime?: ?string} $attributes + */ + public static function from(array $attributes): self + { + return new self($attributes['startTime'] ?? null, $attributes['endTime'] ?? null); + } + + /** + * @return stdClass|array{startTime?: ?string, endTime?: ?string} + */ + public function toArray(): stdClass|array + { + $data = []; + + if ($this->startTime !== null) { + $data['startTime'] = $this->startTime; + } + + if ($this->endTime !== null) { + $data['endTime'] = $this->endTime; + } + + return empty($data) ? new stdClass : $data; + } + + /** + * Validates if a string is in RFC 3339 timestamp format + */ + private function isValidTimestamp(string $timestamp): bool + { + // RFC 3339 regex pattern + $pattern = '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})$/'; + + if (! preg_match($pattern, $timestamp)) { + return false; + } + + // Handle Z timezone suffix by converting to +00:00 + $normalizedTimestamp = str_replace('Z', '+00:00', $timestamp); + + // Try with extended format first (includes microseconds) + $dateTime = DateTime::createFromFormat(DateTime::RFC3339_EXTENDED, $normalizedTimestamp); + if ($dateTime === false) { + // Try with standard RFC3339 format + $dateTime = DateTime::createFromFormat(DateTime::RFC3339, $normalizedTimestamp); + } + + return $dateTime !== false; + } +}