$breadcrumb * @param list $detailOf */ public function __construct( public string $type, public int $uid, public string $language, public ?string $site, public ?string $url, public \DateTimeImmutable $modified, public ?string $contentUrl = null, public ?string $title = null, public ?string $description = null, public array $breadcrumb = [], public array $detailOf = [], ) { } /** * @param array $item */ public static function fromArray(array $item): self { if (!is_string($item['type'] ?? null) || !is_int($item['uid'] ?? null) || !is_string($item['language'] ?? null) || !is_string($item['modified'] ?? null)) { throw new \InvalidArgumentException('Manifest item without type, uid, language or modified'); } $modified = self::localTime($item['modified']); if (null === $modified) { throw new \InvalidArgumentException(sprintf('Manifest item %s:%d has an unparseable modified', $item['type'], $item['uid'])); } $detailOf = []; foreach (is_array($item['detailOf'] ?? null) ? $item['detailOf'] : [] as $ref) { if (is_array($ref) && is_string($ref['type'] ?? null) && is_int($ref['uid'] ?? null)) { $detailOf[] = ['type' => $ref['type'], 'uid' => $ref['uid']]; } } $string = static fn (mixed $value): ?string => is_string($value) && '' !== $value ? $value : null; return new self( type: $item['type'], uid: $item['uid'], language: $item['language'], site: $string($item['site'] ?? null), url: $string($item['url'] ?? null), modified: $modified, contentUrl: $string($item['contentUrl'] ?? null), title: $string($item['title'] ?? null), description: $string($item['description'] ?? null), breadcrumb: array_values(array_filter(is_array($item['breadcrumb'] ?? null) ? $item['breadcrumb'] : [], 'is_string')), detailOf: $detailOf, ); } /** * A feed timestamp in the application's timezone. Doctrine stores datetimes without * their offset, so a value kept in TYPO3's +02:00 would never compare equal to itself * once reloaded, and every item would look changed on every run. */ public static function localTime(string $value): ?\DateTimeImmutable { $date = date_create_immutable($value); return false === $date ? null : $date->setTimezone(new \DateTimeZone(date_default_timezone_get())); } public function key(): string { return ContentDocument::key($this->type, $this->uid, $this->language); } }