From 19c1f80589e14a310e16f9a1014181276a96cc4a Mon Sep 17 00:00:00 2001 From: nikic Date: Tue, 3 Apr 2012 22:47:41 +0200 Subject: [PATCH] Add simple templating support. Templates use __name__ placeholders. A variant of the placeholder with a capitalized first latter can be accessed using __Name__ (this is useful for camel case identifiers, e.g. get__Name__). Currently the implemention is not particularly clean, because the Template instantiates a Lexer itself. Fixing this requires a major refactoring of the lexer/parser interface. --- lib/PHPParser/Template.php | 84 +++++++++++++++++++++++++++ test/PHPParser/Tests/TemplateTest.php | 54 +++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/PHPParser/Template.php create mode 100644 test/PHPParser/Tests/TemplateTest.php diff --git a/lib/PHPParser/Template.php b/lib/PHPParser/Template.php new file mode 100644 index 0000000..3e56f2d --- /dev/null +++ b/lib/PHPParser/Template.php @@ -0,0 +1,84 @@ +parser = $parser; + $this->template = $template; + } + + /** + * Get the statements of the template with the passed in placeholders + * replaced. + * + * @param array $placeholders Placeholders + * + * @return PHPParser_Node[] Statements + */ + public function getStmts(array $placeholders) { + /* + * TODO This is evil. + * The lexer shouldn't be created in here, instead it should be a dependency, which + * basically means that we'd need to have a LexerFactory (which seems strange). + * An alternative solution would be to make the lexer work similar to how the parser + * works. I.e. one would instantiate the Lexer only once and then pass the results + * of ->lex() to the parser (which would then be the full tokens array). This design + * seems cleaner, but comes at the expense of higher memory consumption, as the token + * array can be quite large. + */ + return $this->parser->parse( + new PHPParser_Lexer_Emulative( + $this->getTemplateWithPlaceholdersReplaced($placeholders) + ) + ); + } + + protected function getTemplateWithPlaceholdersReplaced(array $placeholders) { + if (empty($placeholders)) { + return $this->template; + } + + return strtr($this->template, $this->preparePlaceholders($placeholders)); + } + + /* + * Prepare the placeholders for replacement. This means that + * a) all placeholders will be surrounded with __. + * b) ucfirst/lcfirst variations of the placeholders are generated. + * + * E.g. for an input array of ['foo' => 'bar'] the result will be + * ['__foo__' => 'bar', '__Foo__' => 'Bar']. + */ + protected function preparePlaceholders(array $placeholders) { + $preparedPlaceholders = array(); + + foreach ($placeholders as $name => $value) { + $preparedPlaceholders['__' . $name . '__'] = $value; + + if (ctype_lower($name[0])) { + $ucfirstName = ucfirst($name); + if (!isset($placeholders[$ucfirstName])) { + $preparedPlaceholders['__' . $ucfirstName . '__'] = ucfirst($value); + } + } + + if (ctype_upper($name[0])) { + $lcfirstName = lcfirst($name); + if (!isset($placeholders[$lcfirstName])) { + $preparedPlaceholders['__' . $lcfirstName . '__'] = lcfirst($value); + } + } + } + + return $preparedPlaceholders; + } +} \ No newline at end of file diff --git a/test/PHPParser/Tests/TemplateTest.php b/test/PHPParser/Tests/TemplateTest.php new file mode 100644 index 0000000..61bbdee --- /dev/null +++ b/test/PHPParser/Tests/TemplateTest.php @@ -0,0 +1,54 @@ +assertEquals( + $expectedPrettyPrint, + $prettyPrinter->prettyPrint($template->getStmts($placeholders)) + ); + } + + public function provideTestPlaceholderReplacement() { + return array( + array( + ' 'foo'), + '$foo + $Foo;' + ), + array( + ' 'Foo'), + '$foo + $Foo;' + ), + array( + ' 'foo', 'Name' => 'Bar'), + '$foo + $Bar;' + ), + array( + ' 'Bar', 'name' => 'foo'), + '$foo + $Bar;' + ), + array( + ' 'infix'), + '$prefixInfixSuffix;' + ), + array( + ' 'foo'), + '$_foo_;' + ) + ); + } +} \ No newline at end of file