template; $sourcePath = Storage::disk('local')->path($template->file_path); $presentation = IOFactory::load($sourcePath); $values = $generation->values ?? []; $textValues = []; foreach ($template->keys as $key) { if (! array_key_exists($key->key, $values)) { continue; } match ($key->type) { TemplateKeyType::Text => $textValues[$key->key] = (string) $values[$key->key], TemplateKeyType::Image => $this->fillImage($presentation, $key->shape_name, Storage::disk('local')->path($values[$key->key])), TemplateKeyType::Chart => throw new RuntimeException('پرکردن کلید از نوع چارت هنوز پشتیبانی نمی‌شود.'), }; } if ($textValues !== []) { foreach ($presentation->getAllSlides() as $slide) { $this->replaceInShapes($slide->getShapeCollection(), $textValues); } } $outputRelativePath = 'templates/generations/'.$generation->uuid.'.pptx'; $outputAbsolutePath = Storage::disk('local')->path($outputRelativePath); Storage::disk('local')->makeDirectory('templates/generations'); $writer = IOFactory::createWriter($presentation, 'PowerPoint2007'); $writer->save($outputAbsolutePath); return $outputRelativePath; } /** * @param iterable $shapes * @param array $textValues */ private function replaceInShapes(iterable $shapes, array $textValues): void { foreach ($shapes as $shape) { if ($shape instanceof RichText) { foreach ($shape->getParagraphs() as $paragraph) { $this->replaceInParagraph($paragraph, $textValues); } continue; } if ($shape instanceof TableShape) { foreach ($shape->getRows() as $row) { foreach ($row->getCells() as $cell) { foreach ($cell->getParagraphs() as $paragraph) { $this->replaceInParagraph($paragraph, $textValues); } } } continue; } if ($shape instanceof GroupShape) { $this->replaceInShapes($shape->getShapeCollection(), $textValues); } } } /** * @param array $textValues */ private function replaceInParagraph(Paragraph $paragraph, array $textValues): void { $elements = $paragraph->getRichTextElements(); if ($elements === []) { return; } $originalText = ''; foreach ($elements as $element) { $originalText .= $element->getText(); } if (! str_contains($originalText, '{')) { return; } $lookup = []; foreach ($textValues as $key => $value) { $lookup[$this->normalizeKey($key)] = $value; } $newText = preg_replace_callback( '/\{\{?\s*([^{}]+?)\s*\}?\}/u', function (array $matches) use ($lookup): string { $normalizedKey = $this->normalizeKey($matches[1]); return array_key_exists($normalizedKey, $lookup) ? $lookup[$normalizedKey] : $matches[0]; }, $originalText ); if ($newText === null || $newText === $originalText) { return; } $target = null; foreach ($elements as $element) { if ($element instanceof BreakElement) { continue; } if ($target === null) { $target = $element; $element->setText($newText); continue; } $element->setText(''); } } private function normalizeKey(string $key): string { return mb_strtolower(trim($key, "{} \t\n\r\0\x0B")); } private function fillImage(PhpPresentation $presentation, ?string $shapeName, string $imagePath): void { if ($shapeName === null || $shapeName === '') { return; } foreach ($presentation->getAllSlides() as $slide) { $this->replaceImageInShapes($slide->getShapeCollection(), $shapeName, $imagePath); } } /** * @param iterable $shapes */ private function replaceImageInShapes(iterable $shapes, string $shapeName, string $imagePath): void { foreach ($shapes as $shape) { if ($shape instanceof GroupShape) { $this->replaceImageInShapes($shape->getShapeCollection(), $shapeName, $imagePath); continue; } if ($shape->getName() !== $shapeName) { continue; } if ($shape instanceof GdDrawing) { $this->replaceGdImage($shape, $imagePath); } elseif ($shape instanceof FileDrawing) { $shape->setPath($imagePath); } } } private function replaceGdImage(GdDrawing $shape, string $imagePath): void { $info = getimagesize($imagePath); $image = imagecreatefromstring(file_get_contents($imagePath)); if ($info === false || $image === false) { throw new RuntimeException('فایل تصویر ارسالی معتبر نیست.'); } $shape->setImageResource($image); $shape->setMimeType($info['mime']); $shape->setRenderingFunction(str_replace('/', '', $info['mime'])); } }