PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,151 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Asset\Packages;
use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Twig extension for the Symfony Asset component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AssetExtension extends AbstractExtension
{
private $packages;
private $foundationExtension;
/**
* Passing an HttpFoundationExtension instance as a second argument must not be relied on
* as it's only there to maintain BC with older Symfony version. It will be removed in 3.0.
*/
public function __construct(Packages $packages, HttpFoundationExtension $foundationExtension = null)
{
$this->packages = $packages;
$this->foundationExtension = $foundationExtension;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('asset', array($this, 'getAssetUrl')),
new TwigFunction('asset_version', array($this, 'getAssetVersion')),
new TwigFunction('assets_version', array($this, 'getAssetsVersion'), array('deprecated' => true, 'alternative' => 'asset_version')),
);
}
/**
* Returns the public url/path of an asset.
*
* If the package used to generate the path is an instance of
* UrlPackage, you will always get a URL and not a path.
*
* @param string $path A public path
* @param string $packageName The name of the asset package to use
*
* @return string The public path of the asset
*/
public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null)
{
// BC layer to be removed in 3.0
if (2 < $count = \func_num_args()) {
@trigger_error('Generating absolute URLs with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0. Please use absolute_url() instead.', E_USER_DEPRECATED);
if (4 === $count) {
@trigger_error('Forcing a version with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
}
$args = \func_get_args();
return $this->getLegacyAssetUrl($path, $packageName, $args[2], isset($args[3]) ? $args[3] : null);
}
return $this->packages->getUrl($path, $packageName);
}
/**
* Returns the version of an asset.
*
* @param string $path A public path
* @param string $packageName The name of the asset package to use
*
* @return string The asset version
*/
public function getAssetVersion($path, $packageName = null)
{
return $this->packages->getVersion($path, $packageName);
}
public function getAssetsVersion($packageName = null)
{
@trigger_error('The Twig assets_version() function was deprecated in 2.7 and will be removed in 3.0. Please use asset_version() instead.', E_USER_DEPRECATED);
return $this->packages->getVersion('/', $packageName);
}
private function getLegacyAssetUrl($path, $packageName = null, $absolute = false, $version = null)
{
if ($version) {
$package = $this->packages->getPackage($packageName);
$v = new \ReflectionProperty('Symfony\Component\Asset\Package', 'versionStrategy');
$v->setAccessible(true);
$currentVersionStrategy = $v->getValue($package);
if (property_exists($currentVersionStrategy, 'format')) {
$f = new \ReflectionProperty($currentVersionStrategy, 'format');
$f->setAccessible(true);
$format = $f->getValue($currentVersionStrategy);
$v->setValue($package, new StaticVersionStrategy($version, $format));
} else {
$v->setValue($package, new StaticVersionStrategy($version));
}
}
try {
$url = $this->packages->getUrl($path, $packageName);
} catch (\Exception $e) {
if ($version) {
$v->setValue($package, $currentVersionStrategy);
}
throw $e;
}
if ($version) {
$v->setValue($package, $currentVersionStrategy);
}
if ($absolute) {
return $this->foundationExtension->generateAbsoluteUrl($url);
}
return $url;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'asset';
}
}

View File

@ -0,0 +1,242 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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 Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
/**
* Twig extension relate to PHP code and used by the profiler and the default exception templates.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CodeExtension extends AbstractExtension
{
private $fileLinkFormat;
private $rootDir;
private $charset;
/**
* @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 = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->rootDir = str_replace('/', \DIRECTORY_SEPARATOR, \dirname($rootDir)).\DIRECTORY_SEPARATOR;
$this->charset = $charset;
}
/**
* {@inheritdoc}
*/
public function getFilters()
{
return array(
new TwigFilter('abbr_class', array($this, 'abbrClass'), array('is_safe' => array('html'))),
new TwigFilter('abbr_method', array($this, 'abbrMethod'), array('is_safe' => array('html'))),
new TwigFilter('format_args', array($this, 'formatArgs'), array('is_safe' => array('html'))),
new TwigFilter('format_args_as_text', array($this, 'formatArgsAsText')),
new TwigFilter('file_excerpt', array($this, 'fileExcerpt'), array('is_safe' => array('html'))),
new TwigFilter('format_file', array($this, 'formatFile'), array('is_safe' => array('html'))),
new TwigFilter('format_file_from_text', array($this, 'formatFileFromText'), array('is_safe' => array('html'))),
new TwigFilter('file_link', array($this, 'getFileLink')),
);
}
public function abbrClass($class)
{
$parts = explode('\\', $class);
$short = array_pop($parts);
return sprintf('<abbr title="%s">%s</abbr>', $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('<abbr title="%s">%1$s</abbr>', $method);
} else {
$result = sprintf('<abbr title="%s">%1$s</abbr>()', $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('<em>object</em>(<abbr title="%s">%s</abbr>)', $item[1], $short);
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%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 = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
$formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
} elseif ('resource' === $item[0]) {
$formattedValue = '<em>resource</em>';
} 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)) {
// highlight_file could throw warnings
// see https://bugs.php.net/bug.php?id=25725
$code = @highlight_file($file, true);
// remove main code/span tags
$code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
$content = explode('<br />', $code);
$lines = array();
for ($i = max($line - 3, 1), $max = min($line + 3, \count($content)); $i <= $max; ++$i) {
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
}
return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
}
}
/**
* Formats a file path.
*
* @param string $file An absolute file path
* @param int $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)
{
$file = trim($file);
if (null === $text) {
$text = str_replace('/', \DIRECTORY_SEPARATOR, $file);
if (0 === strpos($text, $this->rootDir)) {
$text = substr($text, \strlen($this->rootDir));
$text = explode(\DIRECTORY_SEPARATOR, $text, 2);
$text = sprintf('<abbr title="%s%2$s">%s</abbr>%s', $this->rootDir, $text[0], isset($text[1]) ? \DIRECTORY_SEPARATOR.$text[1] : '');
}
}
$text = "$text at line $line";
if (false !== $link = $this->getFileLink($file, $line)) {
if (\PHP_VERSION_ID >= 50400) {
$flags = ENT_QUOTES | ENT_SUBSTITUTE;
} else {
$flags = ENT_QUOTES;
}
return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, $flags, $this->charset), $text);
}
return $text;
}
/**
* Returns the link for a given file/line pair.
*
* @param string $file An absolute file path
* @param int $line The line number
*
* @return string|false A link or 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 ("|&quot;)?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) use ($that) {
return 'in '.$that->formatFile($match[2], $match[3]);
}, $text);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'code';
}
protected static function fixCodeMarkup($line)
{
// </span> ending tag from previous line
$opening = strpos($line, '<span');
$closing = strpos($line, '</span>');
if (false !== $closing && (false === $opening || $closing < $opening)) {
$line = substr_replace($line, '', $closing, 7);
}
// missing </span> tag at the end of line
$opening = strpos($line, '<span');
$closing = strpos($line, '</span>');
if (false !== $opening && (false === $closing || $closing > $opening)) {
$line .= '</span>';
}
return $line;
}
}

View File

@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\DumpTokenParser;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Template;
use Twig\TwigFunction;
/**
* Provides integration of the dump() function with Twig.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class DumpExtension extends AbstractExtension
{
private $cloner;
public function __construct(ClonerInterface $cloner)
{
$this->cloner = $cloner;
}
public function getFunctions()
{
return array(
new TwigFunction('dump', array($this, 'dump'), array('is_safe' => array('html'), 'needs_context' => true, 'needs_environment' => true)),
);
}
public function getTokenParsers()
{
return array(new DumpTokenParser());
}
public function getName()
{
return 'dump';
}
public function dump(Environment $env, $context)
{
if (!$env->isDebug()) {
return;
}
if (2 === \func_num_args()) {
$vars = array();
foreach ($context as $key => $value) {
if (!$value instanceof Template) {
$vars[$key] = $value;
}
}
$vars = array($vars);
} else {
$vars = \func_get_args();
unset($vars[0], $vars[1]);
}
$dump = fopen('php://memory', 'r+b');
$dumper = new HtmlDumper($dump, $env->getCharset());
foreach ($vars as $value) {
$dumper->dump($this->cloner->cloneVar($value));
}
rewind($dump);
return stream_get_contents($dump);
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\ExpressionLanguage\Expression;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* ExpressionExtension gives a way to create Expressions from a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExpressionExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('expression', array($this, 'createExpression')),
);
}
public function createExpression($expression)
{
return new Expression($expression);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'expression';
}
}

View File

@ -0,0 +1,193 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Form\TwigRendererInterface;
use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Component\Form\FormView;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Extension\InitRuntimeInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* FormExtension extends Twig with form capabilities.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormExtension extends AbstractExtension implements InitRuntimeInterface
{
/**
* 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(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(
new TwigFunction('form_enctype', null, array('node_class' => 'Symfony\Bridge\Twig\Node\FormEnctypeNode', 'is_safe' => array('html'), 'deprecated' => true, 'alternative' => 'form_start')),
new TwigFunction('form_widget', null, array('node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_errors', null, array('node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_label', null, array('node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_row', null, array('node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_rest', null, array('node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form', null, array('node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_start', null, array('node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('form_end', null, array('node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => array('html'))),
new TwigFunction('csrf_token', array($this, 'renderCsrfToken')),
);
}
/**
* {@inheritdoc}
*/
public function getFilters()
{
return array(
new TwigFilter('humanize', array($this, 'humanize')),
new TwigFilter('form_encode_currency', array($this, 'encodeCurrency'), array('is_safe' => array('html'), 'needs_environment' => true)),
);
}
/**
* {@inheritdoc}
*/
public function getTests()
{
return array(
new TwigTest('selectedchoice', array($this, 'isSelectedChoice')),
new TwigTest('rootform', array($this, 'isRootForm')),
);
}
/**
* Renders a CSRF token.
*
* @param string $intention The intention of the protected action
*
* @return string A CSRF token
*/
public function renderCsrfToken($intention)
{
return $this->renderer->renderCsrfToken($intention);
}
/**
* Makes a technical name human readable.
*
* @param string $text The text to humanize
*
* @return string The humanized text
*/
public function humanize($text)
{
return $this->renderer->humanize($text);
}
/**
* 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 bool Whether the choice is selected
*
* @see ChoiceView::isSelected()
*/
public function isSelectedChoice(ChoiceView $choice, $selectedValue)
{
if (\is_array($selectedValue)) {
return \in_array($choice->value, $selectedValue, true);
}
return $choice->value === $selectedValue;
}
/**
* @internal
*/
public function isRootForm(FormView $formView)
{
return null === $formView->parent;
}
/**
* @internal
*/
public function encodeCurrency(Environment $environment, $text, $widget = '')
{
if ('UTF-8' === $charset = $environment->getCharset()) {
$text = htmlspecialchars($text, ENT_QUOTES | (\defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8');
} else {
$text = htmlentities($text, ENT_QUOTES | (\defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8');
$text = iconv('UTF-8', $charset, $text);
$widget = iconv('UTF-8', $charset, $widget);
}
return str_replace('{{ widget }}', $widget, $text);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'form';
}
}

View File

@ -0,0 +1,144 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RequestContext;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Twig extension for the Symfony HttpFoundation component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpFoundationExtension extends AbstractExtension
{
private $requestStack;
private $requestContext;
public function __construct(RequestStack $requestStack, RequestContext $requestContext = null)
{
$this->requestStack = $requestStack;
$this->requestContext = $requestContext;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('absolute_url', array($this, 'generateAbsoluteUrl')),
new TwigFunction('relative_path', array($this, 'generateRelativePath')),
);
}
/**
* Returns the absolute URL for the given absolute or relative path.
*
* This method returns the path unchanged if no request is available.
*
* @param string $path The path
*
* @return string The absolute URL
*
* @see Request::getUriForPath()
*/
public function generateAbsoluteUrl($path)
{
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
return $path;
}
if (!$request = $this->requestStack->getMasterRequest()) {
if (null !== $this->requestContext && '' !== $host = $this->requestContext->getHost()) {
$scheme = $this->requestContext->getScheme();
$port = '';
if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) {
$port = ':'.$this->requestContext->getHttpPort();
} elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) {
$port = ':'.$this->requestContext->getHttpsPort();
}
if ('#' === $path[0]) {
$queryString = $this->requestContext->getQueryString();
$path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path;
} elseif ('?' === $path[0]) {
$path = $this->requestContext->getPathInfo().$path;
}
if ('/' !== $path[0]) {
$path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path;
}
return $scheme.'://'.$host.$port.$path;
}
return $path;
}
if ('#' === $path[0]) {
$path = $request->getRequestUri().$path;
} elseif ('?' === $path[0]) {
$path = $request->getPathInfo().$path;
}
if (!$path || '/' !== $path[0]) {
$prefix = $request->getPathInfo();
$last = \strlen($prefix) - 1;
if ($last !== $pos = strrpos($prefix, '/')) {
$prefix = substr($prefix, 0, $pos).'/';
}
return $request->getUriForPath($prefix.$path);
}
return $request->getSchemeAndHttpHost().$path;
}
/**
* Returns a relative path based on the current Request.
*
* This method returns the path unchanged if no request is available.
*
* @param string $path The path
*
* @return string The relative path
*
* @see Request::getRelativeUriForPath()
*/
public function generateRelativePath($path)
{
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
return $path;
}
if (!$request = $this->requestStack->getMasterRequest()) {
return $path;
}
return $request->getRelativeUriForPath($path);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'request';
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Provides integration with the HttpKernel component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpKernelExtension extends AbstractExtension
{
private $handler;
public function __construct(FragmentHandler $handler)
{
$this->handler = $handler;
}
public function getFunctions()
{
return array(
new TwigFunction('render', array($this, 'renderFragment'), array('is_safe' => array('html'))),
new TwigFunction('render_*', array($this, 'renderFragmentStrategy'), array('is_safe' => array('html'))),
new TwigFunction('controller', array($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 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 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);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'http_kernel';
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Http\Logout\LogoutUrlGenerator;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* LogoutUrlHelper provides generator functions for the logout URL to Twig.
*
* @author Jeremy Mikola <jmikola@gmail.com>
*/
class LogoutUrlExtension extends AbstractExtension
{
private $generator;
public function __construct(LogoutUrlGenerator $generator)
{
$this->generator = $generator;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('logout_url', array($this, 'getLogoutUrl')),
new TwigFunction('logout_path', array($this, 'getLogoutPath')),
);
}
/**
* Generates the relative logout URL for the firewall.
*
* @param string|null $key The firewall key or null to use the current firewall key
*
* @return string The relative logout URL
*/
public function getLogoutPath($key = null)
{
return $this->generator->getLogoutPath($key);
}
/**
* Generates the absolute logout URL for the firewall.
*
* @param string|null $key The firewall key or null to use the current firewall key
*
* @return string The absolute logout URL
*/
public function getLogoutUrl($key = null)
{
return $this->generator->getLogoutUrl($key);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'logout_url';
}
}

View File

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Stopwatch\Stopwatch;
use Twig\Extension\ProfilerExtension as BaseProfilerExtension;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class ProfilerExtension extends BaseProfilerExtension
{
private $stopwatch;
private $events;
public function __construct(Profile $profile, Stopwatch $stopwatch = null)
{
parent::__construct($profile);
$this->stopwatch = $stopwatch;
$this->events = new \SplObjectStorage();
}
public function enter(Profile $profile)
{
if ($this->stopwatch && $profile->isTemplate()) {
$this->events[$profile] = $this->stopwatch->start($profile->getName(), 'template');
}
parent::enter($profile);
}
public function leave(Profile $profile)
{
parent::leave($profile);
if ($this->stopwatch && $profile->isTemplate()) {
$this->events[$profile]->stop();
unset($this->events[$profile]);
}
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'native_profiler';
}
}

View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;
use Twig\Extension\AbstractExtension;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\TwigFunction;
/**
* Provides integration of the Routing component with Twig.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RoutingExtension extends AbstractExtension
{
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(
new TwigFunction('url', array($this, 'getUrl'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
new TwigFunction('path', array($this, 'getPath'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
);
}
/**
* @param string $name
* @param array $parameters
* @param bool $relative
*
* @return string
*/
public function getPath($name, $parameters = array(), $relative = false)
{
return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
}
/**
* @param string $name
* @param array $parameters
* @param bool $schemeRelative
*
* @return string
*/
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 Node $argsNode The arguments of the path/url function
*
* @return array An array with the contexts the URL is safe
*
* To be made @final in 3.4, and the type-hint be changed to "\Twig\Node\Node" in 4.0.
*/
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 ArrayExpression && \count($paramsNode) <= 2 &&
(!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof ConstantExpression)
) {
return array('html');
}
return array();
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'routing';
}
}

View File

@ -0,0 +1,68 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* SecurityExtension exposes security context features.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SecurityExtension extends AbstractExtension
{
private $securityChecker;
public function __construct(AuthorizationCheckerInterface $securityChecker = null)
{
$this->securityChecker = $securityChecker;
}
public function isGranted($role, $object = null, $field = null)
{
if (null === $this->securityChecker) {
return false;
}
if (null !== $field) {
$object = new FieldVote($object, $field);
}
try {
return $this->securityChecker->isGranted($role, $object);
} catch (AuthenticationCredentialsNotFoundException $e) {
return false;
}
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('is_granted', array($this, 'isGranted')),
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'security';
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\StopwatchTokenParser;
use Symfony\Component\Stopwatch\Stopwatch;
use Twig\Extension\AbstractExtension;
/**
* Twig extension for the stopwatch helper.
*
* @author Wouter J <wouter@wouterj.nl>
*/
class StopwatchExtension extends AbstractExtension
{
private $stopwatch;
private $enabled;
public function __construct(Stopwatch $stopwatch = null, $enabled = true)
{
$this->stopwatch = $stopwatch;
$this->enabled = $enabled;
}
public function getStopwatch()
{
return $this->stopwatch;
}
public function getTokenParsers()
{
return array(
/*
* {% stopwatch foo %}
* Some stuff which will be recorded on the timeline
* {% endstopwatch %}
*/
new StopwatchTokenParser(null !== $this->stopwatch && $this->enabled),
);
}
public function getName()
{
return 'stopwatch';
}
}

View File

@ -0,0 +1,112 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\NodeVisitor\TranslationDefaultDomainNodeVisitor;
use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser;
use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser;
use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
use Symfony\Component\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\AbstractTokenParser;
use Twig\TwigFilter;
/**
* Provides integration of the Translation component with Twig.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TranslationExtension extends AbstractExtension
{
private $translator;
private $translationNodeVisitor;
public function __construct(TranslatorInterface $translator, 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(
new TwigFilter('trans', array($this, 'trans')),
new TwigFilter('transchoice', array($this, 'transchoice')),
);
}
/**
* Returns the token parser instance to add to the existing list.
*
* @return AbstractTokenParser[]
*/
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)
{
return $this->translator->trans($message, $arguments, $domain, $locale);
}
public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
{
return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'translator';
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;
use Symfony\Component\Yaml\Yaml;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
/**
* Provides integration of the Yaml component with Twig.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class YamlExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*/
public function getFilters()
{
return array(
new TwigFilter('yaml_encode', array($this, 'encode')),
new TwigFilter('yaml_dump', array($this, 'dump')),
);
}
public function encode($input, $inline = 0, $dumpObjects = false)
{
static $dumper;
if (null === $dumper) {
$dumper = new YamlDumper();
}
if (\defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) {
return $dumper->dump($input, $inline, 0, \is_bool($dumpObjects) ? Yaml::DUMP_OBJECT : 0);
}
return $dumper->dump($input, $inline, 0, 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);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'yaml';
}
}