Search code examples
phptemplateslibreofficeodt

ODTPHP and segments


I'm using odt-php library to customize .odt template with personnal datas.

I'm currently stuck during the 6th tutorial, where I want to duplicate a row of a table.

The code is running fine when I use the default segment name : articles

$app = $odf->setSegment('articles');
foreach ($listing_app as $element) 
{
    $app->descrApp($element['descr']);
    $app->refApp($element['ref']);
    $app->merge();  
}
$odf->mergeSegment($app);

But when I want to replace/edit/create a new segment with another name (here test. It does not work

Fatal error: Uncaught exception 'OdfException' with message ''test' segment not found in the document'

The code is exactly the same

$app = $odf->setSegment('test');
foreach ($listing_app as $element) 
{
    $app->descrApp($element['descr']);
    $app->refApp($element['ref']);
    $app->merge();  
}
$odf->mergeSegment($app);

And I do have those lines in my .odt :

[!-- BEGIN row.test --] {descrApp} {refApp} [!-- END row.test --]

I tried to copy/paste from the online tutorial just by editing the segment name. And I also tried to re-write everything. Nothing seems to be working.

I also tried to export my template.odt as xml and nothing seems to be screw up

<informaltable frame="all">
    <tgroup cols="3"><tbody><row><entry><para/></entry><entry><para/></entry><entry><para/></entry></row><row><entry><para>[!-- BEGIN row.articles --]{descrApp}</para></entry><entry><para>{refApp}</para></entry><entry><para/><para/><para>[!-- END row.articles --]</para></entry></row></tbody></tgroup>
  </informaltable>

edit

I found that the error is coming from this function

public function setSegment($segment)
{
    if (array_key_exists($segment, $this->segments)) {
        return $this->segments[$segment];
    }
    // $reg = "#\[!--\sBEGIN\s$segment\s--\]<\/text:p>(.*?)<text:p\s.*>\[!--\sEND\s$segment\s--\]#sm";
    $reg = "#\[!--\sBEGIN\s$segment\s--\](.*?)\[!--\sEND\s$segment\s--\]#smU";
    if (preg_match($reg, html_entity_decode($this->contentXml), $m) == 0) {
        throw new OdfException("'$segment' segment not found in the document");
    }
    $this->segments[$segment] = new Segment($segment, $m[1], $this);
    return $this->segments[$segment];
}

I do not know enough about regex but do you think this could be not up-to-date?


Solution

  • The problem is not mainly caused by odtPhp! The problem is caused by the way you modify the template odt file. As soon as you edit the row label in the template document in a (newer) open/libreoffice, it adds some unwanted formaters into it:

    Original code:

    [!-- BEGIN row.articles --]
    

    New code:

    [!-- BEGIN row.<text:span text:style-name="T4">articles</text:span> --]
    

    The easiest fix is to rewrite the whole place holder. Alternatively you can do the following:

    1. Modify the template file as wanted.
    2. Unpack the odt file (is a simple zip file)
    3. Remove those unwanted tags manually again in a text editor (file: content.xml)
    4. Pack the files again into a zip file and rename it back to .odt.

    Additional notes:

    As a test, I weakened the tag detector in the function setSegment to still fire as wanted:

    $reg = "#\[!--\sBEGIN\s(.*?)$segment(.*?)\s--\](.*?)\[!--\sEND\s(.*?)$segment(.*?)\s--\]#smU";
    

    How ever this seems to lead to false positives and an error later down in the library.