login consent app sql

This commit is contained in:
2022-05-03 08:54:45 +02:00
parent e7253acfd8
commit f9a6535906
1652 changed files with 187600 additions and 45 deletions

View File

@ -0,0 +1,61 @@
<?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>
*/
final class AssetExtension extends AbstractExtension
{
private $packages;
public function __construct(Packages $packages)
{
$this->packages = $packages;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('asset', [$this, 'getAssetUrl']),
new TwigFunction('asset_version', [$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.
*/
public function getAssetUrl(string $path, string $packageName = null): string
{
return $this->packages->getUrl($path, $packageName);
}
/**
* Returns the version of an asset.
*/
public function getAssetVersion(string $path, string $packageName = null): string
{
return $this->packages->getVersion($path, $packageName);
}
}

View File

@ -0,0 +1,246 @@
<?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>
*/
final class CodeExtension extends AbstractExtension
{
private $fileLinkFormat;
private $charset;
private $projectDir;
/**
* @param string|FileLinkFormatter $fileLinkFormat The format for links to source files
*/
public function __construct($fileLinkFormat, string $projectDir, string $charset)
{
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->projectDir = str_replace('\\', '/', $projectDir).'/';
$this->charset = $charset;
}
/**
* {@inheritdoc}
*/
public function getFilters(): array
{
return [
new TwigFilter('abbr_class', [$this, 'abbrClass'], ['is_safe' => ['html']]),
new TwigFilter('abbr_method', [$this, 'abbrMethod'], ['is_safe' => ['html']]),
new TwigFilter('format_args', [$this, 'formatArgs'], ['is_safe' => ['html']]),
new TwigFilter('format_args_as_text', [$this, 'formatArgsAsText']),
new TwigFilter('file_excerpt', [$this, 'fileExcerpt'], ['is_safe' => ['html']]),
new TwigFilter('format_file', [$this, 'formatFile'], ['is_safe' => ['html']]),
new TwigFilter('format_file_from_text', [$this, 'formatFileFromText'], ['is_safe' => ['html']]),
new TwigFilter('format_log_message', [$this, 'formatLogMessage'], ['is_safe' => ['html']]),
new TwigFilter('file_link', [$this, 'getFileLink']),
new TwigFilter('file_relative', [$this, 'getFileRelative']),
];
}
public function abbrClass(string $class): string
{
$parts = explode('\\', $class);
$short = array_pop($parts);
return sprintf('<abbr title="%s">%s</abbr>', $class, $short);
}
public function abbrMethod(string $method): string
{
if (str_contains($method, '::')) {
[$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.
*/
public function formatArgs(array $args): string
{
$result = [];
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.
*/
public function formatArgsAsText(array $args): string
{
return strip_tags($this->formatArgs($args));
}
/**
* Returns an excerpt of a code file around the given line number.
*/
public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?string
{
if (is_file($file) && is_readable($file)) {
// highlight_file could throw warnings
// see https://bugs.php.net/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 = [];
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" id="line'.$i.'"></a><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
}
return '<ol start="'.max($line - $srcContext, 1).'">'.implode("\n", $lines).'</ol>';
}
return null;
}
/**
* Formats a file path.
*/
public function formatFile(string $file, int $line, string $text = null): string
{
$file = trim($file);
if (null === $text) {
$text = $file;
if (null !== $rel = $this->getFileRelative($text)) {
$rel = explode('/', $rel, 2);
$text = sprintf('<abbr title="%s%2$s">%s</abbr>%s', $this->projectDir, $rel[0], '/'.($rel[1] ?? ''));
}
}
if (0 < $line) {
$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.
*
* @return string|false
*/
public function getFileLink(string $file, int $line)
{
if ($fmt = $this->fileLinkFormat) {
return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line);
}
return false;
}
public function getFileRelative(string $file): ?string
{
$file = str_replace('\\', '/', $file);
if (null !== $this->projectDir && str_starts_with($file, $this->projectDir)) {
return ltrim(substr($file, \strlen($this->projectDir)), '/');
}
return null;
}
public function formatFileFromText(string $text): string
{
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(string $message, array $context): string
{
if ($context && str_contains($message, '{')) {
$replacements = [];
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);
}
protected static function fixCodeMarkup(string $line): string
{
// </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 trim($line);
}
}

View File

@ -0,0 +1,32 @@
<?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\TwigFunction;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
final class CsrfExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('csrf_token', [CsrfRuntime::class, 'getCsrfToken']),
];
}
}

View File

@ -0,0 +1,33 @@
<?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\Csrf\CsrfTokenManagerInterface;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
final class CsrfRuntime
{
private $csrfTokenManager;
public function __construct(CsrfTokenManagerInterface $csrfTokenManager)
{
$this->csrfTokenManager = $csrfTokenManager;
}
public function getCsrfToken(string $tokenId): string
{
return $this->csrfTokenManager->getToken($tokenId)->getValue();
}
}

View File

@ -0,0 +1,86 @@
<?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>
*/
final class DumpExtension extends AbstractExtension
{
private $cloner;
private $dumper;
public function __construct(ClonerInterface $cloner, HtmlDumper $dumper = null)
{
$this->cloner = $cloner;
$this->dumper = $dumper;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('dump', [$this, 'dump'], ['is_safe' => ['html'], 'needs_context' => true, 'needs_environment' => true]),
];
}
/**
* {@inheritdoc}
*/
public function getTokenParsers(): array
{
return [new DumpTokenParser()];
}
public function dump(Environment $env, array $context): ?string
{
if (!$env->isDebug()) {
return null;
}
if (2 === \func_num_args()) {
$vars = [];
foreach ($context as $key => $value) {
if (!$value instanceof Template) {
$vars[$key] = $value;
}
}
$vars = [$vars];
} else {
$vars = \func_get_args();
unset($vars[0], $vars[1]);
}
$dump = fopen('php://memory', 'r+');
$this->dumper = $this->dumper ?? new HtmlDumper();
$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,39 @@
<?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>
*/
final class ExpressionExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('expression', [$this, 'createExpression']),
];
}
public function createExpression(string $expression): Expression
{
return new Expression($expression);
}
}

View File

@ -0,0 +1,219 @@
<?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\Component\Form\ChoiceList\View\ChoiceGroupView;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormView;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
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>
*/
final class FormExtension extends AbstractExtension
{
private $translator;
public function __construct(TranslatorInterface $translator = null)
{
$this->translator = $translator;
}
/**
* {@inheritdoc}
*/
public function getTokenParsers(): array
{
return [
// {% form_theme form "SomeBundle::widgets.twig" %}
new FormThemeTokenParser(),
];
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('form_widget', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_errors', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_label', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_help', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_row', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_rest', null, ['node_class' => 'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form', null, ['node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_start', null, ['node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('form_end', null, ['node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => ['html']]),
new TwigFunction('csrf_token', ['Symfony\Component\Form\FormRenderer', 'renderCsrfToken']),
new TwigFunction('form_parent', 'Symfony\Bridge\Twig\Extension\twig_get_form_parent'),
new TwigFunction('field_name', [$this, 'getFieldName']),
new TwigFunction('field_value', [$this, 'getFieldValue']),
new TwigFunction('field_label', [$this, 'getFieldLabel']),
new TwigFunction('field_help', [$this, 'getFieldHelp']),
new TwigFunction('field_errors', [$this, 'getFieldErrors']),
new TwigFunction('field_choices', [$this, 'getFieldChoices']),
];
}
/**
* {@inheritdoc}
*/
public function getFilters(): array
{
return [
new TwigFilter('humanize', ['Symfony\Component\Form\FormRenderer', 'humanize']),
new TwigFilter('form_encode_currency', ['Symfony\Component\Form\FormRenderer', 'encodeCurrency'], ['is_safe' => ['html'], 'needs_environment' => true]),
];
}
/**
* {@inheritdoc}
*/
public function getTests(): array
{
return [
new TwigTest('selectedchoice', 'Symfony\Bridge\Twig\Extension\twig_is_selected_choice'),
new TwigTest('rootform', 'Symfony\Bridge\Twig\Extension\twig_is_root_form'),
];
}
public function getFieldName(FormView $view): string
{
$view->setRendered();
return $view->vars['full_name'];
}
/**
* @return string|array
*/
public function getFieldValue(FormView $view)
{
return $view->vars['value'];
}
public function getFieldLabel(FormView $view): ?string
{
if (false === $label = $view->vars['label']) {
return null;
}
if (!$label && $labelFormat = $view->vars['label_format']) {
$label = str_replace(['%id%', '%name%'], [$view->vars['id'], $view->vars['name']], $labelFormat);
} elseif (!$label) {
$label = ucfirst(strtolower(trim(preg_replace(['/([A-Z])/', '/[_\s]+/'], ['_$1', ' '], $view->vars['name']))));
}
return $this->createFieldTranslation(
$label,
$view->vars['label_translation_parameters'] ?: [],
$view->vars['translation_domain']
);
}
public function getFieldHelp(FormView $view): ?string
{
return $this->createFieldTranslation(
$view->vars['help'],
$view->vars['help_translation_parameters'] ?: [],
$view->vars['translation_domain']
);
}
/**
* @return string[]
*/
public function getFieldErrors(FormView $view): iterable
{
/** @var FormError $error */
foreach ($view->vars['errors'] as $error) {
yield $error->getMessage();
}
}
/**
* @return string[]|string[][]
*/
public function getFieldChoices(FormView $view): iterable
{
yield from $this->createFieldChoicesList($view->vars['choices'], $view->vars['choice_translation_domain']);
}
private function createFieldChoicesList(iterable $choices, $translationDomain): iterable
{
foreach ($choices as $choice) {
$translatableLabel = $this->createFieldTranslation($choice->label, [], $translationDomain);
if ($choice instanceof ChoiceGroupView) {
yield $translatableLabel => $this->createFieldChoicesList($choice, $translationDomain);
continue;
}
/* @var ChoiceView $choice */
yield $translatableLabel => $choice->value;
}
}
private function createFieldTranslation(?string $value, array $parameters, $domain): ?string
{
if (!$this->translator || !$value || false === $domain) {
return $value;
}
return $this->translator->trans($value, $parameters, $domain);
}
}
/**
* 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
*
* @see ChoiceView::isSelected()
*/
function twig_is_selected_choice(ChoiceView $choice, $selectedValue): bool
{
if (\is_array($selectedValue)) {
return \in_array($choice->value, $selectedValue, true);
}
return $choice->value === $selectedValue;
}
/**
* @internal
*/
function twig_is_root_form(FormView $formView): bool
{
return null === $formView->parent;
}
/**
* @internal
*/
function twig_get_form_parent(FormView $formView): ?FormView
{
return $formView->parent;
}

View File

@ -0,0 +1,67 @@
<?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\UrlHelper;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* Twig extension for the Symfony HttpFoundation component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class HttpFoundationExtension extends AbstractExtension
{
private $urlHelper;
public function __construct(UrlHelper $urlHelper)
{
$this->urlHelper = $urlHelper;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('absolute_url', [$this, 'generateAbsoluteUrl']),
new TwigFunction('relative_path', [$this, 'generateRelativePath']),
];
}
/**
* Returns the absolute URL for the given absolute or relative path.
*
* This method returns the path unchanged if no request is available.
*
* @see Request::getUriForPath()
*/
public function generateAbsoluteUrl(string $path): string
{
return $this->urlHelper->getAbsoluteUrl($path);
}
/**
* Returns a relative path based on the current Request.
*
* This method returns the path unchanged if no request is available.
*
* @see Request::getRelativeUriForPath()
*/
public function generateRelativePath(string $path): string
{
return $this->urlHelper->getRelativePath($path);
}
}

View File

@ -0,0 +1,42 @@
<?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>
*/
final class HttpKernelExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('render', [HttpKernelRuntime::class, 'renderFragment'], ['is_safe' => ['html']]),
new TwigFunction('render_*', [HttpKernelRuntime::class, 'renderFragmentStrategy'], ['is_safe' => ['html']]),
new TwigFunction('fragment_uri', [HttpKernelRuntime::class, 'generateFragmentUri']),
new TwigFunction('controller', static::class.'::controller'),
];
}
public static function controller(string $controller, array $attributes = [], array $query = []): ControllerReference
{
return new ControllerReference($controller, $attributes, $query);
}
}

View File

@ -0,0 +1,69 @@
<?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 Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
/**
* Provides integration with the HttpKernel component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class HttpKernelRuntime
{
private $handler;
private $fragmentUriGenerator;
public function __construct(FragmentHandler $handler, FragmentUriGeneratorInterface $fragmentUriGenerator = null)
{
$this->handler = $handler;
$this->fragmentUriGenerator = $fragmentUriGenerator;
}
/**
* Renders a fragment.
*
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
*
* @see FragmentHandler::render()
*/
public function renderFragment($uri, array $options = []): string
{
$strategy = $options['strategy'] ?? 'inline';
unset($options['strategy']);
return $this->handler->render($uri, $strategy, $options);
}
/**
* Renders a fragment.
*
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
*
* @see FragmentHandler::render()
*/
public function renderFragmentStrategy(string $strategy, $uri, array $options = []): string
{
return $this->handler->render($uri, $strategy, $options);
}
public function generateFragmentUri(ControllerReference $controller, bool $absolute = false, bool $strict = true, bool $sign = true): string
{
if (null === $this->fragmentUriGenerator) {
throw new \LogicException(sprintf('An instance of "%s" must be provided to use "%s()".', FragmentUriGeneratorInterface::class, __METHOD__));
}
return $this->fragmentUriGenerator->generate($controller, null, $absolute, $strict, $sign);
}
}

View File

@ -0,0 +1,62 @@
<?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>
*/
final class LogoutUrlExtension extends AbstractExtension
{
private $generator;
public function __construct(LogoutUrlGenerator $generator)
{
$this->generator = $generator;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('logout_url', [$this, 'getLogoutUrl']),
new TwigFunction('logout_path', [$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
*/
public function getLogoutPath(string $key = null): string
{
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
*/
public function getLogoutUrl(string $key = null): string
{
return $this->generator->getLogoutUrl($key);
}
}

View File

@ -0,0 +1,57 @@
<?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\Component\Stopwatch\StopwatchEvent;
use Twig\Extension\ProfilerExtension as BaseProfilerExtension;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
final class ProfilerExtension extends BaseProfilerExtension
{
private $stopwatch;
/**
* @var \SplObjectStorage<Profile, StopwatchEvent>
*/
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): void
{
if ($this->stopwatch && $profile->isTemplate()) {
$this->events[$profile] = $this->stopwatch->start($profile->getName(), 'template');
}
parent::enter($profile);
}
public function leave(Profile $profile): void
{
parent::leave($profile);
if ($this->stopwatch && $profile->isTemplate()) {
$this->events[$profile]->stop();
unset($this->events[$profile]);
}
}
}

View File

@ -0,0 +1,93 @@
<?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>
*/
final class RoutingExtension extends AbstractExtension
{
private $generator;
public function __construct(UrlGeneratorInterface $generator)
{
$this->generator = $generator;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
new TwigFunction('path', [$this, 'getPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
];
}
public function getPath(string $name, array $parameters = [], bool $relative = false): string
{
return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
}
public function getUrl(string $name, array $parameters = [], bool $schemeRelative = false): string
{
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
*/
public function isUrlGenerationSafe(Node $argsNode): array
{
// 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 ['html'];
}
return [];
}
}

View File

@ -0,0 +1,87 @@
<?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 Symfony\Component\Security\Http\Impersonate\ImpersonateUrlGenerator;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* SecurityExtension exposes security context features.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class SecurityExtension extends AbstractExtension
{
private $securityChecker;
private $impersonateUrlGenerator;
public function __construct(AuthorizationCheckerInterface $securityChecker = null, ImpersonateUrlGenerator $impersonateUrlGenerator = null)
{
$this->securityChecker = $securityChecker;
$this->impersonateUrlGenerator = $impersonateUrlGenerator;
}
/**
* @param mixed $object
*/
public function isGranted($role, $object = null, string $field = null): bool
{
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;
}
}
public function getImpersonateExitUrl(string $exitTo = null): string
{
if (null === $this->impersonateUrlGenerator) {
return '';
}
return $this->impersonateUrlGenerator->generateExitUrl($exitTo);
}
public function getImpersonateExitPath(string $exitTo = null): string
{
if (null === $this->impersonateUrlGenerator) {
return '';
}
return $this->impersonateUrlGenerator->generateExitPath($exitTo);
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('is_granted', [$this, 'isGranted']),
new TwigFunction('impersonation_exit_url', [$this, 'getImpersonateExitUrl']),
new TwigFunction('impersonation_exit_path', [$this, 'getImpersonateExitPath']),
];
}
}

View File

@ -0,0 +1,28 @@
<?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;
/**
* @author Jesse Rushlow <jr@rushlow.dev>
*/
final class SerializerExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('serialize', [SerializerRuntime::class, 'serialize']),
];
}
}

View File

@ -0,0 +1,33 @@
<?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\Serializer\SerializerInterface;
use Twig\Extension\RuntimeExtensionInterface;
/**
* @author Jesse Rushlow <jr@rushlow.dev>
*/
final class SerializerRuntime implements RuntimeExtensionInterface
{
private $serializer;
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
public function serialize($data, string $format = 'json', array $context = []): string
{
return $this->serializer->serialize($data, $format, $context);
}
}

View File

@ -0,0 +1,54 @@
<?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;
use Twig\TokenParser\TokenParserInterface;
/**
* Twig extension for the stopwatch helper.
*
* @author Wouter J <wouter@wouterj.nl>
*/
final class StopwatchExtension extends AbstractExtension
{
private $stopwatch;
private $enabled;
public function __construct(Stopwatch $stopwatch = null, bool $enabled = true)
{
$this->stopwatch = $stopwatch;
$this->enabled = $enabled;
}
public function getStopwatch(): Stopwatch
{
return $this->stopwatch;
}
/**
* @return TokenParserInterface[]
*/
public function getTokenParsers(): array
{
return [
/*
* {% stopwatch foo %}
* Some stuff which will be recorded on the timeline
* {% endstopwatch %}
*/
new StopwatchTokenParser(null !== $this->stopwatch && $this->enabled),
];
}
}

View File

@ -0,0 +1,145 @@
<?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\TransDefaultDomainTokenParser;
use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
// Help opcache.preload discover always-needed symbols
class_exists(TranslatorInterface::class);
class_exists(TranslatorTrait::class);
/**
* Provides integration of the Translation component with Twig.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class TranslationExtension extends AbstractExtension
{
private $translator;
private $translationNodeVisitor;
public function __construct(TranslatorInterface $translator = null, TranslationNodeVisitor $translationNodeVisitor = null)
{
$this->translator = $translator;
$this->translationNodeVisitor = $translationNodeVisitor;
}
public function getTranslator(): TranslatorInterface
{
if (null === $this->translator) {
if (!interface_exists(TranslatorInterface::class)) {
throw new \LogicException(sprintf('You cannot use the "%s" if the Translation Contracts are not available. Try running "composer require symfony/translation".', __CLASS__));
}
$this->translator = new class() implements TranslatorInterface {
use TranslatorTrait;
};
}
return $this->translator;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('t', [$this, 'createTranslatable']),
];
}
/**
* {@inheritdoc}
*/
public function getFilters(): array
{
return [
new TwigFilter('trans', [$this, 'trans']),
];
}
/**
* {@inheritdoc}
*/
public function getTokenParsers(): array
{
return [
// {% trans %}Symfony is great!{% endtrans %}
new TransTokenParser(),
// {% trans_default_domain "foobar" %}
new TransDefaultDomainTokenParser(),
];
}
/**
* {@inheritdoc}
*/
public function getNodeVisitors(): array
{
return [$this->getTranslationNodeVisitor(), new TranslationDefaultDomainNodeVisitor()];
}
public function getTranslationNodeVisitor(): TranslationNodeVisitor
{
return $this->translationNodeVisitor ?: $this->translationNodeVisitor = new TranslationNodeVisitor();
}
/**
* @param string|\Stringable|TranslatableInterface|null $message
* @param array|string $arguments Can be the locale as a string when $message is a TranslatableInterface
*/
public function trans($message, $arguments = [], string $domain = null, string $locale = null, int $count = null): string
{
if ($message instanceof TranslatableInterface) {
if ([] !== $arguments && !\is_string($arguments)) {
throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be a locale passed as a string when the message is a "%s", "%s" given.', __METHOD__, TranslatableInterface::class, get_debug_type($arguments)));
}
return $message->trans($this->getTranslator(), $locale ?? (\is_string($arguments) ? $arguments : null));
}
if (!\is_array($arguments)) {
throw new \TypeError(sprintf('Unless the message is a "%s", argument 2 passed to "%s()" must be an array of parameters, "%s" given.', TranslatableInterface::class, __METHOD__, get_debug_type($arguments)));
}
if ('' === $message = (string) $message) {
return '';
}
if (null !== $count) {
$arguments['%count%'] = $count;
}
return $this->getTranslator()->trans($message, $arguments, $domain, $locale);
}
public function createTranslatable(string $message, array $parameters = [], string $domain = null): TranslatableMessage
{
if (!class_exists(TranslatableMessage::class)) {
throw new \LogicException(sprintf('You cannot use the "%s" as the Translation Component is not installed. Try running "composer require symfony/translation".', __CLASS__));
}
return new TranslatableMessage($message, $parameters, $domain);
}
}

View File

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

View File

@ -0,0 +1,121 @@
<?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 Symfony\Component\Workflow\TransitionBlockerList;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* WorkflowExtension.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Carlos Pereira De Amorim <carlos@shauri.fr>
*/
final class WorkflowExtension extends AbstractExtension
{
private $workflowRegistry;
public function __construct(Registry $workflowRegistry)
{
$this->workflowRegistry = $workflowRegistry;
}
/**
* {@inheritdoc}
*/
public function getFunctions(): array
{
return [
new TwigFunction('workflow_can', [$this, 'canTransition']),
new TwigFunction('workflow_transitions', [$this, 'getEnabledTransitions']),
new TwigFunction('workflow_transition', [$this, 'getEnabledTransition']),
new TwigFunction('workflow_has_marked_place', [$this, 'hasMarkedPlace']),
new TwigFunction('workflow_marked_places', [$this, 'getMarkedPlaces']),
new TwigFunction('workflow_metadata', [$this, 'getMetadata']),
new TwigFunction('workflow_transition_blockers', [$this, 'buildTransitionBlockerList']),
];
}
/**
* Returns true if the transition is enabled.
*/
public function canTransition(object $subject, string $transitionName, string $name = null): bool
{
return $this->workflowRegistry->get($subject, $name)->can($subject, $transitionName);
}
/**
* Returns all enabled transitions.
*
* @return Transition[]
*/
public function getEnabledTransitions(object $subject, string $name = null): array
{
return $this->workflowRegistry->get($subject, $name)->getEnabledTransitions($subject);
}
public function getEnabledTransition(object $subject, string $transition, string $name = null): ?Transition
{
return $this->workflowRegistry->get($subject, $name)->getEnabledTransition($subject, $transition);
}
/**
* Returns true if the place is marked.
*/
public function hasMarkedPlace(object $subject, string $placeName, string $name = null): bool
{
return $this->workflowRegistry->get($subject, $name)->getMarking($subject)->has($placeName);
}
/**
* Returns marked places.
*
* @return string[]|int[]
*/
public function getMarkedPlaces(object $subject, bool $placesNameOnly = true, string $name = null): array
{
$places = $this->workflowRegistry->get($subject, $name)->getMarking($subject)->getPlaces();
if ($placesNameOnly) {
return array_keys($places);
}
return $places;
}
/**
* Returns the metadata for a specific subject.
*
* @param string|Transition|null $metadataSubject Use null to get workflow metadata
* Use a string (the place name) to get place metadata
* Use a Transition instance to get transition metadata
*/
public function getMetadata(object $subject, string $key, $metadataSubject = null, string $name = null)
{
return $this
->workflowRegistry
->get($subject, $name)
->getMetadataStore()
->getMetadata($key, $metadataSubject)
;
}
public function buildTransitionBlockerList(object $subject, string $transitionName, string $name = null): TransitionBlockerList
{
$workflow = $this->workflowRegistry->get($subject, $name);
return $workflow->buildTransitionBlockerList($subject, $transitionName);
}
}

View File

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