Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
<?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 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;
public function __construct(Packages $packages)
{
$this->packages = $packages;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('asset', array($this, 'getAssetUrl')),
new TwigFunction('asset_version', array($this, 'getAssetVersion')),
);
}
/**
* 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)
{
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);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'asset';
}
}

View File

@@ -0,0 +1,264 @@
<?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\Debug\FileLinkFormatter;
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|FileLinkFormatter $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('format_log_message', array($this, 'formatLogMessage'), 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 ('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", '', htmlspecialchars(var_export($item[1], true), ENT_COMPAT | ENT_SUBSTITUTE, $this->charset));
}
$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
* @param int $srcContext The number of displayed lines around or -1 for the whole file
*
* @return string An HTML string
*/
public function fileExcerpt($file, $line, $srcContext = 3)
{
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);
// split multiline spans
$code = preg_replace_callback('#<span ([^>]++)>((?:[^<]*+<br \/>)++[^<]*+)</span>#', function ($m) {
return "<span $m[1]>".str_replace('<br />', "</span><br /><span $m[1]>", $m[2]).'</span>';
}, $code);
$content = explode('<br />', $code);
$lines = array();
if (0 > $srcContext) {
$srcContext = count($content);
}
for ($i = max($line - $srcContext, 1), $max = min($line + $srcContext, count($content)); $i <= $max; ++$i) {
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><a class="anchor" name="line'.$i.'"></a><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
}
return '<ol start="'.max($line - $srcContext, 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)) {
return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, ENT_COMPAT | ENT_SUBSTITUTE, $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 ($fmt = $this->fileLinkFormat) {
return is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line);
}
return false;
}
public function formatFileFromText($text)
{
return preg_replace_callback('/in ("|&quot;)?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) {
return 'in '.$this->formatFile($match[2], $match[3]);
}, $text);
}
/**
* @internal
*/
public function formatLogMessage($message, array $context)
{
if ($context && false !== strpos($message, '{')) {
$replacements = array();
foreach ($context as $key => $val) {
if (is_scalar($val)) {
$replacements['{'.$key.'}'] = $val;
}
}
if ($replacements) {
$message = strtr($message, $replacements);
}
}
return htmlspecialchars($message, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset);
}
/**
* {@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,84 @@
<?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;
private $dumper;
public function __construct(ClonerInterface $cloner, HtmlDumper $dumper = null)
{
$this->cloner = $cloner;
$this->dumper = $dumper ?: new HtmlDumper();
}
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');
$this->dumper->setCharset($env->getCharset());
foreach ($vars as $value) {
$this->dumper->dump($this->cloner->cloneVar($value), $dump);
}
return stream_get_contents($dump, -1, 0);
}
}

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,204 @@
<?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\FormThemeTokenParser;
use Symfony\Bridge\Twig\Form\TwigRendererInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\ChoiceList\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
{
/**
* @deprecated since version 3.2, to be removed in 4.0 alongside with magic methods below
*/
private $renderer;
public function __construct($renderer = null)
{
if ($renderer instanceof TwigRendererInterface) {
@trigger_error(sprintf('Passing a Twig Form Renderer to the "%s" constructor is deprecated since Symfony 3.2 and won\'t be possible in 4.0. Pass the Twig\Environment to the TwigRendererEngine constructor instead.', static::class), E_USER_DEPRECATED);
} elseif (null !== $renderer && !(is_array($renderer) && isset($renderer[0], $renderer[1]) && $renderer[0] instanceof ContainerInterface)) {
throw new \InvalidArgumentException(sprintf('Passing any arguments the constructor of %s is reserved for internal use.', __CLASS__));
}
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*
* To be removed in 4.0
*/
public function initRuntime(Environment $environment)
{
if ($this->renderer instanceof TwigRendererInterface) {
$this->renderer->setEnvironment($environment);
} elseif (null !== $this->renderer) {
$this->renderer[2] = $environment;
}
}
/**
* {@inheritdoc}
*/
public function getTokenParsers()
{
return array(
// {% form_theme form "SomeBundle::widgets.twig" %}
new FormThemeTokenParser(),
);
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
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('Symfony\Bridge\Twig\Form\TwigRenderer', 'renderCsrfToken')),
);
}
/**
* {@inheritdoc}
*/
public function getFilters()
{
return array(
new TwigFilter('humanize', array('Symfony\Bridge\Twig\Form\TwigRenderer', 'humanize')),
);
}
/**
* {@inheritdoc}
*/
public function getTests()
{
return array(
new TwigTest('selectedchoice', 'Symfony\Bridge\Twig\Extension\twig_is_selected_choice'),
new TwigTest('rootform', 'Symfony\Bridge\Twig\Extension\twig_is_root_form'),
);
}
/**
* @internal
*/
public function __get($name)
{
if ('renderer' === $name) {
@trigger_error(sprintf('Using the "%s::$renderer" property is deprecated since Symfony 3.2 as it will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
if (is_array($this->renderer)) {
$renderer = $this->renderer[0]->get($this->renderer[1]);
if (isset($this->renderer[2])) {
$renderer->setEnvironment($this->renderer[2]);
}
$this->renderer = $renderer;
}
}
return $this->$name;
}
/**
* @internal
*/
public function __set($name, $value)
{
if ('renderer' === $name) {
@trigger_error(sprintf('Using the "%s::$renderer" property is deprecated since Symfony 3.2 as it will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
}
$this->$name = $value;
}
/**
* @internal
*/
public function __isset($name)
{
if ('renderer' === $name) {
@trigger_error(sprintf('Using the "%s::$renderer" property is deprecated since Symfony 3.2 as it will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
}
return isset($this->$name);
}
/**
* @internal
*/
public function __unset($name)
{
if ('renderer' === $name) {
@trigger_error(sprintf('Using the "%s::$renderer" property is deprecated since Symfony 3.2 as it will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
}
unset($this->$name);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'form';
}
}
/**
* Returns whether a choice is selected for a given form value.
*
* This is a function and not callable due to performance reasons.
*
* @param string|array $selectedValue The selected value to compare
*
* @return bool Whether the choice is selected
*
* @see ChoiceView::isSelected()
*/
function twig_is_selected_choice(ChoiceView $choice, $selectedValue)
{
if (is_array($selectedValue)) {
return in_array($choice->value, $selectedValue, true);
}
return $choice->value === $selectedValue;
}
/**
* @internal
*/
function twig_is_root_form(FormView $formView)
{
return null === $formView->parent;
}

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\RequestStack;
use Symfony\Component\HttpFoundation\Request;
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,46 @@
<?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 Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Provides integration with the HttpKernel component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpKernelExtension extends AbstractExtension
{
public function getFunctions()
{
return array(
new TwigFunction('render', array(HttpKernelRuntime::class, 'renderFragment'), array('is_safe' => array('html'))),
new TwigFunction('render_*', array(HttpKernelRuntime::class, 'renderFragmentStrategy'), array('is_safe' => array('html'))),
new TwigFunction('controller', static::class.'::controller'),
);
}
public static 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,64 @@
<?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\Fragment\FragmentHandler;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
/**
* Provides integration with the HttpKernel component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpKernelRuntime
{
private $handler;
public function __construct(FragmentHandler $handler)
{
$this->handler = $handler;
}
/**
* 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);
}
}

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\Component\Stopwatch\Stopwatch;
use Symfony\Bridge\Twig\TokenParser\StopwatchTokenParser;
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\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;
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,139 @@
<?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 Fig\Link\GenericLinkProvider;
use Fig\Link\Link;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Twig extension for the Symfony WebLink component.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class WebLinkExtension extends AbstractExtension
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('link', array($this, 'link')),
new TwigFunction('preload', array($this, 'preload')),
new TwigFunction('dns_prefetch', array($this, 'dnsPrefetch')),
new TwigFunction('preconnect', array($this, 'preconnect')),
new TwigFunction('prefetch', array($this, 'prefetch')),
new TwigFunction('prerender', array($this, 'prerender')),
);
}
/**
* Adds a "Link" HTTP header.
*
* @param string $uri The relation URI
* @param string $rel The relation type (e.g. "preload", "prefetch", "prerender" or "dns-prefetch")
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('pr' => 0.5)")
*
* @return string The relation URI
*/
public function link($uri, $rel, array $attributes = array())
{
if (!$request = $this->requestStack->getMasterRequest()) {
return $uri;
}
$link = new Link($rel, $uri);
foreach ($attributes as $key => $value) {
$link = $link->withAttribute($key, $value);
}
$linkProvider = $request->attributes->get('_links', new GenericLinkProvider());
$request->attributes->set('_links', $linkProvider->withLink($link));
return $uri;
}
/**
* Preloads a resource.
*
* @param string $uri A public path
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('crossorigin' => 'use-credentials')")
*
* @return string The path of the asset
*/
public function preload($uri, array $attributes = array())
{
return $this->link($uri, 'preload', $attributes);
}
/**
* Resolves a resource origin as early as possible.
*
* @param string $uri A public path
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('pr' => 0.5)")
*
* @return string The path of the asset
*/
public function dnsPrefetch($uri, array $attributes = array())
{
return $this->link($uri, 'dns-prefetch', $attributes);
}
/**
* Initiates a early connection to a resource (DNS resolution, TCP handshake, TLS negotiation).
*
* @param string $uri A public path
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('pr' => 0.5)")
*
* @return string The path of the asset
*/
public function preconnect($uri, array $attributes = array())
{
return $this->link($uri, 'preconnect', $attributes);
}
/**
* Indicates to the client that it should prefetch this resource.
*
* @param string $uri A public path
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('pr' => 0.5)")
*
* @return string The path of the asset
*/
public function prefetch($uri, array $attributes = array())
{
return $this->link($uri, 'prefetch', $attributes);
}
/**
* Indicates to the client that it should prerender this resource .
*
* @param string $uri A public path
* @param array $attributes The attributes of this link (e.g. "array('as' => true)", "array('pr' => 0.5)")
*
* @return string The path of the asset
*/
public function prerender($uri, array $attributes = array())
{
return $this->link($uri, 'prerender', $attributes);
}
}

View File

@@ -0,0 +1,108 @@
<?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\Workflow\Registry;
use Symfony\Component\Workflow\Transition;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* WorkflowExtension.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class WorkflowExtension extends AbstractExtension
{
private $workflowRegistry;
public function __construct(Registry $workflowRegistry)
{
$this->workflowRegistry = $workflowRegistry;
}
public function getFunctions()
{
return array(
new TwigFunction('workflow_can', array($this, 'canTransition')),
new TwigFunction('workflow_transitions', array($this, 'getEnabledTransitions')),
new TwigFunction('workflow_has_marked_place', array($this, 'hasMarkedPlace')),
new TwigFunction('workflow_marked_places', array($this, 'getMarkedPlaces')),
);
}
/**
* Returns true if the transition is enabled.
*
* @param object $subject A subject
* @param string $transitionName A transition
* @param string $name A workflow name
*
* @return bool true if the transition is enabled
*/
public function canTransition($subject, $transitionName, $name = null)
{
return $this->workflowRegistry->get($subject, $name)->can($subject, $transitionName);
}
/**
* Returns all enabled transitions.
*
* @param object $subject A subject
* @param string $name A workflow name
*
* @return Transition[] All enabled transitions
*/
public function getEnabledTransitions($subject, $name = null)
{
return $this->workflowRegistry->get($subject, $name)->getEnabledTransitions($subject);
}
/**
* Returns true if the place is marked.
*
* @param object $subject A subject
* @param string $placeName A place name
* @param string $name A workflow name
*
* @return bool true if the transition is enabled
*/
public function hasMarkedPlace($subject, $placeName, $name = null)
{
return $this->workflowRegistry->get($subject, $name)->getMarking($subject)->has($placeName);
}
/**
* Returns marked places.
*
* @param object $subject A subject
* @param bool $placesNameOnly If true, returns only places name. If false returns the raw representation
* @param string $name A workflow name
*
* @return string[]|int[]
*/
public function getMarkedPlaces($subject, $placesNameOnly = true, $name = null)
{
$places = $this->workflowRegistry->get($subject, $name)->getMarking($subject)->getPlaces();
if ($placesNameOnly) {
return array_keys($places);
}
return $places;
}
public function getName()
{
return 'workflow';
}
}

View File

@@ -0,0 +1,80 @@
<?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 = 0)
{
static $dumper;
if (null === $dumper) {
$dumper = new YamlDumper();
}
if (defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) {
if (is_bool($dumpObjects)) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
$flags = $dumpObjects ? Yaml::DUMP_OBJECT : 0;
} else {
$flags = $dumpObjects;
}
return $dumper->dump($input, $inline, 0, $flags);
}
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';
}
}