phptemplatesms-wordphpword

PHPWord template processing with block row cloning inside a block clone


I'm using PHPWord to create reports that make use of a .docx template.

This library allows me to clone a block and clone table rows. However the examples are separate from each other. I need to combine both approaches because my template table looks like this:

${block_group}
+--------+----------------------------------------------------------------+
| Group: | ${group}                                                       |
+--------+------------+---------------------------------------------------+
| Name                | Address                                           |
+---------------------+---------------------------------------------------+
| ${name}             | ${address}                                        |
+---------------------+---------------------------------------------------+
${/block_group}

Requirements:

What I Have

So far this is what my code looks like:

# Create the template processor
$templateProcessor = new TemplateProcessor('/path/to/template/Template.docx');

# Block cloning
$replacements = array(
    array('group' => 'Group 1'),
    array('group' => 'Group 2')
);
$templateProcessor->cloneBlock('block_group', 0, true, false, $replacements);

As you can see, $replacements only took care of the ${group} placeholder because that's the only thing I'm worried about for the clone block step. I now have two tables, the ${group} placeholders are properly set, so on to the ${name} and ${address} placeholders.

Now that I need to clone table rows for each group, I'm stuck, I don't know how to even begin coding it.


This is how the file that I get when I run my current code looks like:

+--------+----------------------------------------------------------------+
| Group: | Group 1                                                        |
+--------+------------+---------------------------------------------------+
| Name                | Address                                           |
+---------------------+---------------------------------------------------+
| ${name}             | ${address}                                        |
+---------------------+---------------------------------------------------+

+--------+----------------------------------------------------------------+
| Group: | Group 2                                                        |
+--------+------------+---------------------------------------------------+
| Name                | Address                                           |
+---------------------+---------------------------------------------------+
| ${name}             | ${address}                                        |
+---------------------+---------------------------------------------------+

Solution

  • After countless attempts I finally figured a way to do this (not really sure if it's the best approach, but it works).

    Assumptions

    Assuming my data looks like this:

    $data = array(
        'Group 1' => array(
            array(
                'name' => 'John Smith',
                'address' => '123 Main Rd.'
            ),
            array(
                'name' => 'Jane Doe',
                'address' => '456 Second St.'
            )
        ),
        'Group 2' => array(
            array(
                'name' => 'Noah Ford',
                'address' => '987 Rich Blvd.'
            ),
            array(
                'name' => 'Oliver Brown',
                'address' => '654 Third St.'
            )
        )
    );
    

    Clone Block

    The first step is to clone the block:

    # Block cloning
    $replacements = array();
    $i = 0;
    foreach($data as $group_name => $group) {
        $replacements[] = array(
            'group' => $group_name,
            'name' => '${name_'.$i.'}',
            'address' => '${address_'.$i.'}'
        );
    
        $i++;
    }
    $templateProcessor->cloneBlock('block_group', count($replacements), true, false, $replacements);
    

    The main idea here is to not put any row data yet but instead change the placeholder identifiers to include the group index.

    After this code, the document should look like this:

    +--------+----------------------------------------------------------------+
    | Group: | Group 1                                                        |
    +--------+------------+---------------------------------------------------+
    | Name                | Address                                           |
    +---------------------+---------------------------------------------------+
    | ${name_0}           | ${address_0}                                      |
    +---------------------+---------------------------------------------------+
    
    +--------+----------------------------------------------------------------+
    | Group: | Group 2                                                        |
    +--------+------------+---------------------------------------------------+
    | Name                | Address                                           |
    +---------------------+---------------------------------------------------+
    | ${name_1}           | ${address_1}                                      |
    +---------------------+---------------------------------------------------+
    

    Clone Table Row

    The final step is to clone the table rows according to your data.

    # Table row cloning
    $i = 0;
    foreach($data as $group) {
        $values = array();
        foreach($group as $row) {
            $values[] = array(
                "name_{$i}" => $row['name'],
                "address_{$i}" => $row['address']
            );
        }
        $templateProcessor->cloneRowAndSetValues("name_{$i}", $values);
    
        $i++;
    }
    

    After this code, the document should look like this:

    +--------+----------------------------------------------------------------+
    | Group: | Group 1                                                        |
    +--------+------------+---------------------------------------------------+
    | Name                | Address                                           |
    +---------------------+---------------------------------------------------+
    | John Smith          | 123 Main Rd.                                      |
    +---------------------+---------------------------------------------------+
    | Jane Doe            | 456 Second St.                                    |
    +---------------------+---------------------------------------------------+
    
    +--------+----------------------------------------------------------------+
    | Group: | Group 2                                                        |
    +--------+------------+---------------------------------------------------+
    | Name                | Address                                           |
    +---------------------+---------------------------------------------------+
    | Noah Ford           | 987 Rich Blvd.                                    |
    +---------------------+---------------------------------------------------+
    | Oliver Brown        | 654 Third St.                                     |
    +---------------------+---------------------------------------------------+