*/ private array $documentDirs = []; /** * @param array $directories */ public function __construct(array $directories) { foreach ($directories as $directory) { $this->addDirectory($directory); } } /** * @CloudRequired */ public function addDirectory(string $directory): void { $this->documentDirs[] = $directory; } /** * @CloudRequired */ public function removeDirectory(string $directory): void { if (($key = array_search($directory, $this->documentDirs, true)) !== false) { unset($this->documentDirs[$key]); } } /** * @codeCoverageIgnore */ public function remove(InvoiceDocument $invoiceDocument): void { if (stripos($invoiceDocument->getFilename(), $this->getUploadDirectory()) === false) { throw new \InvalidArgumentException('Cannot delete built-in invoice template'); } $realpath = realpath($invoiceDocument->getFilename()); if ($realpath === false) { throw new \InvalidArgumentException('Template does not exist: ' . $invoiceDocument->getFilename()); } @unlink($realpath); } public function getUploadDirectory(): string { // reverse the array, as bundles can register invoice directories a well (as prepend extensions) // and then the first entries are the directories from the bundles and not the default ones registered in Kimai foreach (array_reverse($this->documentDirs) as $dir) { if ($dir === self::DEFAULT_DIRECTORY) { continue; } return $dir; } throw new \Exception('Unknown upload directory'); } public function findByName(string $name): ?InvoiceDocument { foreach ($this->findAll() as $document) { if ($document->getId() === $name) { return $document; } } return null; } /** * Returns an array of all custom invoice documents. * * @return InvoiceDocument[] */ public function findCustom(): array { $paths = []; foreach ($this->documentDirs as $dir) { if ($dir === self::DEFAULT_DIRECTORY) { continue; } $paths[] = $dir; } return $this->findByPaths($paths); } /** * Returns an array of all original Kimai documents. * * @return InvoiceDocument[] */ public function findBuiltIn(): array { foreach ($this->documentDirs as $dir) { if ($dir === self::DEFAULT_DIRECTORY) { return $this->findByPaths([$dir]); } } return []; } /** * Returns an array of invoice documents. * * @return InvoiceDocument[] */ public function findAll(): array { return $this->findByPaths($this->documentDirs); } /** * Returns an array of invoice documents. * * @param array $paths * @return InvoiceDocument[] */ private function findByPaths(array $paths): array { $base = \dirname(\dirname(__DIR__)) . DIRECTORY_SEPARATOR; $documents = []; foreach ($paths as $searchPath) { $searchDir = $searchPath; if ($searchDir[0] !== '/') { $searchDir = $base . $searchPath; } if (!is_dir($searchDir)) { continue; } $finder = Finder::create()->ignoreDotFiles(true)->files()->in($searchDir)->depth(0)->name('*.*'); /** @var SplFileInfo $file */ foreach ($finder->getIterator() as $file) { $doc = new InvoiceDocument($file); // the first found invoice document wins if (!isset($documents[$doc->getId()])) { $documents[$doc->getId()] = $doc; } } } return $documents; } }