/** * Method: cloneRow * ========================================================================= * Clone a table row in a template document. * * > NOTE: Currently only works in the main body content. * > Will not work in headers and footers. * * Parameters: * ------------------------------------------------------------------------- * - $search: * - $numberOfClones: * * Returns: * ------------------------------------------------------------------------- * */ public function cloneRow($search, $numberOfClones) { $search = $this->normaliseStartTag($search); $xml = $this->documentXML->asXml(); if (($tagPos = strpos($xml, $search)) === false) { throw new RuntimeException('Can not clone row, template variable not found ' . 'or variable contains markup.'); } $rowStart = $this->findRowStart($xml, $tagPos); $rowEnd = $this->findRowEnd($xml, $tagPos); $xmlRow = Str::slice($xml, $rowStart, $rowEnd); // Check if there's a cell spanning multiple rows. if (preg_match('#<w:vMerge w:val="restart"/>#', $xmlRow)) { // $extraRowStart = $rowEnd; $extraRowEnd = $rowEnd; while (true) { $extraRowStart = $this->findRowStart($xml, $extraRowEnd + 1); $extraRowEnd = $this->findRowEnd($xml, $extraRowEnd + 1); // If extraRowEnd is lower then 7, there was no next row found. if ($extraRowEnd < 7) { break; } // If tmpXmlRow doesn't contain continue, // this row is no longer part of the spanned row. $tmpXmlRow = Str::slice($xml, $extraRowStart, $extraRowEnd); if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) && !preg_match('#<w:vMerge w:val="continue" />#', $tmpXmlRow)) { break; } // This row was a spanned row, // update $rowEnd and search for the next row. $rowEnd = $extraRowEnd; } $xmlRow = Str::slice($xml, $rowStart, $rowEnd); } $result = Str::slice($xml, 0, $rowStart); for ($i = 1; $i <= $numberOfClones; $i++) { $result .= preg_replace('/\\$\\{(.*?)\\}/', '\\${\\1_' . $i . '}', $xmlRow); } $result .= Str::slice($xml, $rowEnd); $this->documentXML = $this->xml($result); }