manipulating template in PHPWord

John Micah Fernandez Miguel picture John Micah Fernandez Miguel · Jan 28, 2013 · Viewed 25.8k times · Source

I am using a word document generator for PHP for the reports module of the web-app i am developing. I choose PHPWord because the free version of PHPDocX has very limited functionality plus it has a footer that it is only a free version. I have a template given by the client. What I want is I want to load the template and add dynamic elements to it like additional text or tables. My code is here:

<?php
require_once '../PHPWord.php';

$PHPWord = new PHPWord();

$document = $PHPWord->loadTemplate('Template.docx');
$document->setValue('Value1', 'Great');

$section = $PHPWord->createSection();
$section->addText('Hello World!');
$section->addTextBreak(2);

$document->setValue('Value2', $section);

$document->save('test.docx');
?>

I tried to create a new section and tried to assign it to one variable in the template(Value2) but this error appeared:

[28-Jan-2013 10:36:37 UTC] PHP Warning:  utf8_encode() expects parameter 1 to be string, object given in /Users/admin/localhost/PHPWord_0.6.2_Beta/PHPWord/Template.php on line 99

Answer

Jeroen Moors picture Jeroen Moors · Mar 13, 2013

setValue expects the second parameter to be a plain string. It's not possible to provide a section object.

I've dived into the code and there's not an easy way to have a section object returning a value that could be used by the setValue function.

As I had the same issue, I've wrote a patch for the Template.php file that allows you to clone table rows before replacing their tags with setValue. Each row gets an unique id, allowing you to identify the template tags for each different row.

This is how it works:

Add this function to your Template.php file (found inside the PHPWord directory)

public function cloneRow($search, $numberOfClones) {
    if(substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
        $search = '${'.$search.'}';
    }
    $tagPos      = strpos($this->_documentXML, $search);
    $rowStartPos = strrpos($this->_documentXML, "<w:tr", ((strlen($this->_documentXML) - $tagPos) * -1));
    $rowEndPos   = strpos($this->_documentXML, "</w:tr>", $tagPos) + 7;

    $result = substr($this->_documentXML, 0, $rowStartPos);
    $xmlRow = substr($this->_documentXML, $rowStartPos, ($rowEndPos - $rowStartPos));
    for ($i = 1; $i <= $numberOfClones; $i++) {
        $result .= preg_replace('/\$\{(.*?)\}/','\${\\1#'.$i.'}', $xmlRow);
    }
    $result .= substr($this->_documentXML, $rowEndPos);
    $this->_documentXML = $result;
}

In your template file add to each table one row that you will use as a template row. Let's assume you've added a tag ${first_name} in this row.

To get a table with 3 rows call: $document->cloneRow('first_name', 3);

The working copy of your template is now updated with a table containing 3 rows. Each tag inside the row has been appended with a # and row number.

To set your values, use setValue $document->setValue('first_name#1', 'Name on the first row'); $document->setValue('first_name#2', 'Name on the second row'); $document->setValue('first_name#3', 'Name on the third row');

I hope this is useful! I'll keep an updated version of the code and documentation here: http://jeroen.is/phpword-templates-with-repeating-rows/