Skip to content

Commit

Permalink
Merge pull request #2261 from ismail1432/customize-macro
Browse files Browse the repository at this point in the history
Allow to customize macro delimiters in TemplateProcessor
  • Loading branch information
Progi1984 authored Dec 23, 2022
2 parents f195d28 + c4bcba9 commit b453cf0
Show file tree
Hide file tree
Showing 6 changed files with 645 additions and 10 deletions.
26 changes: 25 additions & 1 deletion docs/templates-processing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Templates processing
====================

You can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced.
Macros are defined like this: ``${search-pattern}``.
By default Macros are defined like this: ``${search-pattern}`` but you can define custom macros.
To load a template file, create a new instance of the TemplateProcessor.

.. code-block:: php
Expand Down Expand Up @@ -35,6 +35,30 @@ You can also set multiple values by passing all of them in an array.
$templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe'));
setMacroOpeningChars
""""""""
You can define a custom opening macro. The following will set ``{#`` as the opening search pattern.

.. code-block:: php
$templateProcessor->setMacroOpeningChars('{#');
setMacroClosingChars
""""""""
You can define a custom closing macro. The following will set ``#}`` as the closing search pattern.

.. code-block:: php
$templateProcessor->setMacroClosingChars('#}');
setMacroChars
""""""""
You can define a custom opening and closing macro at the same time . The following will set the search-pattern like this: ``{#search-pattern#}`` .

.. code-block:: php
$templateProcessor->setMacroChars('{#', '#}');
setImageValue
"""""""""""""
The search-pattern model for images can be like:
Expand Down
57 changes: 48 additions & 9 deletions src/PhpWord/TemplateProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ class TemplateProcessor
*/
protected $tempDocumentNewImages = [];

protected static $macroOpeningChars = '${';

protected static $macroClosingChars = '}';

/**
* @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception
*
Expand Down Expand Up @@ -238,8 +242,8 @@ public function applyXslStyleSheet($xslDomDocument, $xslOptions = [], $xslOption
*/
protected static function ensureMacroCompleted($macro)
{
if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') {
$macro = '${' . $macro . '}';
if (substr($macro, 0, 2) !== self::$macroOpeningChars && substr($macro, -1) !== self::$macroClosingChars) {
$macro = self::$macroOpeningChars . $macro . self::$macroClosingChars;
}

return $macro;
Expand Down Expand Up @@ -856,8 +860,12 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria
{
$xmlBlock = null;
$matches = [];
$escapedMacroOpeningChars = self::$macroOpeningChars;
$escapedMacroClosingChars = self::$macroClosingChars;
preg_match(
'/(.*((?s)<w:p\b(?:(?!<w:p\b).)*?\${' . $blockname . '}<\/w:.*?p>))(.*)((?s)<w:p\b(?:(?!<w:p\b).)[^$]*?\${\/' . $blockname . '}<\/w:.*?p>)/is',
//'/(.*((?s)<w:p\b(?:(?!<w:p\b).)*?\{{' . $blockname . '}<\/w:.*?p>))(.*)((?s)<w:p\b(?:(?!<w:p\b).)[^$]*?\{{\/' . $blockname . '}<\/w:.*?p>)/is',
'/(.*((?s)<w:p\b(?:(?!<w:p\b).)*?\\' . $escapedMacroOpeningChars . $blockname . $escapedMacroClosingChars . '<\/w:.*?p>))(.*)((?s)<w:p\b(?:(?!<w:p\b).)[^$]*?\\' . $escapedMacroOpeningChars . '\/' . $blockname . $escapedMacroClosingChars . '<\/w:.*?p>)/is',
//'/(.*((?s)<w:p\b(?:(?!<w:p\b).)*?\\'. $escapedMacroOpeningChars . $blockname . '}<\/w:.*?p>))(.*)((?s)<w:p\b(?:(?!<w:p\b).)[^$]*?\\'.$escapedMacroOpeningChars.'\/' . $blockname . '}<\/w:.*?p>)/is',
$this->tempDocumentMainPart,
$matches
);
Expand Down Expand Up @@ -896,8 +904,10 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria
public function replaceBlock($blockname, $replacement): void
{
$matches = [];
$escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
$escapedMacroClosingChars = preg_quote(self::$macroClosingChars);
preg_match(
'/(<\?xml.*)(<w:p.*>\${' . $blockname . '}<\/w:.*?p>)(.*)(<w:p.*\${\/' . $blockname . '}<\/w:.*?p>)/is',
'/(<\?xml.*)(<w:p.*>' . $escapedMacroOpeningChars . $blockname . $escapedMacroClosingChars . '<\/w:.*?p>)(.*)(<w:p.*' . $escapedMacroOpeningChars . '\/' . $blockname . $escapedMacroClosingChars . '<\/w:.*?p>)/is',
$this->tempDocumentMainPart,
$matches
);
Expand Down Expand Up @@ -1013,8 +1023,12 @@ public function saveAs($fileName): void
*/
protected function fixBrokenMacros($documentPart)
{
$brokenMacroOpeningChars = substr(self::$macroOpeningChars, 0, 1);
$endMacroOpeningChars = substr(self::$macroOpeningChars, 1);
$macroClosingChars = self::$macroClosingChars;

return preg_replace_callback(
'/\$(?:\{|[^{$]*\>\{)[^}$]*\}/U',
'/\\' . $brokenMacroOpeningChars . '(?:\\' . $endMacroOpeningChars . '|[^{$]*\>\{)[^' . $macroClosingChars . '$]*\}/U',
function ($match) {
return strip_tags($match[0]);
},
Expand Down Expand Up @@ -1053,7 +1067,10 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit)
protected function getVariablesForPart($documentPartXML)
{
$matches = [];
preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches);
$escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
$escapedMacroClosingChars = preg_quote(self::$macroClosingChars);

preg_match_all("/$escapedMacroOpeningChars(.*?)$escapedMacroClosingChars/i", $documentPartXML, $matches);

return $matches[1];
}
Expand Down Expand Up @@ -1238,8 +1255,11 @@ protected function getSlice($startPosition, $endPosition = 0)
protected function indexClonedVariables($count, $xmlBlock)
{
$results = [];
$escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
$escapedMacroClosingChars = preg_quote(self::$macroClosingChars);

for ($i = 1; $i <= $count; ++$i) {
$results[] = preg_replace('/\$\{([^:]*?)(:.*?)?\}/', '\${\1#' . $i . '\2}', $xmlBlock);
$results[] = preg_replace("/$escapedMacroOpeningChars([^:]*?)(:.*?)?$escapedMacroClosingChars/", self::$macroOpeningChars . '\1#' . $i . '\2' . self::$macroClosingChars, $xmlBlock);
}

return $results;
Expand Down Expand Up @@ -1394,7 +1414,7 @@ protected function splitTextIntoTexts($text)
}

$unformattedText = preg_replace('/>\s+</', '><', $text);
$result = str_replace(['${', '}'], ['</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space="preserve">${', '}</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space="preserve">'], $unformattedText);
$result = str_replace([self::$macroOpeningChars, self::$macroClosingChars], ['</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space="preserve">' . self::$macroOpeningChars, self::$macroClosingChars . '</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space="preserve">'], $unformattedText);

return str_replace(['<w:r>' . $extractedStyle . '<w:t xml:space="preserve"></w:t></w:r>', '<w:r><w:t xml:space="preserve"></w:t></w:r>', '<w:t>'], ['', '', '<w:t xml:space="preserve">'], $result);
}
Expand All @@ -1408,6 +1428,25 @@ protected function splitTextIntoTexts($text)
*/
protected function textNeedsSplitting($text)
{
return preg_match('/[^>]\${|}[^<]/i', $text) == 1;
$escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
$escapedMacroClosingChars = preg_quote(self::$macroClosingChars);

return 1 === preg_match('/[^>]' . $escapedMacroOpeningChars . '|' . $escapedMacroClosingChars . '[^<]/i', $text);
}

public function setMacroOpeningChars(string $macroOpeningChars): void
{
self::$macroOpeningChars = $macroOpeningChars;
}

public function setMacroClosingChars(string $macroClosingChars): void
{
self::$macroClosingChars = $macroClosingChars;
}

public function setMacroChars(string $macroOpeningChars, string $macroClosingChars): void
{
self::$macroOpeningChars = $macroOpeningChars;
self::$macroClosingChars = $macroClosingChars;
}
}
Loading

0 comments on commit b453cf0

Please sign in to comment.