-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
PHPWord - CloneBlock not working #1071
Comments
I tried with the current development branch with the following code $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/template.docx');
$templateProcessor->cloneBlock('EDUCATIONBLOCK', count($myProfile['EDUCATION']));
$templateProcessor->saveAs('results/generated_templateFile.docx'); The result is the following word document |
@troosan That too is not helpful you know. |
I can imagine that's not the end result you are looking for :-) After that you'll need to replace. |
If you don't mind modifying sourcecode: ./vendor/phpoffice/phpword/src/PhpWord/TemplateProcessor.php Go to the public function cloneBlock() and there add a new parameter:
Note I also changed the regexp to suit my needs (as the current version seems to spew out malformed xml and LibreOffice complains about it, I'll test it at work this week on MSOffice and maybe ask a pull request, after learning how to do that). The thing is: both ${yourblock} needs to be on a separate line (paragraph) for my modification to work. So if the old regexp works for you, then remove mine and uncomment the original back in. Will probably use more fancy functions like cloneRow() does to search for places to snip and cut. EDIT 2017-09-25: Modified the regexp so that the test also works, from the ./vendor/ directory:
So it now goes to the first
EDIT2: |
@ahmednawazbutt |
I've had persistent and hard to trace issues with the cloneBlock failing too, the XML written by Word can break the regex given (or the modified ones I've seen). Also imho regex can be quite brittle. The below is a replacement using standard string functions. It's undoubtedly slower and less elegant that the regex version, but it's proven more robust for me - and easier to understand. ` public function cloneBlock($blockname, $clones = 1, $replace = true)
` |
Hi @troosan, I would like to suggest you add the method posted by @cruachan as e.g. If you want I can send a PR? |
Try to change cloneBlock regexp to following, might help: I've created a class extending project's template processor: namespace PhpOffice\PhpWord; class TemplateProcessorMod extends TemplateProcessor {
} This regex prevents catastrophic backtracking for xml. Sometimes this was the issue for me. |
hm |
Hi, you should take a look at my ticket because I have the same problem : #1836 I've just posted a rewrite of the function which bypasses the issue for my cases. |
I've just noticed that setting pcre.jit = 1 in /etc/php.ini makes a world of difference! Before I had some blocks replaced and some not. Also the code was sluggish. After setting pcre.jit = 1 all is fine using phpOffice::phpWord v0.17.0 (01 oct 2019). |
looks like old pcre version error
don't clone block
clone block |
replace buggy preg_match public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null)
{
$xmlBlock = null;
[$block, $content] = $this->findBlockParts($blockname);
if (isset($content)) {
$xmlBlock = $content;
if ($indexVariables) {
$cloned = $this->indexClonedVariables($clones, $xmlBlock);
} elseif ($variableReplacements !== null && is_array($variableReplacements)) {
$cloned = $this->replaceClonedVariables($variableReplacements, $xmlBlock);
} else {
$cloned = array();
for ($i = 1; $i <= $clones; $i++) {
$cloned[] = $xmlBlock;
}
}
if ($replace) {
$this->tempDocumentMainPart = str_replace(
$block,
implode('', $cloned),
$this->tempDocumentMainPart
);
}
}
return $xmlBlock;
}
public function replaceBlock($blockname, $replacement)
{
[$block, $content] = $this->findBlockParts($blockname);
if (isset($content)) {
$this->tempDocumentMainPart = str_replace(
$block,
$replacement,
$this->tempDocumentMainPart
);
}
}
protected function findBlockParts($blockname)
{
$open = mb_strpos($this->tempDocumentMainPart, '${' . $blockname . '}');
if($open === false) {
return [null, null];
}
$close = mb_strpos($this->tempDocumentMainPart, '${/' . $blockname . '}');
if($close === false) {
return [null, null];
}
$start = mb_strrpos(mb_substr($this->tempDocumentMainPart, 0, $open), '<w:p>');
$end = mb_strpos($this->tempDocumentMainPart, '</w:p>', $close) + mb_strlen('</w:p>');
$openEnd = mb_strpos($this->tempDocumentMainPart, '</w:p>', $open) + mb_strlen('</w:p>');
$closeStart = mb_strrpos(mb_substr($this->tempDocumentMainPart, 0, $close), '<w:p>');
$block = mb_substr($this->tempDocumentMainPart, $start, $end - $start);
$content = mb_substr($this->tempDocumentMainPart, $openEnd, $closeStart - $openEnd);
return [$block, $content];
} |
Hope everyone is doing great.
i am having trouble using PHPWord extension for my web Application that I installed using composer using:
Now, when It comes to add a single value variable, the setValue() works like a charm. but when I need to copy a set of lines, the cloneBlock() method does not work at all.
No change at all. I don't see any cloned block in my document. Please help.
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
The text was updated successfully, but these errors were encountered: