Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can I use a template (TemplateProcessor) for odt? #952

Open
vierkantemeter opened this issue Dec 1, 2016 · 27 comments
Open

Can I use a template (TemplateProcessor) for odt? #952

vierkantemeter opened this issue Dec 1, 2016 · 27 comments

Comments

@vierkantemeter
Copy link

vierkantemeter commented Dec 1, 2016

I'm trying to create an odt file using a template, with this code:

$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('/home/docs/template.odt');
$templateProcessor->setValue('title', $title);
$templateProcessor->saveAs('/home/docs/'.$titeldoc.'.odt');

however the file is damaged, and nothing has been replaced... I can't find much on using an odf template, does anyone have this working?

Thanks!
-Michèlle


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@mikerockett
Copy link

mikerockett commented Dec 1, 2016

I'm having the same issue - using LibreOffice 5.2.0.4

@msphn
Copy link

msphn commented Dec 14, 2016

TemplateProcessor can only deal with Word 2007 and higher :-/.

@Progi1984 to be closed

@mikerockett
Copy link

mikerockett commented Dec 14, 2016

@cookiekiller - but it does work, just not properly - which means it can surely be addressed? Or perhaps it just happens to work, but not by design? And if that is the case, surely a warning shuld be issued or an exception thrown?

Scratch that - I apologise. Have used so many different ODT processors that I can't remember which one gave which result. Thst said, TemplateProcessor should still throw an exception for ODTs.

@papoteur-mga
Copy link

Hello,
I'm working on a hack to deal with ODT templates and that I will submit.
I have added tests like for Word, but with the documents saved in ODT format. It already work, except for images for now.
What I would ask is about the manner to call the processor.
For now, I have added a class TemplateProcessorOdt, keeping TemplateProcessor to deal with Word format. I created a class TemplateProcessorCommon which share the common methods and that TemplateProcessor and TemplateProcessorOdt inherits. Is it OK this way? This will leave the responsibility ta call the good class to the caller.
Or should I include in TemplateProcessor some checks about file format to call specific methods? By this way, I don't see how to use inheritance.

@knulo
Copy link

knulo commented Jan 27, 2021

@papoteur-mga
Hi, I'm very interested in your work, because I want to output both docx and odt files with HTML input and using templates in a large documentation project. Hope you will succeed soon... ;-)
Kind regards, Knut

@papoteur-mga
Copy link

Hello,
You can have a look here : https://github.com/papoteur-mga/PHPWord/commits/develop

@knulo
Copy link

knulo commented Jan 28, 2021

@papoteur-mga Thank you for sharing that.

@papoteur-mga
Copy link

@knulo If you mean this is fine, I can request a pull.

@knulo
Copy link

knulo commented Jan 28, 2021

@papoteur-mga Please give me some time to test...
BTW: Would be fine to have an output for PDF, right? ;-)

@papoteur-mga
Copy link

BTW: Would be fine to have an output for PDF, right? ;-)

Hmm, sorry, I don't understand what PDF has to do. templateProcessor takes a text document and replaces inside it the tags. If PDF is needed, this is to the developer to add a step which transform the generated text document to PDF or something telse.
Now I propose templateProcessorOdt which does the job for ODT texts.

@knulo
Copy link

knulo commented Jan 28, 2021

@papoteur-mga Was only an idea for getting output of template handeled stuff to PDF. ;-)
How do I instantiate respectively bind TemplateProcessorOdt to the phpWord instance?
At the moment I use $phpWord->loadTemplate(...) but I guess that wouldn't do the job.

@papoteur-mga
Copy link

papoteur-mga commented Jan 28, 2021

What I use is for example:

$template = new \PhpOffice\PhpWord\TemplateProcessorOdt('mytemplate.odt');
$template->setValues($dataArray);
$template->saveAs('myoutput.odt');

This is meant to be used as templateProcessor in https://phpword.readthedocs.io/en/latest/templates-processing.html but replacing with templateProssessorOdt.

@knulo
Copy link

knulo commented Jan 28, 2021

@papoteur-mga Thanks. I will discover that tomorrow.
Kind regards, Knut

@knulo
Copy link

knulo commented Jan 29, 2021

@papoteur-mga After some trouble with cloning the repo (my fault!), I'm now about to test your enhancements.
Sorry to inform you that apparently the substitution of complex blocks doesn't work.
In my template I have some 'simple' macros (they are replaced) and a block

${htmlblock}
${html}
${/htmlblock}

that is cloned for inserting the HTML input.
As a result, only the 'simple' macros are replaced and only one page is created showing the macros.
Any suggestions?
Thanks in advance and kind regards,
Knut

@papoteur-mga
Copy link

Thanks for your test.
This is a part I've not yet dealt with.
I come back later.

@knulo
Copy link

knulo commented Feb 3, 2021

@papoteur-mga O.K. and good luck!

@papoteur-mga
Copy link

Hello,
I have pushed some improvements.
I think this is probably not robust, as I don't know which surprise can be included in a current text. However, blocks are dealt.

@knulo
Copy link

knulo commented Feb 5, 2021

@papoteur-mga Thanks! I'll check your improvements next days and report my experience... ;-)

@knulo
Copy link

knulo commented Feb 6, 2021

@papoteur-mga
I have the following, given the template mentioned above (and there are simple macros in the header and footer section - they were processed with the former version):

$section = new \PhpOffice\PhpWord\Element\Section(1);
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $htmlContent, false, true);
$containers = $section->getElements();
for($i=0; $i<count($containers); $i++) {
    	$templateProcessor->setComplexBlock('html#'.($i+1), $containers[$i]);
}

This results in one blank page, the block marks are gone, but not filled with the new (desired) content. And also header and footer aren't there anymore.

If I do additionally that after the above:

$textrun = $section->addTextRun(array('pageBreakBefore' => true));
$dim = @getimagesize($mf);    // $mf = media file, an image filename
$w = 170; // mm
$h = $w * $dim[1] / $dim[0];
if ($h > 250) {
	$h = 250;
	$w = $h * $dim[0] / $dim[1];
}
$textrun->addText('Headline for image',
				array('name' => 'Arial', 'size' => 14, 'bold' => true),
				array('spaceAfter' => 250, 'spaceBefore' => 250));
$textrun->addTextBreak();
$textrun->addText('${img#'.($i+1).'}');
$textrun->addTextBreak();
$textrun->addText('some text '.basename($mf));
$templateProcessor->setComplexBlock('html#'.$i, $textrun);
$templateProcessor->setImageValue('img#'.($i+1),
							array('path' => realpath(__DIR__.'/.'.$mf),
							'width' => intval($w).'mm',
							'height' => intval($h).'mm'));

This results in one page without header and footer and only with one line:
Headline for image${img#579}some text BMMH(5).jpg

So it seems, page breaks and setImageValue aren't handeled yet?
Hope that helps you for further investigation and development.
Unfortunately at the moment I haven't the time to assist your work by diving in the code...
Kind regards
Knut

@papoteur-mga
Copy link

papoteur-mga commented Feb 13, 2021

@papoteur-mga
I have the following, given the template mentioned above (and there are simple macros in the header and footer section - they were processed with the former version):

$section = new \PhpOffice\PhpWord\Element\Section(1);
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $htmlContent, false, true);
$containers = $section->getElements();
for($i=0; $i<count($containers); $i++) {
    	$templateProcessor->setComplexBlock('html#'.($i+1), $containers[$i]);
}

This results in one blank page, the block marks are gone, but not filled with the new (desired) content. And also header and footer aren't there anymore.

Can you give a complete example. I can't detect a problem. Did you included instructions like

 $templateProcessor->cloneBlock('htmlblock', 3, true ,true);

before setComplexBlock ?

If I do additionally that after the above:

$textrun = $section->addTextRun(array('pageBreakBefore' => true));
$dim = @getimagesize($mf);    // $mf = media file, an image filename
$w = 170; // mm
$h = $w * $dim[1] / $dim[0];
if ($h > 250) {
	$h = 250;
	$w = $h * $dim[0] / $dim[1];
}
$textrun->addText('Headline for image',
				array('name' => 'Arial', 'size' => 14, 'bold' => true),
				array('spaceAfter' => 250, 'spaceBefore' => 250));
$textrun->addTextBreak();
$textrun->addText('${img#'.($i+1).'}');
$textrun->addTextBreak();
$textrun->addText('some text '.basename($mf));
$templateProcessor->setComplexBlock('html#'.$i, $textrun);
$templateProcessor->setImageValue('img#'.($i+1),
							array('path' => realpath(__DIR__.'/.'.$mf),
							'width' => intval($w).'mm',
							'height' => intval($h).'mm'));

This results in one page without header and footer and only with one line:
Headline for image${img#579}some text BMMH(5).jpg

So it seems, page breaks and setImageValue aren't handeled yet?
Hope that helps you for further investigation and development.
Unfortunately at the moment I haven't the time to assist your work by diving in the code...
Kind regards
Knut

The same here, did you clone blocks before?

@knulo
Copy link

knulo commented Feb 16, 2021

@papoteur-mga
Sorry for late reply... 🙏

  1. Yes, I have, just before the loop (sorry to miss this in my former code snippet):
$templateProcessor->cloneBlock('htmlblock', count($containers)+count($mediaFiles), true, true);
  1. see 1): count of containers plus media files

And the same code works with Docx template processor. So I guess an issue with template processing for Odt.
Kind regards
Knut

@papoteur-mga
Copy link

@knulo : no problem, I have no production constraints ;)
Can you check that the code$containers = $section->getElements(); provides what you expect?
And can you provide me something more complete, with your HTML code, for tests on my side?

@knulo
Copy link

knulo commented Feb 16, 2021

@papoteur-mga
The statement $section->getElements() retrieves the right content (remember: the same code is working fine on Docx template processor).
I'll build a small testemonial, so I can provide you the base data - stay patient... 😁

@knulo
Copy link

knulo commented Feb 16, 2021

@papoteur-mga
Mea culpa!
While creating the testemonial I found out that I output a (not used) writer instance instead of template processor (commented out in code.php of the testemonial). So the result must be empty! Sorry for that!

Now the odt is generated with content (big surprise!) 😁
But besides that: No formatting (headlines, bold, italic) is done in case of Odt and the font (Arial) isn't process correct.
The testemonial files are here

Kind regards and thanks for your patience
Knut

@papoteur-mga
Copy link

Hi Knut,
I have done some more investigation with your example, thanks for it.
I think that this is in this portion of code in setComplexBlock:

        $xmlWriter = new XMLWriter();
        $xmlWriter->setIndent(false);
        $elementWriter = new $objectClass($xmlWriter, $complexType, false);
        $elementWriter->write();
        $xmlWriter->getData();

At the last line, there is no formatting data. This is what is inserted in the document. Thus I would say that the XMLWriter for ODT doesn't provide the formatting you expect. This is the same code as for Word2007 templates.
Thus, probably "not my fault" :/
I didn't build an testimonial to prove that.

@ucenxyz
Copy link

ucenxyz commented Oct 8, 2021

Hello, I'm working on a hack to deal with ODT templates and that I will submit. I have added tests like for Word, but with the documents saved in ODT format. It already work, except for images for now. What I would ask is about the manner to call the processor. For now, I have added a class TemplateProcessorOdt, keeping TemplateProcessor to deal with Word format. I created a class TemplateProcessorCommon which share the common methods and that TemplateProcessor and TemplateProcessorOdt inherits. Is it OK this way? This will leave the responsibility ta call the good class to the caller. Or should I include in TemplateProcessor some checks about file format to call specific methods? By this way, I don't see how to use inheritance.

it's work, when i got missing watermark on convert docx to pdf with soffice.
now i have odt generated file, then i convert odt to pdf and watermark is show 👍

@Kalmon
Copy link

Kalmon commented Mar 27, 2024

Hello, You can have a look here : https://github.com/papoteur-mga/PHPWord/commits/develop

The "setImageValue" function did not work, the text with the key disappeared, but the image did not appear. In the docx it appears normal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants