From 4f5b44bd3bd490309eb2ba7b44df4769816ba729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Sat, 3 Aug 2013 19:26:54 +0200 Subject: twig implementation --- .../twig-bridge/Symfony/Bridge/Twig/.gitignore | 4 + .../twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md | 29 ++ .../Bridge/Twig/Extension/CodeExtension.php | 232 ++++++++++++ .../Bridge/Twig/Extension/FormExtension.php | 136 +++++++ .../Bridge/Twig/Extension/HttpKernelExtension.php | 88 +++++ .../Bridge/Twig/Extension/RoutingExtension.php | 100 ++++++ .../Bridge/Twig/Extension/SecurityExtension.php | 63 ++++ .../Bridge/Twig/Extension/TranslationExtension.php | 118 +++++++ .../Bridge/Twig/Extension/YamlExtension.php | 67 ++++ .../Symfony/Bridge/Twig/Form/TwigRenderer.php | 41 +++ .../Bridge/Twig/Form/TwigRendererEngine.php | 183 ++++++++++ .../Twig/Form/TwigRendererEngineInterface.php | 27 ++ .../Bridge/Twig/Form/TwigRendererInterface.php | 27 ++ .../twig-bridge/Symfony/Bridge/Twig/LICENSE | 19 + .../Symfony/Bridge/Twig/Node/FormEnctypeNode.php | 31 ++ .../Symfony/Bridge/Twig/Node/FormThemeNode.php | 40 +++ .../Symfony/Bridge/Twig/Node/RenderBlockNode.php | 42 +++ .../Bridge/Twig/Node/SearchAndRenderBlockNode.php | 106 ++++++ .../Bridge/Twig/Node/TransDefaultDomainNode.php | 33 ++ .../Symfony/Bridge/Twig/Node/TransNode.php | 119 +++++++ .../Symfony/Bridge/Twig/NodeVisitor/Scope.php | 135 +++++++ .../TranslationDefaultDomainNodeVisitor.php | 106 ++++++ .../Twig/NodeVisitor/TranslationNodeVisitor.php | 137 ++++++++ .../twig-bridge/Symfony/Bridge/Twig/README.md | 15 + .../Resources/views/Form/form_div_layout.html.twig | 390 +++++++++++++++++++++ .../views/Form/form_table_layout.html.twig | 52 +++ .../Twig/Tests/Extension/CodeExtensionTest.php | 69 ++++ .../Extension/Fixtures/StubFilesystemLoader.php | 30 ++ .../Tests/Extension/Fixtures/StubTranslator.php | 35 ++ .../Tests/Extension/FormExtensionDivLayoutTest.php | 209 +++++++++++ .../Extension/FormExtensionTableLayoutTest.php | 131 +++++++ .../Tests/Extension/HttpKernelExtensionTest.php | 68 ++++ .../Twig/Tests/Extension/RoutingExtensionTest.php | 60 ++++ .../Tests/Extension/TranslationExtensionTest.php | 151 ++++++++ .../Twig/Tests/Extension/child_label.html.twig | 3 + .../Twig/Tests/Extension/custom_widgets.html.twig | 16 + .../Twig/Tests/Extension/parent_label.html.twig | 3 + .../Bridge/Twig/Tests/Extension/theme.html.twig | 6 + .../Twig/Tests/Extension/theme_extends.html.twig | 8 + .../Twig/Tests/Extension/theme_use.html.twig | 8 + .../Bridge/Twig/Tests/Node/FormThemeTest.php | 85 +++++ .../Tests/Node/SearchAndRenderBlockNodeTest.php | 282 +++++++++++++++ .../Bridge/Twig/Tests/NodeVisitor/ScopeTest.php | 25 ++ .../TranslationDefaultDomainNodeVisitorTest.php | 83 +++++ .../NodeVisitor/TranslationNodeVisitorTest.php | 61 ++++ .../Twig/Tests/NodeVisitor/TwigNodeProvider.php | 77 ++++ .../Symfony/Bridge/Twig/Tests/TestCase.php | 22 ++ .../Tests/TokenParser/FormThemeTokenParserTest.php | 108 ++++++ .../Twig/Tests/Translation/TwigExtractorTest.php | 81 +++++ .../Twig/TokenParser/FormThemeTokenParser.php | 61 ++++ .../Twig/TokenParser/TransChoiceTokenParser.php | 89 +++++ .../TokenParser/TransDefaultDomainTokenParser.php | 48 +++ .../Bridge/Twig/TokenParser/TransTokenParser.php | 89 +++++ .../Bridge/Twig/Translation/TwigExtractor.php | 86 +++++ .../twig-bridge/Symfony/Bridge/Twig/TwigEngine.php | 126 +++++++ .../twig-bridge/Symfony/Bridge/Twig/composer.json | 50 +++ .../Symfony/Bridge/Twig/phpunit.xml.dist | 30 ++ 57 files changed, 4540 insertions(+) create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json create mode 100644 vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist (limited to 'vendor/symfony/twig-bridge') diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore new file mode 100644 index 00000000..44de97a3 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore @@ -0,0 +1,4 @@ +vendor/ +composer.lock +phpunit.xml + diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md new file mode 100644 index 00000000..ad22216e --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md @@ -0,0 +1,29 @@ +CHANGELOG +========= + +2.3.0 +----- + + * added helpers form(), form_start() and form_end() + * deprecated form_enctype() in favor of form_start() + +2.2.0 +----- + + * added a `controller` function to help generating controller references + * added a `render_esi` and a `render_hinclude` function + * [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed) + * added a `render` function to render a request + * The `app` global variable is now injected even when using the twig service directly. + * Added an optional parameter to the `path` and `url` function which allows to generate + relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file"). + +2.1.0 +----- + + * added global variables access in a form theme + * added TwigEngine + * added TwigExtractor + * added a csrf_token function + * added a way to specify a default domain for a Twig template (via the + 'trans_default_domain' tag) diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php new file mode 100644 index 00000000..a6202b24 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php @@ -0,0 +1,232 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +if (!defined('ENT_SUBSTITUTE')) { + define('ENT_SUBSTITUTE', 8); +} + +/** + * Twig extension relate to PHP code and used by the profiler and the default exception templates. + * + * @author Fabien Potencier + */ +class CodeExtension extends \Twig_Extension +{ + private $fileLinkFormat; + private $rootDir; + private $charset; + + /** + * Constructor. + * + * @param string $fileLinkFormat The format for links to source files + * @param string $rootDir The project root directory + * @param string $charset The charset + */ + public function __construct($fileLinkFormat, $rootDir, $charset) + { + $this->fileLinkFormat = empty($fileLinkFormat) ? ini_get('xdebug.file_link_format') : $fileLinkFormat; + $this->rootDir = str_replace('\\', '/', $rootDir).'/'; + $this->charset = $charset; + } + + /** + * {@inheritdoc} + */ + public function getFilters() + { + return array( + 'abbr_class' => new \Twig_Filter_Method($this, 'abbrClass', array('is_safe' => array('html'))), + 'abbr_method' => new \Twig_Filter_Method($this, 'abbrMethod', array('is_safe' => array('html'))), + 'format_args' => new \Twig_Filter_Method($this, 'formatArgs', array('is_safe' => array('html'))), + 'format_args_as_text' => new \Twig_Filter_Method($this, 'formatArgsAsText'), + 'file_excerpt' => new \Twig_Filter_Method($this, 'fileExcerpt', array('is_safe' => array('html'))), + 'format_file' => new \Twig_Filter_Method($this, 'formatFile', array('is_safe' => array('html'))), + 'format_file_from_text' => new \Twig_Filter_Method($this, 'formatFileFromText', array('is_safe' => array('html'))), + 'file_link' => new \Twig_Filter_Method($this, 'getFileLink', array('is_safe' => array('html'))), + ); + } + + public function abbrClass($class) + { + $parts = explode('\\', $class); + $short = array_pop($parts); + + return sprintf("%s", $class, $short); + } + + public function abbrMethod($method) + { + if (false !== strpos($method, '::')) { + list($class, $method) = explode('::', $method, 2); + $result = sprintf("%s::%s()", $this->abbrClass($class), $method); + } elseif ('Closure' === $method) { + $result = sprintf("%s", $method, $method); + } else { + $result = sprintf("%s()", $method, $method); + } + + return $result; + } + + /** + * Formats an array as a string. + * + * @param array $args The argument array + * + * @return string + */ + public function formatArgs($args) + { + $result = array(); + foreach ($args as $key => $item) { + if ('object' === $item[0]) { + $parts = explode('\\', $item[1]); + $short = array_pop($parts); + $formattedValue = sprintf("object(%s)", $item[1], $short); + } elseif ('array' === $item[0]) { + $formattedValue = sprintf("array(%s)", is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); + } elseif ('string' === $item[0]) { + $formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES, $this->charset)); + } elseif ('null' === $item[0]) { + $formattedValue = 'null'; + } elseif ('boolean' === $item[0]) { + $formattedValue = ''.strtolower(var_export($item[1], true)).''; + } elseif ('resource' === $item[0]) { + $formattedValue = 'resource'; + } else { + $formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES, $this->charset), true)); + } + + $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue); + } + + return implode(', ', $result); + } + + /** + * Formats an array as a string. + * + * @param array $args The argument array + * + * @return string + */ + public function formatArgsAsText($args) + { + return strip_tags($this->formatArgs($args)); + } + + /** + * Returns an excerpt of a code file around the given line number. + * + * @param string $file A file path + * @param int $line The selected line number + * + * @return string An HTML string + */ + public function fileExcerpt($file, $line) + { + if (is_readable($file)) { + $code = highlight_file($file, true); + // remove main code/span tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + $content = preg_split('#
#', $code); + + $lines = array(); + for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++) { + $lines[] = ''.self::fixCodeMarkup($content[$i - 1]).''; + } + + return '
    '.implode("\n", $lines).'
'; + } + } + + /** + * Formats a file path. + * + * @param string $file An absolute file path + * @param integer $line The line number + * @param string $text Use this text for the link rather than the file path + * + * @return string + */ + public function formatFile($file, $line, $text = null) + { + if (null === $text) { + $file = trim($file); + $text = $file; + if (0 === strpos($text, $this->rootDir)) { + $text = str_replace($this->rootDir, '', str_replace('\\', '/', $text)); + $text = sprintf('kernel.root_dir/%s', $this->rootDir, $text); + } + } + + $text = "$text at line $line"; + + if (false !== $link = $this->getFileLink($file, $line)) { + return sprintf('%s', htmlspecialchars($link, ENT_QUOTES | ENT_SUBSTITUTE, $this->charset), $text); + } + + return $text; + } + + /** + * Returns the link for a given file/line pair. + * + * @param string $file An absolute file path + * @param integer $line The line number + * + * @return string A link of false + */ + public function getFileLink($file, $line) + { + if ($this->fileLinkFormat && is_file($file)) { + return strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line)); + } + + return false; + } + + public function formatFileFromText($text) + { + $that = $this; + + return preg_replace_callback('/in ("|")?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) use ($that) { + return 'in '.$that->formatFile($match[2], $match[3]); + }, $text); + } + + public function getName() + { + return 'code'; + } + + protected static function fixCodeMarkup($line) + { + // ending tag from previous line + $opening = strpos($line, ''); + if (false !== $closing && (false === $opening || $closing < $opening)) { + $line = substr_replace($line, '', $closing, 7); + } + + // missing tag at the end of line + $opening = strpos($line, ''); + if (false !== $opening && (false === $closing || $closing > $opening)) { + $line .= ''; + } + + return $line; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php new file mode 100644 index 00000000..fbfa5243 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser; +use Symfony\Bridge\Twig\Form\TwigRendererInterface; +use Symfony\Component\Form\Extension\Core\View\ChoiceView; + +/** + * FormExtension extends Twig with form capabilities. + * + * @author Fabien Potencier + * @author Bernhard Schussek + */ +class FormExtension extends \Twig_Extension +{ + /** + * This property is public so that it can be accessed directly from compiled + * templates without having to call a getter, which slightly decreases performance. + * + * @var TwigRendererInterface + */ + public $renderer; + + public function __construct(TwigRendererInterface $renderer) + { + $this->renderer = $renderer; + } + + /** + * {@inheritdoc} + */ + public function initRuntime(\Twig_Environment $environment) + { + $this->renderer->setEnvironment($environment); + } + + /** + * {@inheritdoc} + */ + public function getTokenParsers() + { + return array( + // {% form_theme form "SomeBundle::widgets.twig" %} + new FormThemeTokenParser(), + ); + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return array( + 'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\FormEnctypeNode', array('is_safe' => array('html'))), + 'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))), + 'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))), + 'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))), + 'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))), + 'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))), + 'form' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))), + 'form_start' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))), + 'form_end' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))), + 'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'), + ); + } + + /** + * {@inheritdoc} + */ + public function getFilters() + { + return array( + 'humanize' => new \Twig_Filter_Method($this, 'renderer->humanize'), + ); + } + + /** + * {@inheritdoc} + */ + public function getTests() + { + return array( + 'selectedchoice' => new \Twig_Test_Method($this, 'isSelectedChoice'), + ); + } + + /** + * Returns whether a choice is selected for a given form value. + * + * Unfortunately Twig does not support an efficient way to execute the + * "is_selected" closure passed to the template by ChoiceType. It is faster + * to implement the logic here (around 65ms for a specific form). + * + * Directly implementing the logic here is also faster than doing so in + * ChoiceView (around 30ms). + * + * The worst option tested so far is to implement the logic in ChoiceView + * and access the ChoiceView method directly in the template. Doing so is + * around 220ms slower than doing the method call here in the filter. Twig + * seems to be much more efficient at executing filters than at executing + * methods of an object. + * + * @param ChoiceView $choice The choice to check. + * @param string|array $selectedValue The selected value to compare. + * + * @return Boolean Whether the choice is selected. + * + * @see ChoiceView::isSelected() + */ + public function isSelectedChoice(ChoiceView $choice, $selectedValue) + { + if (is_array($selectedValue)) { + return false !== array_search($choice->value, $selectedValue, true); + } + + return $choice->value === $selectedValue; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'form'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php new file mode 100644 index 00000000..a8377234 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\HttpKernel\Fragment\FragmentHandler; +use Symfony\Component\HttpKernel\Controller\ControllerReference; + +/** + * Provides integration with the HttpKernel component. + * + * @author Fabien Potencier + */ +class HttpKernelExtension extends \Twig_Extension +{ + private $handler; + + /** + * Constructor. + * + * @param FragmentHandler $handler A FragmentHandler instance + */ + public function __construct(FragmentHandler $handler) + { + $this->handler = $handler; + } + + public function getFunctions() + { + return array( + 'render' => new \Twig_Function_Method($this, 'renderFragment', array('is_safe' => array('html'))), + 'render_*' => new \Twig_Function_Method($this, 'renderFragmentStrategy', array('is_safe' => array('html'))), + 'controller' => new \Twig_Function_Method($this, 'controller'), + ); + } + + /** + * Renders a fragment. + * + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance + * @param array $options An array of options + * + * @return string The fragment content + * + * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render() + */ + public function renderFragment($uri, $options = array()) + { + $strategy = isset($options['strategy']) ? $options['strategy'] : 'inline'; + unset($options['strategy']); + + return $this->handler->render($uri, $strategy, $options); + } + + /** + * Renders a fragment. + * + * @param string $strategy A strategy name + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance + * @param array $options An array of options + * + * @return string The fragment content + * + * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render() + */ + public function renderFragmentStrategy($strategy, $uri, $options = array()) + { + return $this->handler->render($uri, $strategy, $options); + } + + public function controller($controller, $attributes = array(), $query = array()) + { + return new ControllerReference($controller, $attributes, $query); + } + + public function getName() + { + return 'http_kernel'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php new file mode 100644 index 00000000..8274abf3 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +/** + * Provides integration of the Routing component with Twig. + * + * @author Fabien Potencier + */ +class RoutingExtension extends \Twig_Extension +{ + private $generator; + + public function __construct(UrlGeneratorInterface $generator) + { + $this->generator = $generator; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return array( + 'url' => new \Twig_Function_Method($this, 'getUrl', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))), + 'path' => new \Twig_Function_Method($this, 'getPath', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))), + ); + } + + public function getPath($name, $parameters = array(), $relative = false) + { + return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH); + } + + public function getUrl($name, $parameters = array(), $schemeRelative = false) + { + return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL); + } + + /** + * Determines at compile time whether the generated URL will be safe and thus + * saving the unneeded automatic escaping for performance reasons. + * + * The URL generation process percent encodes non-alphanumeric characters. So there is no risk + * that malicious/invalid characters are part of the URL. The only character within an URL that + * must be escaped in html is the ampersand ("&") which separates query params. So we cannot mark + * the URL generation as always safe, but only when we are sure there won't be multiple query + * params. This is the case when there are none or only one constant parameter given. + * E.g. we know beforehand this will be safe: + * - path('route') + * - path('route', {'param': 'value'}) + * But the following may not: + * - path('route', var) + * - path('route', {'param': ['val1', 'val2'] }) // a sub-array + * - path('route', {'param1': 'value1', 'param2': 'value2'}) + * If param1 and param2 reference placeholder in the route, it would still be safe. But we don't know. + * + * @param \Twig_Node $argsNode The arguments of the path/url function + * + * @return array An array with the contexts the URL is safe + */ + public function isUrlGenerationSafe(\Twig_Node $argsNode) + { + // support named arguments + $paramsNode = $argsNode->hasNode('parameters') ? $argsNode->getNode('parameters') : ( + $argsNode->hasNode(1) ? $argsNode->getNode(1) : null + ); + + if (null === $paramsNode || $paramsNode instanceof \Twig_Node_Expression_Array && count($paramsNode) <= 2 && + (!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof \Twig_Node_Expression_Constant) + ) { + return array('html'); + } + + return array(); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'routing'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php new file mode 100644 index 00000000..c9f4466c --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\Security\Acl\Voter\FieldVote; +use Symfony\Component\Security\Core\SecurityContextInterface; + +/** + * SecurityExtension exposes security context features. + * + * @author Fabien Potencier + */ +class SecurityExtension extends \Twig_Extension +{ + private $context; + + public function __construct(SecurityContextInterface $context = null) + { + $this->context = $context; + } + + public function isGranted($role, $object = null, $field = null) + { + if (null === $this->context) { + return false; + } + + if (null !== $field) { + $object = new FieldVote($object, $field); + } + + return $this->context->isGranted($role, $object); + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return array( + 'is_granted' => new \Twig_Function_Method($this, 'isGranted'), + ); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'security'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php new file mode 100644 index 00000000..2ab3832d --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Bridge\Twig\TokenParser\TransTokenParser; +use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser; +use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser; +use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor; +use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor; + +/** + * Provides integration of the Translation component with Twig. + * + * @author Fabien Potencier + */ +class TranslationExtension extends \Twig_Extension +{ + private $translator; + private $translationNodeVisitor; + + public function __construct(TranslatorInterface $translator, \Twig_NodeVisitorInterface $translationNodeVisitor = null) + { + if (!$translationNodeVisitor) { + $translationNodeVisitor = new TranslationNodeVisitor(); + } + + $this->translator = $translator; + $this->translationNodeVisitor = $translationNodeVisitor; + } + + public function getTranslator() + { + return $this->translator; + } + + /** + * {@inheritdoc} + */ + public function getFilters() + { + return array( + 'trans' => new \Twig_Filter_Method($this, 'trans'), + 'transchoice' => new \Twig_Filter_Method($this, 'transchoice'), + ); + } + + /** + * Returns the token parser instance to add to the existing list. + * + * @return array An array of Twig_TokenParser instances + */ + public function getTokenParsers() + { + return array( + // {% trans %}Symfony is great!{% endtrans %} + new TransTokenParser(), + + // {% transchoice count %} + // {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples + // {% endtranschoice %} + new TransChoiceTokenParser(), + + // {% trans_default_domain "foobar" %} + new TransDefaultDomainTokenParser(), + ); + } + + /** + * {@inheritdoc} + */ + public function getNodeVisitors() + { + return array($this->translationNodeVisitor, new TranslationDefaultDomainNodeVisitor()); + } + + public function getTranslationNodeVisitor() + { + return $this->translationNodeVisitor; + } + + public function trans($message, array $arguments = array(), $domain = null, $locale = null) + { + if (null === $domain) { + $domain = 'messages'; + } + + return $this->translator->trans($message, $arguments, $domain, $locale); + } + + public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null) + { + if (null === $domain) { + $domain = 'messages'; + } + + return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'translator'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php new file mode 100644 index 00000000..f88829ee --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\Yaml\Dumper as YamlDumper; + +/** + * Provides integration of the Yaml component with Twig. + * + * @author Fabien Potencier + */ +class YamlExtension extends \Twig_Extension +{ + /** + * {@inheritdoc} + */ + public function getFilters() + { + return array( + 'yaml_encode' => new \Twig_Filter_Method($this, 'encode'), + 'yaml_dump' => new \Twig_Filter_Method($this, 'dump'), + ); + } + + public function encode($input, $inline = 0, $dumpObjects = false) + { + static $dumper; + + if (null === $dumper) { + $dumper = new YamlDumper(); + } + + return $dumper->dump($input, $inline, false, $dumpObjects); + } + + public function dump($value, $inline = 0, $dumpObjects = false) + { + if (is_resource($value)) { + return '%Resource%'; + } + + if (is_array($value) || is_object($value)) { + return '%'.gettype($value).'% '.$this->encode($value, $inline, $dumpObjects); + } + + return $this->encode($value, $inline, $dumpObjects); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'yaml'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php new file mode 100644 index 00000000..72798d10 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Form; + +use Symfony\Component\Form\FormRenderer; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; + +/** + * @author Bernhard Schussek + */ +class TwigRenderer extends FormRenderer implements TwigRendererInterface +{ + /** + * @var TwigRendererEngineInterface + */ + private $engine; + + public function __construct(TwigRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null) + { + parent::__construct($engine, $csrfProvider); + + $this->engine = $engine; + } + + /** + * {@inheritdoc} + */ + public function setEnvironment(\Twig_Environment $environment) + { + $this->engine->setEnvironment($environment); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php new file mode 100644 index 00000000..05beb315 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php @@ -0,0 +1,183 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Form; + +use Symfony\Component\Form\AbstractRendererEngine; +use Symfony\Component\Form\FormView; + +/** + * @author Bernhard Schussek + */ +class TwigRendererEngine extends AbstractRendererEngine implements TwigRendererEngineInterface +{ + /** + * @var \Twig_Environment + */ + private $environment; + + /** + * @var \Twig_Template + */ + private $template; + + /** + * {@inheritdoc} + */ + public function setEnvironment(\Twig_Environment $environment) + { + $this->environment = $environment; + } + + /** + * {@inheritdoc} + */ + public function renderBlock(FormView $view, $resource, $blockName, array $variables = array()) + { + $cacheKey = $view->vars[self::CACHE_KEY_VAR]; + + $context = $this->environment->mergeGlobals($variables); + + ob_start(); + + // By contract,This method can only be called after getting the resource + // (which is passed to the method). Getting a resource for the first time + // (with an empty cache) is guaranteed to invoke loadResourcesFromTheme(), + // where the property $template is initialized. + + // We do not call renderBlock here to avoid too many nested level calls + // (XDebug limits the level to 100 by default) + $this->template->displayBlock($blockName, $context, $this->resources[$cacheKey]); + + return ob_get_clean(); + } + + /** + * Loads the cache with the resource for a given block name. + * + * This implementation eagerly loads all blocks of the themes assigned to the given view + * and all of its ancestors views. This is necessary, because Twig receives the + * list of blocks later. At that point, all blocks must already be loaded, for the + * case that the function "block()" is used in the Twig template. + * + * @see getResourceForBlock() + * + * @param string $cacheKey The cache key of the form view. + * @param FormView $view The form view for finding the applying themes. + * @param string $blockName The name of the block to load. + * + * @return Boolean True if the resource could be loaded, false otherwise. + */ + protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName) + { + // The caller guarantees that $this->resources[$cacheKey][$block] is + // not set, but it doesn't have to check whether $this->resources[$cacheKey] + // is set. If $this->resources[$cacheKey] is set, all themes for this + // $cacheKey are already loaded (due to the eager population, see doc comment). + if (isset($this->resources[$cacheKey])) { + // As said in the previous, the caller guarantees that + // $this->resources[$cacheKey][$block] is not set. Since the themes are + // already loaded, it can only be a non-existing block. + $this->resources[$cacheKey][$blockName] = false; + + return false; + } + + // Recursively try to find the block in the themes assigned to $view, + // then of its parent view, then of the parent view of the parent and so on. + // When the root view is reached in this recursion, also the default + // themes are taken into account. + + // Check each theme whether it contains the searched block + if (isset($this->themes[$cacheKey])) { + for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) { + $this->loadResourcesFromTheme($cacheKey, $this->themes[$cacheKey][$i]); + // CONTINUE LOADING (see doc comment) + } + } + + // Check the default themes once we reach the root view without success + if (!$view->parent) { + for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) { + $this->loadResourcesFromTheme($cacheKey, $this->defaultThemes[$i]); + // CONTINUE LOADING (see doc comment) + } + } + + // Proceed with the themes of the parent view + if ($view->parent) { + $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR]; + + if (!isset($this->resources[$parentCacheKey])) { + $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName); + } + + // EAGER CACHE POPULATION (see doc comment) + foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) { + if (!isset($this->resources[$cacheKey][$nestedBlockName])) { + $this->resources[$cacheKey][$nestedBlockName] = $resource; + } + } + } + + // Even though we loaded the themes, it can happen that none of them + // contains the searched block + if (!isset($this->resources[$cacheKey][$blockName])) { + // Cache that we didn't find anything to speed up further accesses + $this->resources[$cacheKey][$blockName] = false; + } + + return false !== $this->resources[$cacheKey][$blockName]; + } + + /** + * Loads the resources for all blocks in a theme. + * + * @param string $cacheKey The cache key for storing the resource. + * @param mixed $theme The theme to load the block from. This parameter + * is passed by reference, because it might be necessary + * to initialize the theme first. Any changes made to + * this variable will be kept and be available upon + * further calls to this method using the same theme. + */ + protected function loadResourcesFromTheme($cacheKey, &$theme) + { + if (!$theme instanceof \Twig_Template) { + /* @var \Twig_Template $theme */ + $theme = $this->environment->loadTemplate($theme); + } + + if (null === $this->template) { + // Store the first \Twig_Template instance that we find so that + // we can call displayBlock() later on. It doesn't matter *which* + // template we use for that, since we pass the used blocks manually + // anyway. + $this->template = $theme; + } + + // Use a separate variable for the inheritance traversal, because + // theme is a reference and we don't want to change it. + $currentTheme = $theme; + + // The do loop takes care of template inheritance. + // Add blocks from all templates in the inheritance tree, but avoid + // overriding blocks already set. + do { + foreach ($currentTheme->getBlocks() as $block => $blockData) { + if (!isset($this->resources[$cacheKey][$block])) { + // The resource given back is the key to the bucket that + // contains this block. + $this->resources[$cacheKey][$block] = $blockData; + } + } + } while (false !== $currentTheme = $currentTheme->getParent(array())); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php new file mode 100644 index 00000000..ef764a24 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Form; + +use Symfony\Component\Form\FormRendererEngineInterface; + +/** + * @author Bernhard Schussek + */ +interface TwigRendererEngineInterface extends FormRendererEngineInterface +{ + /** + * Sets Twig's environment. + * + * @param \Twig_Environment $environment + */ + public function setEnvironment(\Twig_Environment $environment); +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php new file mode 100644 index 00000000..4682f520 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Form; + +use Symfony\Component\Form\FormRendererInterface; + +/** + * @author Bernhard Schussek + */ +interface TwigRendererInterface extends FormRendererInterface +{ + /** + * Sets Twig's environment. + * + * @param \Twig_Environment $environment + */ + public function setEnvironment(\Twig_Environment $environment); +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE new file mode 100644 index 00000000..88a57f8d --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2013 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php new file mode 100644 index 00000000..93bce1b9 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Bernhard Schussek + * + * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use + * the helper "form_start()" instead. + */ +class FormEnctypeNode extends SearchAndRenderBlockNode +{ + public function compile(\Twig_Compiler $compiler) + { + parent::compile($compiler); + + $compiler->raw(";\n"); + + // Uncomment this as soon as the deprecation note should be shown + // $compiler->write('trigger_error(\'The helper form_enctype(form) is deprecated since version 2.3 and will be removed in 3.0. Use form_start(form) instead.\', E_USER_DEPRECATED)'); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php new file mode 100644 index 00000000..329ab86f --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Fabien Potencier + */ +class FormThemeNode extends \Twig_Node +{ + public function __construct(\Twig_NodeInterface $form, \Twig_NodeInterface $resources, $lineno, $tag = null) + { + parent::__construct(array('form' => $form, 'resources' => $resources), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param \Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(\Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('$this->env->getExtension(\'form\')->renderer->setTheme(') + ->subcompile($this->getNode('form')) + ->raw(', ') + ->subcompile($this->getNode('resources')) + ->raw(");\n"); + ; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php new file mode 100644 index 00000000..822a2727 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * Compiles a call to {@link FormRendererInterface::renderBlock()}. + * + * The function name is used as block name. For example, if the function name + * is "foo", the block "foo" will be rendered. + * + * @author Bernhard Schussek + */ +class RenderBlockNode extends \Twig_Node_Expression_Function +{ + public function compile(\Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + $arguments = iterator_to_array($this->getNode('arguments')); + $compiler->write('$this->env->getExtension(\'form\')->renderer->renderBlock('); + + if (isset($arguments[0])) { + $compiler->subcompile($arguments[0]); + $compiler->raw(', \'' . $this->getAttribute('name') . '\''); + + if (isset($arguments[1])) { + $compiler->raw(', '); + $compiler->subcompile($arguments[1]); + } + } + + $compiler->raw(')'); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php new file mode 100644 index 00000000..630e2638 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Bernhard Schussek + */ +class SearchAndRenderBlockNode extends \Twig_Node_Expression_Function +{ + public function compile(\Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + $compiler->raw('$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock('); + + preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches); + + $label = null; + $arguments = iterator_to_array($this->getNode('arguments')); + $blockNameSuffix = $matches[1]; + + if (isset($arguments[0])) { + $compiler->subcompile($arguments[0]); + $compiler->raw(', \''.$blockNameSuffix.'\''); + + if (isset($arguments[1])) { + if ('label' === $blockNameSuffix) { + // The "label" function expects the label in the second and + // the variables in the third argument + $label = $arguments[1]; + $variables = isset($arguments[2]) ? $arguments[2] : null; + $lineno = $label->getLine(); + + if ($label instanceof \Twig_Node_Expression_Constant) { + // If the label argument is given as a constant, we can either + // strip it away if it is empty, or integrate it into the array + // of variables at compile time. + $labelIsExpression = false; + + // Only insert the label into the array if it is not empty + if (!twig_test_empty($label->getAttribute('value'))) { + $originalVariables = $variables; + $variables = new \Twig_Node_Expression_Array(array(), $lineno); + $labelKey = new \Twig_Node_Expression_Constant('label', $lineno); + + if (null !== $originalVariables) { + foreach ($originalVariables->getKeyValuePairs() as $pair) { + // Don't copy the original label attribute over if it exists + if ((string) $labelKey !== (string) $pair['key']) { + $variables->addElement($pair['value'], $pair['key']); + } + } + } + + // Insert the label argument into the array + $variables->addElement($label, $labelKey); + } + } else { + // The label argument is not a constant, but some kind of + // expression. This expression needs to be evaluated at runtime. + // Depending on the result (whether it is null or not), the + // label in the arguments should take precedence over the label + // in the attributes or not. + $labelIsExpression = true; + } + } else { + // All other functions than "label" expect the variables + // in the second argument + $label = null; + $variables = $arguments[1]; + $labelIsExpression = false; + } + + if (null !== $variables || $labelIsExpression) { + $compiler->raw(', '); + + if (null !== $variables) { + $compiler->subcompile($variables); + } + + if ($labelIsExpression) { + if (null !== $variables) { + $compiler->raw(' + '); + } + + // Check at runtime whether the label is empty. + // If not, add it to the array at runtime. + $compiler->raw('(twig_test_empty($_label_ = '); + $compiler->subcompile($label); + $compiler->raw(') ? array() : array("label" => $_label_))'); + } + } + } + } + + $compiler->raw(")"); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php new file mode 100644 index 00000000..adee71ff --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Fabien Potencier + */ +class TransDefaultDomainNode extends \Twig_Node +{ + public function __construct(\Twig_Node_Expression $expr, $lineno = 0, $tag = null) + { + parent::__construct(array('expr' => $expr), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param \Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(\Twig_Compiler $compiler) + { + // noop as this node is just a marker for TranslationDefaultDomainNodeVisitor + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php new file mode 100644 index 00000000..a68c101a --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Fabien Potencier + */ +class TransNode extends \Twig_Node +{ + public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain = null, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, \Twig_Node_Expression $locale = null, $lineno = 0, $tag = null) + { + parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars, 'locale' => $locale), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param \Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(\Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + $vars = $this->getNode('vars'); + $defaults = new \Twig_Node_Expression_Array(array(), -1); + if ($vars instanceof \Twig_Node_Expression_Array) { + $defaults = $this->getNode('vars'); + $vars = null; + } + list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults); + + $method = null === $this->getNode('count') ? 'trans' : 'transChoice'; + + $compiler + ->write('echo $this->env->getExtension(\'translator\')->getTranslator()->'.$method.'(') + ->subcompile($msg) + ; + + $compiler->raw(', '); + + if (null !== $this->getNode('count')) { + $compiler + ->subcompile($this->getNode('count')) + ->raw(', ') + ; + } + + if (null !== $vars) { + $compiler + ->raw('array_merge(') + ->subcompile($defaults) + ->raw(', ') + ->subcompile($this->getNode('vars')) + ->raw(')') + ; + } else { + $compiler->subcompile($defaults); + } + + $compiler->raw(', '); + + if (null === $this->getNode('domain')) { + $compiler->repr('messages'); + } else { + $compiler->subcompile($this->getNode('domain')); + } + + if (null !== $this->getNode('locale')) { + $compiler + ->raw(', ') + ->subcompile($this->getNode('locale')) + ; + } + $compiler->raw(");\n"); + } + + protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars) + { + if ($body instanceof \Twig_Node_Expression_Constant) { + $msg = $body->getAttribute('value'); + } elseif ($body instanceof \Twig_Node_Text) { + $msg = $body->getAttribute('data'); + } else { + return array($body, $vars); + } + + preg_match_all('/(?=')) { + foreach ($matches[1] as $var) { + $key = new \Twig_Node_Expression_Constant('%'.$var.'%', $body->getLine()); + if (!$vars->hasElement($key)) { + $vars->addElement(new \Twig_Node_Expression_Name($var, $body->getLine()), $key); + } + } + } else { + $current = array(); + foreach ($vars as $name => $var) { + $current[$name] = true; + } + foreach ($matches[1] as $var) { + if (!isset($current['%'.$var.'%'])) { + $vars->setNode('%'.$var.'%', new \Twig_Node_Expression_Name($var, $body->getLine())); + } + } + } + + return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php new file mode 100644 index 00000000..ce27b6a6 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\NodeVisitor; + +/** + * @author Jean-François Simon + */ +class Scope +{ + /** + * @var Scope|null + */ + private $parent; + + /** + * @var Scope[] + */ + private $children; + + /** + * @var array + */ + private $data; + + /** + * @var boolean + */ + private $left; + + /** + * @param Scope $parent + */ + public function __construct(Scope $parent = null) + { + $this->parent = $parent; + $this->left = false; + $this->data = array(); + } + + /** + * Opens a new child scope. + * + * @return Scope + */ + public function enter() + { + $child = new self($this); + $this->children[] = $child; + + return $child; + } + + /** + * Closes current scope and returns parent one. + * + * @return Scope|null + */ + public function leave() + { + $this->left = true; + + return $this->parent; + } + + /** + * Stores data into current scope. + * + * @param string $key + * @param mixed $value + * + * @throws \LogicException + * + * @return Scope Current scope + */ + public function set($key, $value) + { + if ($this->left) { + throw new \LogicException('Left scope is not mutable.'); + } + + $this->data[$key] = $value; + + return $this; + } + + /** + * Tests if a data is visible from current scope. + * + * @param string $key + * + * @return boolean + */ + public function has($key) + { + if (array_key_exists($key, $this->data)) { + return true; + } + + if (null === $this->parent) { + return false; + } + + return $this->parent->has($key); + } + + /** + * Returns data visible from current scope. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public function get($key, $default = null) + { + if (array_key_exists($key, $this->data)) { + return $this->data[$key]; + } + + if (null === $this->parent) { + return $default; + } + + return $this->parent->get($key, $default); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php new file mode 100644 index 00000000..8e7e7f48 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\NodeVisitor; + +use Symfony\Bridge\Twig\Node\TransNode; +use Symfony\Bridge\Twig\Node\TransDefaultDomainNode; + +/** + * TranslationDefaultDomainNodeVisitor. + * + * @author Fabien Potencier + */ +class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface +{ + /** + * @var Scope + */ + private $scope; + + /** + * Constructor. + */ + public function __construct() + { + $this->scope = new Scope(); + } + + /** + * {@inheritdoc} + */ + public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) { + $this->scope = $this->scope->enter(); + } + + if ($node instanceof TransDefaultDomainNode) { + if ($node->getNode('expr') instanceof \Twig_Node_Expression_Constant) { + $this->scope->set('domain', $node->getNode('expr')); + + return $node; + } else { + $var = $env->getParser()->getVarName(); + $name = new \Twig_Node_Expression_AssignName($var, $node->getLine()); + $this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getLine())); + + return new \Twig_Node_Set(false, new \Twig_Node(array($name)), new \Twig_Node(array($node->getNode('expr'))), $node->getLine()); + } + } + + if (!$this->scope->has('domain')) { + return $node; + } + + if ($node instanceof \Twig_Node_Expression_Filter && in_array($node->getNode('filter')->getAttribute('value'), array('trans', 'transchoice'))) { + $ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2; + $arguments = $node->getNode('arguments'); + if (!$arguments->hasNode($ind)) { + if (!$arguments->hasNode($ind - 1)) { + $arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine())); + } + + $arguments->setNode($ind, $this->scope->get('domain')); + } + } elseif ($node instanceof TransNode) { + if (null === $node->getNode('domain')) { + $node->setNode('domain', $this->scope->get('domain')); + } + } + + return $node; + } + + /** + * {@inheritdoc} + */ + public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + if ($node instanceof TransDefaultDomainNode) { + return false; + } + + if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) { + $this->scope = $this->scope->leave(); + } + + return $node; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return -10; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php new file mode 100644 index 00000000..592c2506 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\NodeVisitor; + +use Symfony\Bridge\Twig\Node\TransNode; + +/** + * TranslationNodeVisitor extracts translation messages. + * + * @author Fabien Potencier + */ +class TranslationNodeVisitor implements \Twig_NodeVisitorInterface +{ + const UNDEFINED_DOMAIN = '_undefined'; + + private $enabled = false; + private $messages = array(); + + public function enable() + { + $this->enabled = true; + $this->messages = array(); + } + + public function disable() + { + $this->enabled = false; + $this->messages = array(); + } + + public function getMessages() + { + return $this->messages; + } + + /** + * {@inheritdoc} + */ + public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + if (!$this->enabled) { + return $node; + } + + if ( + $node instanceof \Twig_Node_Expression_Filter && + 'trans' === $node->getNode('filter')->getAttribute('value') && + $node->getNode('node') instanceof \Twig_Node_Expression_Constant + ) { + // extract constant nodes with a trans filter + $this->messages[] = array( + $node->getNode('node')->getAttribute('value'), + $this->getReadDomainFromArguments($node->getNode('arguments'), 1), + ); + } elseif ( + $node instanceof \Twig_Node_Expression_Filter && + 'transchoice' === $node->getNode('filter')->getAttribute('value') && + $node->getNode('node') instanceof \Twig_Node_Expression_Constant + ) { + // extract constant nodes with a trans filter + $this->messages[] = array( + $node->getNode('node')->getAttribute('value'), + $this->getReadDomainFromArguments($node->getNode('arguments'), 2), + ); + } elseif ($node instanceof TransNode) { + // extract trans nodes + $this->messages[] = array( + $node->getNode('body')->getAttribute('data'), + $this->getReadDomainFromNode($node->getNode('domain')), + ); + } + + return $node; + } + + /** + * {@inheritdoc} + */ + public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + return $node; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } + + /** + * @param \Twig_Node $arguments + * @param int $index + * + * @return string|null + */ + private function getReadDomainFromArguments(\Twig_Node $arguments, $index) + { + if ($arguments->hasNode('domain')) { + $argument = $arguments->getNode('domain'); + } elseif ($arguments->hasNode($index)) { + $argument = $arguments->getNode($index); + } else { + return null; + } + + return $this->getReadDomainFromNode($argument); + } + + /** + * @param \Twig_Node $node + * + * @return string|null + */ + private function getReadDomainFromNode(\Twig_Node $node = null) + { + if (null === $node) { + return null; + } + + if ($node instanceof \Twig_Node_Expression_Constant) { + return $node->getAttribute('value'); + } + + return self::UNDEFINED_DOMAIN; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md new file mode 100644 index 00000000..e5663236 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md @@ -0,0 +1,15 @@ +Twig Bridge +=========== + +Provides integration for [Twig](http://twig.sensiolabs.org/) with various +Symfony2 components. + +Resources +--------- + +If you want to run the unit tests, install dev dependencies before +running PHPUnit: + + $ cd path/to/Symfony/Bridge/Twig/ + $ composer.phar install --dev + $ phpunit diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig new file mode 100644 index 00000000..453c29c6 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -0,0 +1,390 @@ +{# Widgets #} + +{% block form_widget %} +{% spaceless %} + {% if compound %} + {{ block('form_widget_compound') }} + {% else %} + {{ block('form_widget_simple') }} + {% endif %} +{% endspaceless %} +{% endblock form_widget %} + +{% block form_widget_simple %} +{% spaceless %} + {% set type = type|default('text') %} + +{% endspaceless %} +{% endblock form_widget_simple %} + +{% block form_widget_compound %} +{% spaceless %} +
+ {% if form.parent is empty %} + {{ form_errors(form) }} + {% endif %} + {{ block('form_rows') }} + {{ form_rest(form) }} +
+{% endspaceless %} +{% endblock form_widget_compound %} + +{% block collection_widget %} +{% spaceless %} + {% if prototype is defined %} + {% set attr = attr|merge({'data-prototype': form_row(prototype) }) %} + {% endif %} + {{ block('form_widget') }} +{% endspaceless %} +{% endblock collection_widget %} + +{% block textarea_widget %} +{% spaceless %} + +{% endspaceless %} +{% endblock textarea_widget %} + +{% block choice_widget %} +{% spaceless %} + {% if expanded %} + {{ block('choice_widget_expanded') }} + {% else %} + {{ block('choice_widget_collapsed') }} + {% endif %} +{% endspaceless %} +{% endblock choice_widget %} + +{% block choice_widget_expanded %} +{% spaceless %} +
+ {% for child in form %} + {{ form_widget(child) }} + {{ form_label(child) }} + {% endfor %} +
+{% endspaceless %} +{% endblock choice_widget_expanded %} + +{% block choice_widget_collapsed %} +{% spaceless %} + +{% endspaceless %} +{% endblock choice_widget_collapsed %} + +{% block choice_widget_options %} +{% spaceless %} + {% for group_label, choice in options %} + {% if choice is iterable %} + + {% set options = choice %} + {{ block('choice_widget_options') }} + + {% else %} + + {% endif %} + {% endfor %} +{% endspaceless %} +{% endblock choice_widget_options %} + +{% block checkbox_widget %} +{% spaceless %} + +{% endspaceless %} +{% endblock checkbox_widget %} + +{% block radio_widget %} +{% spaceless %} + +{% endspaceless %} +{% endblock radio_widget %} + +{% block datetime_widget %} +{% spaceless %} + {% if widget == 'single_text' %} + {{ block('form_widget_simple') }} + {% else %} +
+ {{ form_errors(form.date) }} + {{ form_errors(form.time) }} + {{ form_widget(form.date) }} + {{ form_widget(form.time) }} +
+ {% endif %} +{% endspaceless %} +{% endblock datetime_widget %} + +{% block date_widget %} +{% spaceless %} + {% if widget == 'single_text' %} + {{ block('form_widget_simple') }} + {% else %} +
+ {{ date_pattern|replace({ + '{{ year }}': form_widget(form.year), + '{{ month }}': form_widget(form.month), + '{{ day }}': form_widget(form.day), + })|raw }} +
+ {% endif %} +{% endspaceless %} +{% endblock date_widget %} + +{% block time_widget %} +{% spaceless %} + {% if widget == 'single_text' %} + {{ block('form_widget_simple') }} + {% else %} + {% set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} %} +
+ {{ form_widget(form.hour, vars) }}{% if with_minutes %}:{{ form_widget(form.minute, vars) }}{% endif %}{% if with_seconds %}:{{ form_widget(form.second, vars) }}{% endif %} +
+ {% endif %} +{% endspaceless %} +{% endblock time_widget %} + +{% block number_widget %} +{% spaceless %} + {# type="number" doesn't work with floats #} + {% set type = type|default('text') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock number_widget %} + +{% block integer_widget %} +{% spaceless %} + {% set type = type|default('number') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock integer_widget %} + +{% block money_widget %} +{% spaceless %} + {{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }} +{% endspaceless %} +{% endblock money_widget %} + +{% block url_widget %} +{% spaceless %} + {% set type = type|default('url') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock url_widget %} + +{% block search_widget %} +{% spaceless %} + {% set type = type|default('search') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock search_widget %} + +{% block percent_widget %} +{% spaceless %} + {% set type = type|default('text') %} + {{ block('form_widget_simple') }} % +{% endspaceless %} +{% endblock percent_widget %} + +{% block password_widget %} +{% spaceless %} + {% set type = type|default('password') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock password_widget %} + +{% block hidden_widget %} +{% spaceless %} + {% set type = type|default('hidden') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock hidden_widget %} + +{% block email_widget %} +{% spaceless %} + {% set type = type|default('email') %} + {{ block('form_widget_simple') }} +{% endspaceless %} +{% endblock email_widget %} + +{% block button_widget %} +{% spaceless %} + {% if label is empty %} + {% set label = name|humanize %} + {% endif %} + +{% endspaceless %} +{% endblock button_widget %} + +{% block submit_widget %} +{% spaceless %} + {% set type = type|default('submit') %} + {{ block('button_widget') }} +{% endspaceless %} +{% endblock submit_widget %} + +{% block reset_widget %} +{% spaceless %} + {% set type = type|default('reset') %} + {{ block('button_widget') }} +{% endspaceless %} +{% endblock reset_widget %} + +{# Labels #} + +{% block form_label %} +{% spaceless %} + {% if label is not sameas(false) %} + {% if not compound %} + {% set label_attr = label_attr|merge({'for': id}) %} + {% endif %} + {% if required %} + {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %} + {% endif %} + {% if label is empty %} + {% set label = name|humanize %} + {% endif %} + {{ label|trans({}, translation_domain) }} + {% endif %} +{% endspaceless %} +{% endblock form_label %} + +{% block button_label %}{% endblock %} + +{# Rows #} + +{% block repeated_row %} +{% spaceless %} + {# + No need to render the errors here, as all errors are mapped + to the first child (see RepeatedTypeValidatorExtension). + #} + {{ block('form_rows') }} +{% endspaceless %} +{% endblock repeated_row %} + +{% block form_row %} +{% spaceless %} +
+ {{ form_label(form) }} + {{ form_errors(form) }} + {{ form_widget(form) }} +
+{% endspaceless %} +{% endblock form_row %} + +{% block button_row %} +{% spaceless %} +
+ {{ form_widget(form) }} +
+{% endspaceless %} +{% endblock button_row %} + +{% block hidden_row %} + {{ form_widget(form) }} +{% endblock hidden_row %} + +{# Misc #} + +{% block form %} +{% spaceless %} + {{ form_start(form) }} + {{ form_widget(form) }} + {{ form_end(form) }} +{% endspaceless %} +{% endblock form %} + +{% block form_start %} +{% spaceless %} + {% set method = method|upper %} + {% if method in ["GET", "POST"] %} + {% set form_method = method %} + {% else %} + {% set form_method = "POST" %} + {% endif %} +
+ {% if form_method != method %} + + {% endif %} +{% endspaceless %} +{% endblock form_start %} + +{% block form_end %} +{% spaceless %} + {% if not render_rest is defined or render_rest %} + {{ form_rest(form) }} + {% endif %} +
+{% endspaceless %} +{% endblock form_end %} + +{% block form_enctype %} +{% spaceless %} + {% if multipart %}enctype="multipart/form-data"{% endif %} +{% endspaceless %} +{% endblock form_enctype %} + +{% block form_errors %} +{% spaceless %} + {% if errors|length > 0 %} +
    + {% for error in errors %} +
  • {{ error.message }}
  • + {% endfor %} +
+ {% endif %} +{% endspaceless %} +{% endblock form_errors %} + +{% block form_rest %} +{% spaceless %} + {% for child in form %} + {% if not child.rendered %} + {{ form_row(child) }} + {% endif %} + {% endfor %} +{% endspaceless %} +{% endblock form_rest %} + +{# Support #} + +{% block form_rows %} +{% spaceless %} + {% for child in form %} + {{ form_row(child) }} + {% endfor %} +{% endspaceless %} +{% endblock form_rows %} + +{% block widget_attributes %} +{% spaceless %} + id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %} + {% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %} +{% endspaceless %} +{% endblock widget_attributes %} + +{% block widget_container_attributes %} +{% spaceless %} + {% if id is not empty %}id="{{ id }}" {% endif %} + {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %} +{% endspaceless %} +{% endblock widget_container_attributes %} + +{% block button_attributes %} +{% spaceless %} + id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %} + {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %} +{% endspaceless %} +{% endblock button_attributes %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig new file mode 100644 index 00000000..aed4f8d7 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig @@ -0,0 +1,52 @@ +{% use "form_div_layout.html.twig" %} + +{% block form_row %} +{% spaceless %} + + + {{ form_label(form) }} + + + {{ form_errors(form) }} + {{ form_widget(form) }} + + +{% endspaceless %} +{% endblock form_row %} + +{% block button_row %} +{% spaceless %} + + + + {{ form_widget(form) }} + + +{% endspaceless %} +{% endblock button_row %} + +{% block hidden_row %} +{% spaceless %} + + + {{ form_widget(form) }} + + +{% endspaceless %} +{% endblock hidden_row %} + +{% block form_widget_compound %} +{% spaceless %} + + {% if form.parent is empty and errors|length > 0 %} + + + + {% endif %} + {{ block('form_rows') }} + {{ form_rest(form) }} +
+ {{ form_errors(form) }} +
+{% endspaceless %} +{% endblock form_widget_compound %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php new file mode 100644 index 00000000..d9356514 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\CodeExtension; + +class CodeExtensionTest extends \PHPUnit_Framework_TestCase +{ + protected $helper; + + public function testFormatFile() + { + $expected = sprintf('%s at line 25', __FILE__, __FILE__); + $this->assertEquals($expected, $this->getExtension()->formatFile(__FILE__, 25)); + } + + /** + * @dataProvider getClassNameProvider + */ + public function testGettingClassAbbreviation($class, $abbr) + { + $this->assertEquals($this->getExtension()->abbrClass($class), $abbr); + } + + /** + * @dataProvider getMethodNameProvider + */ + public function testGettingMethodAbbreviation($method, $abbr) + { + $this->assertEquals($this->getExtension()->abbrMethod($method), $abbr); + } + + public function getClassNameProvider() + { + return array( + array('F\Q\N\Foo', 'Foo'), + array('Bare', 'Bare'), + ); + } + + public function getMethodNameProvider() + { + return array( + array('F\Q\N\Foo::Method', 'Foo::Method()'), + array('Bare::Method', 'Bare::Method()'), + array('Closure', 'Closure'), + array('Method', 'Method()') + ); + } + + public function testGetName() + { + $this->assertEquals('code', $this->getExtension()->getName()); + } + + protected function getExtension() + { + return new CodeExtension('txmt://open?url=file://%f&line=%l', '/root', 'UTF-8'); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php new file mode 100644 index 00000000..36c61cd6 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures; + +// Preventing autoloader throwing E_FATAL when Twig is now available +if (!class_exists('Twig_Environment')) { + class StubFilesystemLoader + { + } +} else { + class StubFilesystemLoader extends \Twig_Loader_Filesystem + { + protected function findTemplate($name) + { + // strip away bundle name + $parts = explode(':', $name); + + return parent::findTemplate(end($parts)); + } + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php new file mode 100644 index 00000000..b7d011b5 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures; + +use Symfony\Component\Translation\TranslatorInterface; + +class StubTranslator implements TranslatorInterface +{ + public function trans($id, array $parameters = array(), $domain = null, $locale = null) + { + return '[trans]'.$id.'[/trans]'; + } + + public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) + { + return '[trans]'.$id.'[/trans]'; + } + + public function setLocale($locale) + { + } + + public function getLocale() + { + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php new file mode 100644 index 00000000..c5c134bc --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -0,0 +1,209 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\FormExtension; +use Symfony\Bridge\Twig\Form\TwigRenderer; +use Symfony\Bridge\Twig\Form\TwigRendererEngine; +use Symfony\Bridge\Twig\Extension\TranslationExtension; +use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator; +use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader; +use Symfony\Component\Form\FormView; +use Symfony\Component\Form\Extension\Core\View\ChoiceView; +use Symfony\Component\Form\Tests\AbstractDivLayoutTest; + +class FormExtensionDivLayoutTest extends AbstractDivLayoutTest +{ + /** + * @var FormExtension + */ + protected $extension; + + protected function setUp() + { + if (!class_exists('Symfony\Component\Locale\Locale')) { + $this->markTestSkipped('The "Locale" component is not available'); + } + + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + + if (!class_exists('Symfony\Component\Form\Form')) { + $this->markTestSkipped('The "Form" component is not available'); + } + + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + + parent::setUp(); + + $rendererEngine = new TwigRendererEngine(array( + 'form_div_layout.html.twig', + 'custom_widgets.html.twig', + )); + $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface')); + + $this->extension = new FormExtension($renderer); + + $loader = new StubFilesystemLoader(array( + __DIR__.'/../../Resources/views/Form', + __DIR__, + )); + + $environment = new \Twig_Environment($loader, array('strict_variables' => true)); + $environment->addExtension(new TranslationExtension(new StubTranslator())); + $environment->addGlobal('global', ''); + $environment->addExtension($this->extension); + + $this->extension->initRuntime($environment); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->extension = null; + } + + public function testThemeBlockInheritanceUsingUse() + { + $view = $this->factory + ->createNamed('name', 'email') + ->createView() + ; + + $this->setTheme($view, array('theme_use.html.twig')); + + $this->assertMatchesXpath( + $this->renderWidget($view), + '/input[@type="email"][@rel="theme"]' + ); + } + + public function testThemeBlockInheritanceUsingExtend() + { + $view = $this->factory + ->createNamed('name', 'email') + ->createView() + ; + + $this->setTheme($view, array('theme_extends.html.twig')); + + $this->assertMatchesXpath( + $this->renderWidget($view), + '/input[@type="email"][@rel="theme"]' + ); + } + + public function isSelectedChoiceProvider() + { + // The commented cases should not be necessary anymore, because the + // choice lists should assure that both values passed here are always + // strings + return array( +// array(true, 0, 0), + array(true, '0', '0'), + array(true, '1', '1'), +// array(true, false, 0), +// array(true, true, 1), + array(true, '', ''), +// array(true, null, ''), + array(true, '1.23', '1.23'), + array(true, 'foo', 'foo'), + array(true, 'foo10', 'foo10'), + array(true, 'foo', array(1, 'foo', 'foo10')), + + array(false, 10, array(1, 'foo', 'foo10')), + array(false, 0, array(1, 'foo', 'foo10')), + ); + } + + /** + * @dataProvider isSelectedChoiceProvider + */ + public function testIsChoiceSelected($expected, $choice, $value) + { + $choice = new ChoiceView($choice, $choice, $choice.' label'); + + $this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value)); + } + + protected function renderForm(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form', $vars); + } + + protected function renderEnctype(FormView $view) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype'); + } + + protected function renderLabel(FormView $view, $label = null, array $vars = array()) + { + if ($label !== null) { + $vars += array('label' => $label); + } + + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars); + } + + protected function renderErrors(FormView $view) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors'); + } + + protected function renderWidget(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars); + } + + protected function renderRow(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars); + } + + protected function renderRest(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars); + } + + protected function renderStart(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars); + } + + protected function renderEnd(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars); + } + + protected function setTheme(FormView $view, array $themes) + { + $this->extension->renderer->setTheme($view, $themes); + } + + public static function themeBlockInheritanceProvider() + { + return array( + array(array('theme.html.twig')) + ); + } + + public static function themeInheritanceProvider() + { + return array( + array(array('parent_label.html.twig'), array('child_label.html.twig')) + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php new file mode 100644 index 00000000..99a78217 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Component\Form\FormView; +use Symfony\Bridge\Twig\Form\TwigRenderer; +use Symfony\Bridge\Twig\Form\TwigRendererEngine; +use Symfony\Bridge\Twig\Extension\FormExtension; +use Symfony\Bridge\Twig\Extension\TranslationExtension; +use Symfony\Component\Form\Tests\AbstractTableLayoutTest; +use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator; +use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader; + +class FormExtensionTableLayoutTest extends AbstractTableLayoutTest +{ + /** + * @var FormExtension + */ + protected $extension; + + protected function setUp() + { + if (!class_exists('Symfony\Component\Locale\Locale')) { + $this->markTestSkipped('The "Locale" component is not available'); + } + + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + + if (!class_exists('Symfony\Component\Form\Form')) { + $this->markTestSkipped('The "Form" component is not available'); + } + + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + + parent::setUp(); + + $rendererEngine = new TwigRendererEngine(array( + 'form_table_layout.html.twig', + 'custom_widgets.html.twig', + )); + $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface')); + + $this->extension = new FormExtension($renderer); + + $loader = new StubFilesystemLoader(array( + __DIR__.'/../../Resources/views/Form', + __DIR__, + )); + + $environment = new \Twig_Environment($loader, array('strict_variables' => true)); + $environment->addExtension(new TranslationExtension(new StubTranslator())); + $environment->addGlobal('global', ''); + $environment->addExtension($this->extension); + + $this->extension->initRuntime($environment); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->extension = null; + } + + protected function renderForm(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form', $vars); + } + + protected function renderEnctype(FormView $view) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype'); + } + + protected function renderLabel(FormView $view, $label = null, array $vars = array()) + { + if ($label !== null) { + $vars += array('label' => $label); + } + + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars); + } + + protected function renderErrors(FormView $view) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors'); + } + + protected function renderWidget(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars); + } + + protected function renderRow(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars); + } + + protected function renderRest(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars); + } + + protected function renderStart(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars); + } + + protected function renderEnd(FormView $view, array $vars = array()) + { + return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars); + } + + protected function setTheme(FormView $view, array $themes) + { + $this->extension->renderer->setTheme($view, $themes); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php new file mode 100644 index 00000000..077927cd --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\HttpKernelExtension; +use Symfony\Bridge\Twig\Tests\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Fragment\FragmentHandler; + +class HttpKernelExtensionTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (!class_exists('Symfony\Component\HttpKernel\HttpKernel')) { + $this->markTestSkipped('The "HttpKernel" component is not available'); + } + + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + } + + /** + * @expectedException \Twig_Error_Runtime + */ + public function testFragmentWithError() + { + $kernel = $this->getFragmentHandler($this->throwException(new \Exception('foo'))); + + $loader = new \Twig_Loader_Array(array('index' => '{{ fragment("foo") }}')); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new HttpKernelExtension($kernel)); + + $this->renderTemplate($kernel); + } + + protected function getFragmentHandler($return) + { + $strategy = $this->getMock('Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface'); + $strategy->expects($this->once())->method('getName')->will($this->returnValue('inline')); + $strategy->expects($this->once())->method('render')->will($return); + + $renderer = new FragmentHandler(array($strategy)); + $renderer->setRequest(Request::create('/')); + + return $renderer; + } + + protected function renderTemplate(FragmentHandler $renderer, $template = '{{ render("foo") }}') + { + $loader = new \Twig_Loader_Array(array('index' => $template)); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new HttpKernelExtension($renderer)); + + return $twig->render('index'); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php new file mode 100644 index 00000000..3c5d762c --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\RoutingExtension; +use Symfony\Bridge\Twig\Tests\TestCase; + +class RoutingExtensionTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (!class_exists('Symfony\Component\Routing\Route')) { + $this->markTestSkipped('The "Routing" component is not available'); + } + } + + /** + * @dataProvider getEscapingTemplates + */ + public function testEscaping($template, $mustBeEscaped) + { + $twig = new \Twig_Environment(null, array('debug' => true, 'cache' => false, 'autoescape' => true, 'optimizations' => 0)); + $twig->addExtension(new RoutingExtension($this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'))); + + $nodes = $twig->parse($twig->tokenize($template)); + + $this->assertSame($mustBeEscaped, $nodes->getNode('body')->getNode(0)->getNode('expr') instanceof \Twig_Node_Expression_Filter); + } + + public function getEscapingTemplates() + { + return array( + array('{{ path("foo") }}', false), + array('{{ path("foo", {}) }}', false), + array('{{ path("foo", { foo: "foo" }) }}', false), + array('{{ path("foo", foo) }}', true), + array('{{ path("foo", { foo: foo }) }}', true), + array('{{ path("foo", { foo: ["foo", "bar"] }) }}', true), + array('{{ path("foo", { foo: "foo", bar: "bar" }) }}', true), + + array('{{ path(name = "foo", parameters = {}) }}', false), + array('{{ path(name = "foo", parameters = { foo: "foo" }) }}', false), + array('{{ path(name = "foo", parameters = foo) }}', true), + array('{{ path(name = "foo", parameters = { foo: ["foo", "bar"] }) }}', true), + array('{{ path(name = "foo", parameters = { foo: foo }) }}', true), + array('{{ path(name = "foo", parameters = { foo: "foo", bar: "bar" }) }}', true), + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php new file mode 100644 index 00000000..2b9c5533 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\TranslationExtension; +use Symfony\Component\Translation\Translator; +use Symfony\Component\Translation\MessageSelector; +use Symfony\Component\Translation\Loader\ArrayLoader; +use Symfony\Bridge\Twig\Tests\TestCase; + +class TranslationExtensionTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (!class_exists('Symfony\Component\Translation\Translator')) { + $this->markTestSkipped('The "Translation" component is not available'); + } + + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + } + + public function testEscaping() + { + $output = $this->getTemplate('{% trans %}Percent: %value%%% (%msg%){% endtrans %}')->render(array('value' => 12, 'msg' => 'approx.')); + + $this->assertEquals('Percent: 12% (approx.)', $output); + } + + /** + * @dataProvider getTransTests + */ + public function testTrans($template, $expected, array $variables = array()) + { + if ($expected != $this->getTemplate($template)->render($variables)) { + print $template."\n"; + $loader = new \Twig_Loader_Array(array('index' => $template)); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector()))); + + echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSource('index'), 'index')))."\n\n"; + $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); + } + + $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); + } + + public function getTransTests() + { + return array( + // trans tag + array('{% trans %}Hello{% endtrans %}', 'Hello'), + array('{% trans %}%name%{% endtrans %}', 'Symfony2', array('name' => 'Symfony2')), + + array('{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'), + + array('{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony2', array('name' => 'Symfony2')), + array('{% trans with { \'%name%\': \'Symfony2\' } %}Hello %name%{% endtrans %}', 'Hello Symfony2'), + array('{% set vars = { \'%name%\': \'Symfony2\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony2'), + + array('{% trans into "fr"%}Hello{% endtrans %}', 'Hello'), + + // transchoice + array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', + 'There is no apples', array('count' => 0)), + array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', + 'There is 5 apples', array('count' => 5)), + array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}', + 'There is 5 apples (Symfony2)', array('count' => 5, 'name' => 'Symfony2')), + array('{% transchoice count with { \'%name%\': \'Symfony2\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}', + 'There is 5 apples (Symfony2)', array('count' => 5)), + array('{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', + 'There is no apples', array('count' => 0)), + + // trans filter + array('{{ "Hello"|trans }}', 'Hello'), + array('{{ name|trans }}', 'Symfony2', array('name' => 'Symfony2')), + array('{{ hello|trans({ \'%name%\': \'Symfony2\' }) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')), + array('{% set vars = { \'%name%\': \'Symfony2\' } %}{{ hello|trans(vars) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')), + array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'), + + // transchoice filter + array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', array('count' => 5)), + array('{{ text|transchoice(5, {\'%name%\': \'Symfony2\'}) }}', 'There is 5 apples (Symfony2)', array('text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)')), + array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count, {}, "messages", "fr") }}', 'There is 5 apples', array('count' => 5)), + ); + } + + public function testDefaultTranslationDomain() + { + $templates = array( + 'index' => ' + {%- extends "base" %} + + {%- trans_default_domain "foo" %} + + {%- block content %} + {%- trans %}foo{% endtrans %} + {%- trans from "custom" %}foo{% endtrans %} + {{- "foo"|trans }} + {{- "foo"|trans({}, "custom") }} + {{- "foo"|transchoice(1) }} + {{- "foo"|transchoice(1, {}, "custom") }} + {% endblock %} + ', + + 'base' => ' + {%- block content "" %} + ', + ); + + $translator = new Translator('en', new MessageSelector()); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', array('foo' => 'foo (messages)'), 'en'); + $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom'); + $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo'); + + $template = $this->getTemplate($templates, $translator); + + $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array()))); + } + + protected function getTemplate($template, $translator = null) + { + if (null === $translator) { + $translator = new Translator('en', new MessageSelector()); + } + + if (is_array($template)) { + $loader = new \Twig_Loader_Array($template); + } else { + $loader = new \Twig_Loader_Array(array('index' => $template)); + } + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new TranslationExtension($translator)); + + return $twig->loadTemplate('index'); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig new file mode 100644 index 00000000..8c7c2489 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig @@ -0,0 +1,3 @@ +{% block form_label %} + +{% endblock form_label %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig new file mode 100644 index 00000000..12fd7c66 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig @@ -0,0 +1,16 @@ +{% block _text_id_widget %} +{% spaceless %} +
+ {{ form_widget(form) }} +
+{% endspaceless %} +{% endblock _text_id_widget %} + +{% block _name_entry_label %} +{% spaceless %} + {% if label is empty %} + {% set label = name|humanize %} + {% endif %} + +{% endspaceless %} +{% endblock _name_entry_label %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig new file mode 100644 index 00000000..e96278b8 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig @@ -0,0 +1,3 @@ +{% block form_label %} + +{% endblock form_label %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig new file mode 100644 index 00000000..da1c1b64 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig @@ -0,0 +1,6 @@ +{% block form_widget_simple %} +{% spaceless %} + {% set type = type|default('text') %} + +{% endspaceless %} +{% endblock form_widget_simple %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig new file mode 100644 index 00000000..8c719867 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig @@ -0,0 +1,8 @@ +{% extends 'form_div_layout.html.twig' %} + +{% block form_widget_simple %} +{% spaceless %} + {% set type = type|default('text') %} + +{% endspaceless %} +{% endblock form_widget_simple %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig new file mode 100644 index 00000000..d485b8d0 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig @@ -0,0 +1,8 @@ +{% use 'form_div_layout.html.twig' %} + +{% block form_widget_simple %} +{% spaceless %} + {% set type = type|default('text') %} + +{% endspaceless %} +{% endblock form_widget_simple %} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php new file mode 100644 index 00000000..90afef12 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Node; + +use Symfony\Bridge\Twig\Tests\TestCase; +use Symfony\Bridge\Twig\Node\FormThemeNode; + +class FormThemeTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) { + $this->markTestSkipped('Requires Twig version to be at least 1.5.0.'); + } + } + + public function testConstructor() + { + $form = new \Twig_Node_Expression_Name('form', 0); + $resources = new \Twig_Node(array( + new \Twig_Node_Expression_Constant('tpl1', 0), + new \Twig_Node_Expression_Constant('tpl2', 0) + )); + + $node = new FormThemeNode($form, $resources, 0); + + $this->assertEquals($form, $node->getNode('form')); + $this->assertEquals($resources, $node->getNode('resources')); + } + + public function testCompile() + { + $form = new \Twig_Node_Expression_Name('form', 0); + $resources = new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant(0, 0), + new \Twig_Node_Expression_Constant('tpl1', 0), + new \Twig_Node_Expression_Constant(1, 0), + new \Twig_Node_Expression_Constant('tpl2', 0) + ), 0); + + $node = new FormThemeNode($form, $resources, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->setTheme(%s, array(0 => "tpl1", 1 => "tpl2"));', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + + $resources = new \Twig_Node_Expression_Constant('tpl1', 0); + + $node = new FormThemeNode($form, $resources, 0); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->setTheme(%s, "tpl1");', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + protected function getVariableGetter($name) + { + if (version_compare(phpversion(), '5.4.0RC1', '>=')) { + return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name); + } + + return sprintf('$this->getContext($context, "%s")', $name); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php new file mode 100644 index 00000000..c1f247ca --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php @@ -0,0 +1,282 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Node; + +use Symfony\Bridge\Twig\Tests\TestCase; +use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode; + +class SearchAndRenderBlockNodeTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) { + $this->markTestSkipped('Requires Twig version to be at least 1.5.0.'); + } + } + + public function testCompileWidget() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + )); + + $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\')', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileWidgetWithVariables() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant('foo', 0), + new \Twig_Node_Expression_Constant('bar', 0), + ), 0), + )); + + $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\', array("foo" => "bar"))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithLabel() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Constant('my label', 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("label" => "my label"))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithNullLabel() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Constant(null, 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + // "label" => null must not be included in the output! + // Otherwise the default label is overwritten with null. + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithEmptyStringLabel() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Constant('', 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + // "label" => null must not be included in the output! + // Otherwise the default label is overwritten with null. + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithDefaultLabel() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithAttributes() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Constant(null, 0), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant('foo', 0), + new \Twig_Node_Expression_Constant('bar', 0), + ), 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + // "label" => null must not be included in the output! + // Otherwise the default label is overwritten with null. + // https://github.com/symfony/symfony/issues/5029 + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar"))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithLabelAndAttributes() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Constant('value in argument', 0), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant('foo', 0), + new \Twig_Node_Expression_Constant('bar', 0), + new \Twig_Node_Expression_Constant('label', 0), + new \Twig_Node_Expression_Constant('value in attributes', 0), + ), 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in argument"))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithLabelThatEvaluatesToNull() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Conditional( + // if + new \Twig_Node_Expression_Constant(true, 0), + // then + new \Twig_Node_Expression_Constant(null, 0), + // else + new \Twig_Node_Expression_Constant(null, 0), + 0 + ), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + // "label" => null must not be included in the output! + // Otherwise the default label is overwritten with null. + // https://github.com/symfony/symfony/issues/5029 + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes() + { + $arguments = new \Twig_Node(array( + new \Twig_Node_Expression_Name('form', 0), + new \Twig_Node_Expression_Conditional( + // if + new \Twig_Node_Expression_Constant(true, 0), + // then + new \Twig_Node_Expression_Constant(null, 0), + // else + new \Twig_Node_Expression_Constant(null, 0), + 0 + ), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant('foo', 0), + new \Twig_Node_Expression_Constant('bar', 0), + new \Twig_Node_Expression_Constant('label', 0), + new \Twig_Node_Expression_Constant('value in attributes', 0), + ), 0), + )); + + $node = new SearchAndRenderBlockNode('form_label', $arguments, 0); + + $compiler = new \Twig_Compiler(new \Twig_Environment()); + + // "label" => null must not be included in the output! + // Otherwise the default label is overwritten with null. + // https://github.com/symfony/symfony/issues/5029 + $this->assertEquals( + sprintf( + '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in attributes") + (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))', + $this->getVariableGetter('form') + ), + trim($compiler->compile($node)->getSource()) + ); + } + + protected function getVariableGetter($name) + { + if (version_compare(phpversion(), '5.4.0RC1', '>=')) { + return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name); + } + + return sprintf('$this->getContext($context, "%s")', $name); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php new file mode 100644 index 00000000..bcae5919 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\NodeVisitor; + +use Symfony\Bridge\Twig\NodeVisitor\Scope; +use Symfony\Bridge\Twig\Tests\TestCase; + +class ScopeTest extends TestCase +{ + public function testScopeInitiation() + { + $scope = new Scope(); + $scope->enter(); + $this->assertNull($scope->get('test')); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php new file mode 100644 index 00000000..24a6215e --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\NodeVisitor; + +use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor; +use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor; +use Symfony\Bridge\Twig\Tests\TestCase; + +class TranslationDefaultDomainNodeVisitorTest extends TestCase +{ + private static $message = 'message'; + private static $domain = 'domain'; + + /** @dataProvider getDefaultDomainAssignmentTestData */ + public function testDefaultDomainAssignment(\Twig_Node $node) + { + $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); + $visitor = new TranslationDefaultDomainNodeVisitor(); + + // visit trans_default_domain tag + $defaultDomain = TwigNodeProvider::getTransDefaultDomainTag(self::$domain); + $visitor->enterNode($defaultDomain, $env); + $visitor->leaveNode($defaultDomain, $env); + + // visit tested node + $enteredNode = $visitor->enterNode($node, $env); + $leavedNode = $visitor->leaveNode($node, $env); + $this->assertSame($node, $enteredNode); + $this->assertSame($node, $leavedNode); + + // extracting tested node messages + $visitor = new TranslationNodeVisitor(); + $visitor->enable(); + $visitor->enterNode($node, $env); + $visitor->leaveNode($node, $env); + + $this->assertEquals(array(array(self::$message, self::$domain)), $visitor->getMessages()); + } + + /** @dataProvider getDefaultDomainAssignmentTestData */ + public function testNewModuleWithoutDefaultDomainTag(\Twig_Node $node) + { + $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); + $visitor = new TranslationDefaultDomainNodeVisitor(); + + // visit trans_default_domain tag + $newModule = TwigNodeProvider::getModule('test'); + $visitor->enterNode($newModule, $env); + $visitor->leaveNode($newModule, $env); + + // visit tested node + $enteredNode = $visitor->enterNode($node, $env); + $leavedNode = $visitor->leaveNode($node, $env); + $this->assertSame($node, $enteredNode); + $this->assertSame($node, $leavedNode); + + // extracting tested node messages + $visitor = new TranslationNodeVisitor(); + $visitor->enable(); + $visitor->enterNode($node, $env); + $visitor->leaveNode($node, $env); + + $this->assertEquals(array(array(self::$message, null)), $visitor->getMessages()); + } + + public function getDefaultDomainAssignmentTestData() + { + return array( + array(TwigNodeProvider::getTransFilter(self::$message)), + array(TwigNodeProvider::getTransChoiceFilter(self::$message)), + array(TwigNodeProvider::getTransTag(self::$message)), + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php new file mode 100644 index 00000000..4e3ee6fd --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\NodeVisitor; + +use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor; +use Symfony\Bridge\Twig\Tests\TestCase; + +class TranslationNodeVisitorTest extends TestCase +{ + /** @dataProvider getMessagesExtractionTestData */ + public function testMessagesExtraction(\Twig_Node $node, array $expectedMessages) + { + $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); + $visitor = new TranslationNodeVisitor(); + $visitor->enable(); + $visitor->enterNode($node, $env); + $visitor->leaveNode($node, $env); + $this->assertEquals($expectedMessages, $visitor->getMessages()); + } + + public function testMessageExtractionWithInvalidDomainNode() + { + $message = 'new key'; + + $node = new \Twig_Node_Expression_Filter( + new \Twig_Node_Expression_Constant($message, 0), + new \Twig_Node_Expression_Constant('trans', 0), + new \Twig_Node(array( + new \Twig_Node_Expression_Array(array(), 0), + new \Twig_Node_Expression_Name('variable', 0), + )), + 0 + ); + + $this->testMessagesExtraction($node, array(array($message, TranslationNodeVisitor::UNDEFINED_DOMAIN))); + } + + public function getMessagesExtractionTestData() + { + $message = 'new key'; + $domain = 'domain'; + + return array( + array(TwigNodeProvider::getTransFilter($message), array(array($message, null))), + array(TwigNodeProvider::getTransChoiceFilter($message), array(array($message, null))), + array(TwigNodeProvider::getTransTag($message), array(array($message, null))), + array(TwigNodeProvider::getTransFilter($message, $domain), array(array($message, $domain))), + array(TwigNodeProvider::getTransChoiceFilter($message, $domain), array(array($message, $domain))), + array(TwigNodeProvider::getTransTag($message, $domain), array(array($message, $domain))), + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php new file mode 100644 index 00000000..277e7774 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\NodeVisitor; + +use Symfony\Bridge\Twig\Node\TransDefaultDomainNode; +use Symfony\Bridge\Twig\Node\TransNode; + +class TwigNodeProvider +{ + public static function getModule($content) + { + return new \Twig_Node_Module( + new \Twig_Node_Expression_Constant($content, 0), + null, + new \Twig_Node_Expression_Array(array(), 0), + new \Twig_Node_Expression_Array(array(), 0), + new \Twig_Node_Expression_Array(array(), 0), + null, + null + ); + } + + public static function getTransFilter($message, $domain = null) + { + $arguments = $domain ? array( + new \Twig_Node_Expression_Array(array(), 0), + new \Twig_Node_Expression_Constant($domain, 0), + ) : array(); + + return new \Twig_Node_Expression_Filter( + new \Twig_Node_Expression_Constant($message, 0), + new \Twig_Node_Expression_Constant('trans', 0), + new \Twig_Node($arguments), + 0 + ); + } + + public static function getTransChoiceFilter($message, $domain = null) + { + $arguments = $domain ? array( + new \Twig_Node_Expression_Constant(0, 0), + new \Twig_Node_Expression_Array(array(), 0), + new \Twig_Node_Expression_Constant($domain, 0), + ) : array(); + + return new \Twig_Node_Expression_Filter( + new \Twig_Node_Expression_Constant($message, 0), + new \Twig_Node_Expression_Constant('transchoice', 0), + new \Twig_Node($arguments), + 0 + ); + } + + public static function getTransTag($message, $domain = null) + { + return new TransNode( + new \Twig_Node_Body(array(), array('data' => $message)), + $domain ? new \Twig_Node_Expression_Constant($domain, 0) : null + ); + } + + public static function getTransDefaultDomainTag($domain) + { + return new TransDefaultDomainNode( + new \Twig_Node_Expression_Constant($domain, 0) + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php new file mode 100644 index 00000000..ecfb7daf --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests; + +abstract class TestCase extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php new file mode 100644 index 00000000..077cd76a --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Node; + +use Symfony\Bridge\Twig\Tests\TestCase; +use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser; +use Symfony\Bridge\Twig\Node\FormThemeNode; + +class FormThemeTokenParserTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + + if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) { + $this->markTestSkipped('Requires Twig version to be at least 1.5.0.'); + } + } + + /** + * @dataProvider getTestsForFormTheme + */ + public function testCompile($source, $expected) + { + $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); + $env->addTokenParser(new FormThemeTokenParser()); + $stream = $env->tokenize($source); + $parser = new \Twig_Parser($env); + + $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)); + } + + public function getTestsForFormTheme() + { + return array( + array( + '{% form_theme form "tpl1" %}', + new FormThemeNode( + new \Twig_Node_Expression_Name('form', 1), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant(0, 1), + new \Twig_Node_Expression_Constant('tpl1', 1), + ), 1), + 1, + 'form_theme' + ) + ), + array( + '{% form_theme form "tpl1" "tpl2" %}', + new FormThemeNode( + new \Twig_Node_Expression_Name('form', 1), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant(0, 1), + new \Twig_Node_Expression_Constant('tpl1', 1), + new \Twig_Node_Expression_Constant(1, 1), + new \Twig_Node_Expression_Constant('tpl2', 1) + ), 1), + 1, + 'form_theme' + ) + ), + array( + '{% form_theme form with "tpl1" %}', + new FormThemeNode( + new \Twig_Node_Expression_Name('form', 1), + new \Twig_Node_Expression_Constant('tpl1', 1), + 1, + 'form_theme' + ) + ), + array( + '{% form_theme form with ["tpl1"] %}', + new FormThemeNode( + new \Twig_Node_Expression_Name('form', 1), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant(0, 1), + new \Twig_Node_Expression_Constant('tpl1', 1), + ), 1), + 1, + 'form_theme' + ) + ), + array( + '{% form_theme form with ["tpl1", "tpl2"] %}', + new FormThemeNode( + new \Twig_Node_Expression_Name('form', 1), + new \Twig_Node_Expression_Array(array( + new \Twig_Node_Expression_Constant(0, 1), + new \Twig_Node_Expression_Constant('tpl1', 1), + new \Twig_Node_Expression_Constant(1, 1), + new \Twig_Node_Expression_Constant('tpl2', 1) + ), 1), + 1, + 'form_theme' + ) + ), + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php new file mode 100644 index 00000000..a2c5cd3d --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Translation; + +use Symfony\Bridge\Twig\Extension\TranslationExtension; +use Symfony\Bridge\Twig\Translation\TwigExtractor; +use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Bridge\Twig\Tests\TestCase; + +class TwigExtractorTest extends TestCase +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\Translation\Translator')) { + $this->markTestSkipped('The "Translation" component is not available'); + } + } + + /** + * @dataProvider getExtractData + */ + public function testExtract($template, $messages) + { + $loader = new \Twig_Loader_Array(array()); + $twig = new \Twig_Environment($loader, array( + 'strict_variables' => true, + 'debug' => true, + 'cache' => false, + 'autoescape' => false, + )); + $twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface'))); + + $extractor = new TwigExtractor($twig); + $extractor->setPrefix('prefix'); + $catalogue = new MessageCatalogue('en'); + + $m = new \ReflectionMethod($extractor, 'extractTemplate'); + $m->setAccessible(true); + $m->invoke($extractor, $template, $catalogue); + + foreach ($messages as $key => $domain) { + $this->assertTrue($catalogue->has($key, $domain)); + $this->assertEquals('prefix'.$key, $catalogue->get($key, $domain)); + } + } + + public function getExtractData() + { + return array( + array('{{ "new key" | trans() }}', array('new key' => 'messages')), + array('{{ "new key" | trans() | upper }}', array('new key' => 'messages')), + array('{{ "new key" | trans({}, "domain") }}', array('new key' => 'domain')), + array('{{ "new key" | transchoice(1) }}', array('new key' => 'messages')), + array('{{ "new key" | transchoice(1) | upper }}', array('new key' => 'messages')), + array('{{ "new key" | transchoice(1, {}, "domain") }}', array('new key' => 'domain')), + array('{% trans %}new key{% endtrans %}', array('new key' => 'messages')), + array('{% trans %} new key {% endtrans %}', array('new key' => 'messages')), + array('{% trans from "domain" %}new key{% endtrans %}', array('new key' => 'domain')), + array('{% set foo = "new key" | trans %}', array('new key' => 'messages')), + array('{{ 1 ? "new key" | trans : "another key" | trans }}', array('new key' => 'messages', 'another key' => 'messages')), + + // make sure 'trans_default_domain' tag is supported + array('{% trans_default_domain "domain" %}{{ "new key"|trans }}', array('new key' => 'domain')), + array('{% trans_default_domain "domain" %}{{ "new key"|transchoice }}', array('new key' => 'domain')), + array('{% trans_default_domain "domain" %}{% trans %}new key{% endtrans %}', array('new key' => 'domain')), + + // make sure this works with twig's named arguments + array('{{ "new key" | trans(domain="domain") }}', array('new key' => 'domain')), + array('{{ "new key" | transchoice(domain="domain", count=1) }}', array('new key' => 'domain')), + ); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php new file mode 100644 index 00000000..244d676e --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\TokenParser; + +use Symfony\Bridge\Twig\Node\FormThemeNode; + +/** + * Token Parser for the 'form_theme' tag. + * + * @author Fabien Potencier + */ +class FormThemeTokenParser extends \Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(\Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + + $form = $this->parser->getExpressionParser()->parseExpression(); + + if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'with')) { + $this->parser->getStream()->next(); + $resources = $this->parser->getExpressionParser()->parseExpression(); + } else { + $resources = new \Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); + do { + $resources->addElement($this->parser->getExpressionParser()->parseExpression()); + } while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)); + } + + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + return new FormThemeNode($form, $resources, $lineno, $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'form_theme'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php new file mode 100644 index 00000000..be8ac5cf --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\TokenParser; + +use Symfony\Bridge\Twig\Node\TransNode; + +/** + * Token Parser for the 'transchoice' tag. + * + * @author Fabien Potencier + */ +class TransChoiceTokenParser extends TransTokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + * + * @throws \Twig_Error_Syntax + */ + public function parse(\Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + + $vars = new \Twig_Node_Expression_Array(array(), $lineno); + + $count = $this->parser->getExpressionParser()->parseExpression(); + + $domain = null; + $locale = null; + + if ($stream->test('with')) { + // {% transchoice count with vars %} + $stream->next(); + $vars = $this->parser->getExpressionParser()->parseExpression(); + } + + if ($stream->test('from')) { + // {% transchoice count from "messages" %} + $stream->next(); + $domain = $this->parser->getExpressionParser()->parseExpression(); + } + + if ($stream->test('into')) { + // {% transchoice count into "fr" %} + $stream->next(); + $locale = $this->parser->getExpressionParser()->parseExpression(); + } + + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + $body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true); + + if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) { + throw new \Twig_Error_Syntax('A message must be a simple text.'); + } + + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + return new TransNode($body, $domain, $count, $vars, $locale, $lineno, $this->getTag()); + } + + public function decideTransChoiceFork($token) + { + return $token->test(array('endtranschoice')); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'transchoice'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php new file mode 100644 index 00000000..0a0ed55b --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\TokenParser; + +use Symfony\Bridge\Twig\Node\TransDefaultDomainNode; + +/** + * Token Parser for the 'trans_default_domain' tag. + * + * @author Fabien Potencier + */ +class TransDefaultDomainTokenParser extends \Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(\Twig_Token $token) + { + $expr = $this->parser->getExpressionParser()->parseExpression(); + + $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); + + return new TransDefaultDomainNode($expr, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'trans_default_domain'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php new file mode 100644 index 00000000..a11681c2 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\TokenParser; + +use Symfony\Bridge\Twig\Node\TransNode; + +/** + * Token Parser for the 'trans' tag. + * + * @author Fabien Potencier + */ +class TransTokenParser extends \Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + * + * @throws \Twig_Error_Syntax + */ + public function parse(\Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + + $vars = new \Twig_Node_Expression_Array(array(), $lineno); + $domain = null; + $locale = null; + if (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) { + if ($stream->test('with')) { + // {% trans with vars %} + $stream->next(); + $vars = $this->parser->getExpressionParser()->parseExpression(); + } + + if ($stream->test('from')) { + // {% trans from "messages" %} + $stream->next(); + $domain = $this->parser->getExpressionParser()->parseExpression(); + } + + if ($stream->test('into')) { + // {% trans into "fr" %} + $stream->next(); + $locale = $this->parser->getExpressionParser()->parseExpression(); + } elseif (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) { + throw new \Twig_Error_Syntax('Unexpected token. Twig was looking for the "with" or "from" keyword.'); + } + } + + // {% trans %}message{% endtrans %} + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideTransFork'), true); + + if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) { + throw new \Twig_Error_Syntax('A message inside a trans tag must be a simple text'); + } + + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + return new TransNode($body, $domain, null, $vars, $locale, $lineno, $this->getTag()); + } + + public function decideTransFork($token) + { + return $token->test(array('endtrans')); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'trans'; + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php new file mode 100644 index 00000000..b93193f2 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Translation; + +use Symfony\Component\Finder\Finder; +use Symfony\Component\Translation\Extractor\ExtractorInterface; +use Symfony\Component\Translation\MessageCatalogue; + +/** + * TwigExtractor extracts translation messages from a twig template. + * + * @author Michel Salib + * @author Fabien Potencier + */ +class TwigExtractor implements ExtractorInterface +{ + /** + * Default domain for found messages. + * + * @var string + */ + private $defaultDomain = 'messages'; + + /** + * Prefix for found message. + * + * @var string + */ + private $prefix = ''; + + /** + * The twig environment. + * + * @var \Twig_Environment + */ + private $twig; + + public function __construct(\Twig_Environment $twig) + { + $this->twig = $twig; + } + + /** + * {@inheritDoc} + */ + public function extract($directory, MessageCatalogue $catalogue) + { + // load any existing translation files + $finder = new Finder(); + $files = $finder->files()->name('*.twig')->in($directory); + foreach ($files as $file) { + $this->extractTemplate(file_get_contents($file->getPathname()), $catalogue); + } + } + + /** + * {@inheritDoc} + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } + + protected function extractTemplate($template, MessageCatalogue $catalogue) + { + $visitor = $this->twig->getExtension('translator')->getTranslationNodeVisitor(); + $visitor->enable(); + + $this->twig->parse($this->twig->tokenize($template)); + + foreach ($visitor->getMessages() as $message) { + $catalogue->set(trim($message[0]), $this->prefix.trim($message[0]), $message[1] ? $message[1] : $this->defaultDomain); + } + + $visitor->disable(); + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php new file mode 100644 index 00000000..955d4e0b --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig; + +use Symfony\Component\Templating\EngineInterface; +use Symfony\Component\Templating\StreamingEngineInterface; +use Symfony\Component\Templating\TemplateNameParserInterface; + +/** + * This engine knows how to render Twig templates. + * + * @author Fabien Potencier + */ +class TwigEngine implements EngineInterface, StreamingEngineInterface +{ + protected $environment; + protected $parser; + + /** + * Constructor. + * + * @param \Twig_Environment $environment A \Twig_Environment instance + * @param TemplateNameParserInterface $parser A TemplateNameParserInterface instance + */ + public function __construct(\Twig_Environment $environment, TemplateNameParserInterface $parser) + { + $this->environment = $environment; + $this->parser = $parser; + } + + /** + * Renders a template. + * + * @param mixed $name A template name + * @param array $parameters An array of parameters to pass to the template + * + * @return string The evaluated template as a string + * + * @throws \InvalidArgumentException if the template does not exist + * @throws \RuntimeException if the template cannot be rendered + */ + public function render($name, array $parameters = array()) + { + return $this->load($name)->render($parameters); + } + + /** + * Streams a template. + * + * @param mixed $name A template name or a TemplateReferenceInterface instance + * @param array $parameters An array of parameters to pass to the template + * + * @throws \RuntimeException if the template cannot be rendered + */ + public function stream($name, array $parameters = array()) + { + $this->load($name)->display($parameters); + } + + /** + * Returns true if the template exists. + * + * @param mixed $name A template name + * + * @return Boolean true if the template exists, false otherwise + */ + public function exists($name) + { + try { + $this->load($name); + } catch (\InvalidArgumentException $e) { + return false; + } + + return true; + } + + /** + * Returns true if this class is able to render the given template. + * + * @param string $name A template name + * + * @return Boolean True if this class supports the given resource, false otherwise + */ + public function supports($name) + { + if ($name instanceof \Twig_Template) { + return true; + } + + $template = $this->parser->parse($name); + + return 'twig' === $template->get('engine'); + } + + /** + * Loads the given template. + * + * @param mixed $name A template name or an instance of Twig_Template + * + * @return \Twig_TemplateInterface A \Twig_TemplateInterface instance + * + * @throws \InvalidArgumentException if the template does not exist + */ + protected function load($name) + { + if ($name instanceof \Twig_Template) { + return $name; + } + + try { + return $this->environment->loadTemplate($name); + } catch (\Twig_Error_Loader $e) { + throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json new file mode 100644 index 00000000..9cd57ae6 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json @@ -0,0 +1,50 @@ +{ + "name": "symfony/twig-bridge", + "type": "symfony-bridge", + "description": "Symfony Twig Bridge", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "twig/twig": "~1.11" + }, + "require-dev": { + "symfony/form": "2.2.*", + "symfony/http-kernel": "~2.2", + "symfony/routing": "~2.2", + "symfony/templating": "~2.1", + "symfony/translation": "~2.2", + "symfony/yaml": "~2.0", + "symfony/security": "~2.0" + }, + "suggest": { + "symfony/form": "", + "symfony/http-kernel": "", + "symfony/routing": "", + "symfony/templating": "", + "symfony/translation": "", + "symfony/yaml": "", + "symfony/security": "" + }, + "autoload": { + "psr-0": { "Symfony\\Bridge\\Twig\\": "" } + }, + "target-dir": "Symfony/Bridge/Twig", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + } +} diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist new file mode 100644 index 00000000..cc9e0e86 --- /dev/null +++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + -- cgit v1.2.3