Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TemplateProcessor::replaceSubstring() #1152

Closed

Conversation

SailorMax
Copy link
Contributor

While TemplateProcessor set variables via replace substrings, but DOCX can has "broken" variables names (

<w:r><w:t>${</w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:t>aaaaa</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:t>}</w:t></w:r>

instead of ${aaaaa}) lets users have option to just replace very_long_variable_names without ${}

@FBnil
Copy link

FBnil commented Oct 11, 2017

But the fixBrokenMacros() actually pulls the $ { } together (sometimes with catastrophic consequences). after that function, the macro's are findable.

your string actually reduces to (made a new testcase for this):

<w:r><w:t>${aaaaa}</w:t></w:r>

so what you actually may want is a global setting where ensureMacroCompleted() is disabled?

	public static $ensureMacroCompletion = true;

    /**
     * @param string $macro
     *
     * @return string
     */
    protected static function ensureMacroCompleted($macro)
    {
        if (TemplateProcessor::$ensureMacroCompletion && substr($macro, 0, 2) !== '${' && substr($macro, -1)
            $macro = '${' . $macro . '}';
        }

        return $macro;
    }

edit: fixed static

2 lines of code for the same functionality...

Now you TemplateProcessor::$ensureMacroCompletion = false
and every new TemplateProcessor() will not ensureMacroCompleted...

@SailorMax
Copy link
Contributor Author

@FBnil Your solution is also possible. But mine allow to replace not only variables. Any text.

P.S. fixBrokenMacros() is still bad solution. What it will return on strings like: "25$ plus some info {hint}"? It will lost text formation.

@FBnil
Copy link

FBnil commented Oct 13, 2017

@SailorMax Not quite, if you disable fixBrokenMacros(), then you can search for any text too because it would be the same as your duplicated code from setValue(). And what I propose is 2 lines of changed code, versus your code that actually removes functionality from setValueForPart().

@SailorMax
Copy link
Contributor Author

@FBnil
again, your solution is possible, but mine is better :) Why?

  1. current version of TemplateProcessor has bad solution for XML templates. It has to work with document via XML objects. It has to support not only DOCX templates (at least ODT also). In future it has to be rewritten.
  2. when it will be rewritten API can be the same. In result setValue() has to do the same - set value for variables. Not replace any substrings.
  3. for replace substrings, in my opinion, we have to has separate method.
  4. I think this is bad practice to change separate function behavior based on some global setting.

@FBnil
Copy link

FBnil commented Oct 16, 2017

@SailorMax ok, I see your point now and it is clever code. Naming-wise, i would call it replaceRaw() because, hey, its xml, not a long string... (or else harddisks and databases are a long strings too ;) )

I can not understand this, but the coverage says it's ok, as do the testcases. using preg_quote instead of the xml escaper... mwah... would need to think about bordercases for this.
$searchString = '/(?!<<*)'. preg_quote($searchString, '/'). '(?!>*>)/u';

About rewriting TemplateProcessor: I agree (and it is daunting). By using only xml trees you can immediately start using the "other" part of PHPWord. But as you know, TemplateProcessor has always been a bit isolated from the rest of the code.

I was thinking an intermediate stage, about something with tables, where you have a makeTable() and get a table object, you populate it with existing commands like ->addCell() and then setBlock('blockname', $tableObject); and the new setBlock would know what it was (not a string), and extract the w:tbl XML and inject it. It is still in idea phase, and I have some code but it is still meh.

@SailorMax
Copy link
Contributor Author

@FBnil
replaceSubstring() != replaceRaw(). "Strange" regular expression search only substrings inside ">" and "<"! replaceSubstring() replace exactly users substrings. It doesn't work in cross tags cases, but in simpler cases it work and do not broke XML structure.

preg_quote() used because I have own REG_EXP_DELIMITER, but escaper add his own.

Is the current implementation of setValue() didn't do the same as your setBlock(), but without pre-founded list of variables?

@coveralls
Copy link

Coverage Status

Coverage increased (+0.009%) to 94.892% when pulling cf13c33 on SailorMax:template_replace_substring into c5d0f71 on PHPOffice:develop.

@troosan
Copy link
Contributor

troosan commented Jan 3, 2019

@SailorMax this should not be a problem anymore, as "broken" variable names are being corrected correctly now.

@SailorMax
Copy link
Contributor Author

Agree. replaceBlock() works the same way.

@SailorMax SailorMax closed this Mar 1, 2019
@SailorMax SailorMax deleted the template_replace_substring branch March 1, 2019 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

4 participants