Generování PDF z DOCX šablony

Rndoom04
Člen | 58
+
0
-

Dobrý večer vývojáři,
doufám, že jsem téma nezařadil špatně a někoho to nepohorší. :)

Přicházím s dotazem „Jak s docx šablony vygenerovat PDF?“. Našel jsem skvělou knihovnu phpoffice/phpword. Z docx šablony si vytvořím výsledný soubor (nahraním proměnných za texty a přidáním tabulky) – faktura. Soubor je bez chyb. Avšak váznu u generování PDF. PDFko prostě nevypadá tak, jak by mělo – ani zdaleka. Prosím o radu co dělám špatně.

$sablona = WWW_DIR."/tajna/cesta/sablona.docx";
        $faktura_location_docx = WWW_DIR."/tajna/cesta/vygenerovano/vydane/faktura.docx";
        $faktura_location_pdf = WWW_DIR."/tajna/cesta/vygenerovano/vydane/faktura.pdf";
        $pravodni_tabulka = [
            'typ_faktury' => "Faktura",
            'cislo_faktury' => "1-2021-0001",
            'variabilni_symbol' => "123456789",
            'datum_vystaveni' => "1.1.2021",
            'datum_splatnosti' => "1.2.2021",

            'odberatel_jmeno' => "Jane Doe",
            'odberatel_adresa' => "Adresa 123, 12345 Město",
            'odberatel_stat' => "Česká republika",
            'odberatel_ico' => "123 45 678",
            'odberatel_dic' => "",

            'castka_celkem' => "1.500 Kč",
            'castka_uhrazeno_zalohout' => "0.00 Kč",
            'castka_zbyva_uhradit' => "1.500 Kč",

            'poznamka' => "",
            'poznamka_2' => "",
        ];

        copy($sablona,$faktura_location_docx);

        // Vytvoř tabulku s produkty
        // Vytvoř styly
        $table_style = array(
            'unit' => \PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT,
            'width' => 100 * 50
        );
        $tabulkaPrvniRadek = array('size' => 7, 'bold' => true);
        $tabulkaBunkyStyl = array(
            'borderBottomColor' =>'000000',
            'borderBottomSize' => 1,
            'valign' =>'center',
        );
        $tabulkaBunkyStylText = array(
            'size' => 7,
            'bold' => false,
        );

        // Zarovnání
        $cellVCentered = array('valign' => 'center');
        $cellHCenter = array(
            'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER,
            'spaceBefore' => 50,
            'spaceAfter' => 50
        );
        $cellHLeft = array(
            'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::LEFT,
            'spaceBefore' => 50,
            'spaceAfter' => 50
        );
        $cellHRight = array(
            'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::RIGHT,
            'spaceBefore' => 50,
            'spaceAfter' => 50
        );

        // Vytvoř element
        $phpWord  = new \PhpOffice\PhpWord\PhpWord();
        $phpWord->addTableStyle('produktyTable', $table_style);
        $section = $phpWord->addSection();
        $table = $section->addTable('produktyTable');

        // Přidej tabulce „hlavičku” (první řádek)
        $table->addRow();
        $table->addCell(5550,$tabulkaBunkyStyl)->addText("Označení zboží, či služby", $tabulkaPrvniRadek, $cellHLeft);
        $table->addCell(1000,$tabulkaBunkyStyl)->addText("Počet m. j.", $tabulkaPrvniRadek, $cellHRight);
        $table->addCell(1000,$tabulkaBunkyStyl)->addText("Cena za m. j.", $tabulkaPrvniRadek,$cellHRight);
        $table->addCell(800,$tabulkaBunkyStyl)->addText("Celkem", $tabulkaPrvniRadek,$cellHRight);

        // Přidej jednotlivé produkty
        for ($r = 1; $r <= 8; $r++) {
            $table->addRow();
            $table->addCell(5550,$tabulkaBunkyStyl)->addText("Produkt $r", $tabulkaBunkyStylText, $cellHLeft,);
            $table->addCell(1000,$tabulkaBunkyStyl)->addText("1", $tabulkaBunkyStylText, $cellHRight);
            $table->addCell(1000,$tabulkaBunkyStyl)->addText("1.500 Kč", $tabulkaBunkyStylText, $cellHRight);
            $table->addCell(800,$tabulkaBunkyStyl)->addText("1.500 Kč", $tabulkaBunkyStylText, $cellHRight);
        }

        // Vytvoř writer pro konverzi XML
        $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');

        // Získej všechny XMLv dokumentu
        $fullxml = $objWriter->getWriterPart('Document')->write();

        // Získej jenom XML tabulky
        $tablexml = preg_replace('/^[\s\S]*(<w:tbl\b.*<\/w:tbl>).*/', '$1', $fullxml);

        // Otevři dokument s ${table}
        $template_document = new \PhpOffice\PhpWord\TemplateProcessor($faktura_location_docx);

        // Změn hodnotu tabulky
        $template_document->setValue('tabulka_s_produkty', $tablexml);

        foreach($pravodni_tabulka as $klic => $nova_hodnota) {
            $klic = str_replace(['$','{','}'], ['','',''], $klic);
            $template_document->setValue($klic, $nova_hodnota);
        }

        // Ulož hotovou fakturu do docx
        $template_document->saveAs($faktura_location_docx);

        // Ulož do PDF
        $domPdfPath = realpath(PHPWORD_BASE_DIR . '/../vendor/dompdf/dompdf');
        \PhpOffice\PhpWord\Settings::setPdfRendererPath($domPdfPath);
        \PhpOffice\PhpWord\Settings::setPdfRendererName('DomPDF');

        //Save it
        $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord , 'PDF');
        $xmlWriter->save($faktura_location_pdf);

Přikládám obrázek chyby https://ibb.co/KW58xqx

Budu rád za jakoukoliiv pomoc. :)

Editoval Rndoom04 (18. 12. 2020 20:40)

dakur
Člen | 191
+
0
-

@Rndoom04 Ahoj, jednak tady není úplně správné místo – jsi na fóru ke frameworku Nette. Více se to hodí na fórum jakpsatweb.cz, příp. na Stackoverflow, pokud se nebojíš angličtiny (je tam větší komunita).

Ale když už jsi to napsal – z toho, co je na obrázku, mi to nejvíc připadá jako chybějící styly. S tím nástrojem nemám žádné zkušenosti, ale je dost možné, že třeba některé features DOCX formátu prostě neumí (podobně jako Open/LibreOffice). Osobně bych šel klasickou cestou – ořezat výstup na minimum a postupně po kouskách přidávat prvky a každý z nich nejdřív odladit tak, aby dělal/vypadal, jak má. Víc ti asi za sebe nedokážu pomoct. 🙂

Šaman
Člen | 2528
+
0
-

Taky bych řekl, že si to nacuclo jen strukturu a data. To nastylovaní si možná budeš muset provést ručně. Ale sám tu knihovnu používám jen pro čtení, či generování XLS, na PDF mám jinou a dokumenty skládám ručně. Ani jsem nevěděl, že je možná automatická konverze.