*/ private array $templates; public function __construct(TemplateMapping ...$templates) { $this->templates = array_values($templates); } /** * Add a template to the collection */ public function add(TemplateMapping $template): self { $templates = $this->templates; $templates[] = $template; return new self(...$templates); } /** * Add multiple templates to the collection */ public function addMany(TemplateMapping ...$templates): self { return new self(...array_merge($this->templates, $templates)); } /** * Filter templates by name pattern */ public function filterByName(string $namePattern): self { $filtered = array_filter( $this->templates, fn (TemplateMapping $template) => $template->matchesName($namePattern) ); return new self(...$filtered); } /** * Filter templates by type */ public function filterByType(string $type): self { $filtered = array_filter( $this->templates, fn (TemplateMapping $template) => $template->isType($type) ); return new self(...$filtered); } /** * Filter templates by directory */ public function filterByDirectory(string $directory): self { $normalizedDirectory = rtrim($directory, '/'); $filtered = array_filter( $this->templates, fn (TemplateMapping $template) => dirname($template->path->toString()) === $normalizedDirectory ); return new self(...$filtered); } /** * Filter templates by extension */ public function filterByExtension(string $extension): self { $extension = ltrim($extension, '.'); $filtered = array_filter( $this->templates, fn (TemplateMapping $template) => $template->getExtension() === $extension ); return new self(...$filtered); } /** * Find template by exact name and type */ public function findExact(string $name, string $type = 'view'): ?TemplateMapping { foreach ($this->templates as $template) { if ($template->name === $name && $template->type === $type) { return $template; } } return null; } /** * Find template by name (any type) */ public function findByName(string $name): ?TemplateMapping { foreach ($this->templates as $template) { if ($template->name === $name) { return $template; } } return null; } /** * Find template by file path */ public function findByPath(FilePath $path): ?TemplateMapping { foreach ($this->templates as $template) { if ($template->path->equals($path)) { return $template; } } return null; } /** * Get templates grouped by type * @return array */ public function groupByType(): array { $grouped = []; foreach ($this->templates as $template) { if (! isset($grouped[$template->type])) { $grouped[$template->type] = []; } $grouped[$template->type][] = $template; } return array_map( fn (array $templates) => new self(...$templates), $grouped ); } /** * Get templates grouped by directory * @return array */ public function groupByDirectory(): array { $grouped = []; foreach ($this->templates as $template) { $directory = dirname($template->path->toString()); if (! isset($grouped[$directory])) { $grouped[$directory] = []; } $grouped[$directory][] = $template; } return array_map( fn (array $templates) => new self(...$templates), $grouped ); } /** * Get unique template names * @return array */ public function getUniqueNames(): array { $names = array_map(fn (TemplateMapping $template) => $template->name, $this->templates); return array_unique($names); } /** * Get unique template types * @return array */ public function getUniqueTypes(): array { $types = array_map(fn (TemplateMapping $template) => $template->type, $this->templates); return array_unique($types); } /** * Get unique directories */ public function getUniqueDirectories(): array { $directories = array_map( fn (TemplateMapping $template) => dirname($template->path->toString()), $this->templates ); return array_unique($directories); } /** * Remove duplicate templates based on unique identifier */ public function deduplicate(): self { $seen = []; $unique = []; foreach ($this->templates as $template) { $key = $template->getUniqueId(); if (! isset($seen[$key])) { $seen[$key] = true; $unique[] = $template; } } return new self(...$unique); } /** * Sort templates by name */ public function sortedByName(): self { $sorted = $this->templates; usort($sorted, fn (TemplateMapping $a, TemplateMapping $b) => $a->name <=> $b->name); return new self(...$sorted); } /** * Sort templates by type, then by name */ public function sortedByTypeAndName(): self { $sorted = $this->templates; usort($sorted, function (TemplateMapping $a, TemplateMapping $b) { $typeComparison = $a->type <=> $b->type; return $typeComparison !== 0 ? $typeComparison : $a->name <=> $b->name; }); return new self(...$sorted); } /** * Check if collection is empty */ public function isEmpty(): bool { return empty($this->templates); } /** * Get first template or null */ public function first(): ?TemplateMapping { return $this->templates[0] ?? null; } /** * Get last template or null */ public function last(): ?TemplateMapping { return end($this->templates) ?: null; } /** * Convert to array of TemplateMapping objects */ public function toArray(): array { return $this->templates; } /** * Convert to legacy array format for backward compatibility */ public function toLegacyArray(): array { $legacy = []; foreach ($this->templates as $template) { // Group by template name with variants by type if (! isset($legacy[$template->name])) { $legacy[$template->name] = []; } $legacy[$template->name][$template->type] = $template->path->toString(); } return $legacy; } /** * Get memory footprint of entire collection */ public function getMemoryFootprint(): Byte { $totalBytes = 0; foreach ($this->templates as $template) { $totalBytes += $template->getMemoryFootprint()->toBytes(); } // Add overhead for collection structure $totalBytes += count($this->templates) * 8; // approximate pointer overhead return Byte::fromBytes($totalBytes); } // Countable interface implementation public function count(): int { return count($this->templates); } // IteratorAggregate interface implementation public function getIterator(): ArrayIterator { return new ArrayIterator($this->templates); } }