mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-31 04:27:00 +00:00
Merge branch '3.x' into 4.x
* 3.x: Avoid polluting ModuleNode::toString() with embedded templates Simplify code Add tests Tweak Sandbox docs Improve docs on creating new tags remove not needed code Remove obsolete comment
This commit is contained in:
+20
-2
@@ -478,6 +478,7 @@ Now, let's see the actual code of this class::
|
||||
public function parse(\Twig\Token $token): Node
|
||||
{
|
||||
$parser = $this->parser;
|
||||
$lineno = $token->getLine();
|
||||
$stream = $parser->getStream();
|
||||
|
||||
$name = $stream->expect(\Twig\Token::NAME_TYPE)->getValue();
|
||||
@@ -485,7 +486,7 @@ Now, let's see the actual code of this class::
|
||||
$value = $parser->getExpressionParser()->parseExpression();
|
||||
$stream->expect(\Twig\Token::BLOCK_END_TYPE);
|
||||
|
||||
return new CustomSetNode($name, $value, $token->getLine());
|
||||
return new CustomSetNode($name, $value, $lineno);
|
||||
}
|
||||
|
||||
public function getTag(): string
|
||||
@@ -520,6 +521,18 @@ from the token stream (``$this->parser->getStream()``):
|
||||
Parsing expressions is done by calling the ``parseExpression()`` like we did for
|
||||
the ``set`` tag.
|
||||
|
||||
When encountering a syntax error during parsing, throw an exception::
|
||||
|
||||
throw new SyntaxError('Some error message.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
|
||||
|
||||
For better error reporting to the user, follow these recommendations:
|
||||
|
||||
* Use ``\Twig\Error\SyntaxError``;
|
||||
|
||||
* **Always** pass the line number of the node and the source context;
|
||||
|
||||
* End the exception message with a dot.
|
||||
|
||||
.. tip::
|
||||
|
||||
Reading the existing ``TokenParser`` classes is the best way to learn all
|
||||
@@ -564,7 +577,8 @@ developer generate beautiful and readable PHP code:
|
||||
``\Twig\Node\ForNode`` for a usage example).
|
||||
|
||||
* ``addDebugInfo()``: Adds the line of the original template file related to
|
||||
the current node as a comment.
|
||||
the current node as a comment. It's highly recommended to call this method
|
||||
when implementing custom nodes.
|
||||
|
||||
* ``indent()``: Indents the generated code (see ``\Twig\Node\BlockNode`` for a
|
||||
usage example).
|
||||
@@ -572,6 +586,10 @@ developer generate beautiful and readable PHP code:
|
||||
* ``outdent()``: Outdents the generated code (see ``\Twig\Node\BlockNode`` for a
|
||||
usage example).
|
||||
|
||||
For structural nodes, always call ``addDebugInfo()`` early on in the
|
||||
compilation process to improve error reporting to the user in case the code
|
||||
would throw an exception.
|
||||
|
||||
.. _creating_extensions:
|
||||
|
||||
Creating an Extension
|
||||
|
||||
+7
-7
@@ -17,7 +17,7 @@ The sandbox security is managed by a policy instance, which must be passed to
|
||||
the ``SandboxExtension`` constructor.
|
||||
|
||||
By default, Twig comes with one policy class: ``\Twig\Sandbox\SecurityPolicy``.
|
||||
This class allows you to allow-list some tags, filters, functions, but also
|
||||
This class allows you to allow-list some tags, filters, functions, and
|
||||
properties and methods on objects::
|
||||
|
||||
$tags = ['if'];
|
||||
@@ -31,11 +31,11 @@ properties and methods on objects::
|
||||
$functions = ['range'];
|
||||
$policy = new \Twig\Sandbox\SecurityPolicy($tags, $filters, $methods, $properties, $functions);
|
||||
|
||||
With the previous configuration, the security policy will only allow usage of
|
||||
the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be
|
||||
able to call the ``getTitle()`` and ``getBody()`` methods on ``Article``
|
||||
objects, and the ``title`` and ``body`` public properties. Everything else
|
||||
won't be allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.
|
||||
With the above configuration, the security policy will only allow usage of the
|
||||
``if`` tag, and the ``upper`` filter. Moreover, the templates will only be able
|
||||
to call the ``getTitle()`` and ``getBody()`` methods on ``Article`` objects,
|
||||
and the ``title`` and ``body`` public properties. Everything else won't be
|
||||
allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -60,7 +60,7 @@ function:
|
||||
You can sandbox all templates by passing ``true`` as the second argument of
|
||||
the extension constructor::
|
||||
|
||||
$sandbox = new \Twig\Extension\SandboxExtension($policy, true);
|
||||
$twig->addExtension(new \Twig\Extension\SandboxExtension($policy, true));
|
||||
|
||||
Accepting Callables Arguments
|
||||
-----------------------------
|
||||
|
||||
+4
-13
@@ -29,10 +29,7 @@ use Twig\Template;
|
||||
* Whenever possible, you must set these information (original template name
|
||||
* and line number) yourself by passing them to the constructor. If some or all
|
||||
* these information are not available from where you throw the exception, then
|
||||
* this class will guess them automatically (when the line number is set to -1
|
||||
* and/or the name is set to null). As this is a costly operation, this
|
||||
* can be disabled by passing false for both the name and the line number
|
||||
* when creating a new instance of this class.
|
||||
* this class will guess them automatically.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
@@ -142,18 +139,12 @@ class Error extends \Exception
|
||||
|
||||
$this->lineno = 0;
|
||||
$template = null;
|
||||
$templateClass = null;
|
||||
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
foreach ($backtrace as $trace) {
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template) {
|
||||
$currentClass = $trace['object']::class;
|
||||
$isEmbedContainer = null === $templateClass ? false : str_starts_with($templateClass, $currentClass);
|
||||
if ($this->source->getName() === $trace['object']->getTemplateName() && !$isEmbedContainer) {
|
||||
$template = $trace['object'];
|
||||
$templateClass = $trace['object']::class;
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template && $this->source->getName() === $trace['object']->getTemplateName()) {
|
||||
$template = $trace['object'];
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@ final class ModuleNode extends Node
|
||||
{
|
||||
public function __construct(BodyNode $body, ?AbstractExpression $parent, Node $blocks, Node $macros, Node $traits, $embeddedTemplates, Source $source)
|
||||
{
|
||||
if (!$embeddedTemplates instanceof Node) {
|
||||
trigger_deprecation('twig/twig', '3.21', \sprintf('Not passing a "%s" instance as the "embedded_templates" argument of the "%s" constructor is deprecated.', Node::class, static::class));
|
||||
|
||||
$embeddedTemplates = new Nodes($embeddedTemplates);
|
||||
}
|
||||
|
||||
$nodes = [
|
||||
'body' => $body,
|
||||
'blocks' => $blocks,
|
||||
|
||||
+9
-1
@@ -127,7 +127,15 @@ class Parser
|
||||
$this->expressionRefs = null;
|
||||
}
|
||||
|
||||
$node = new ModuleNode(new BodyNode([$body]), $this->parent, new Nodes($this->blocks), new Nodes($this->macros), new Nodes($this->traits), $this->embeddedTemplates, $stream->getSourceContext());
|
||||
$node = new ModuleNode(
|
||||
new BodyNode([$body]),
|
||||
$this->parent,
|
||||
$this->blocks ? new Nodes($this->blocks) : new EmptyNode(),
|
||||
$this->macros ? new Nodes($this->macros) : new EmptyNode(),
|
||||
$this->traits ? new Nodes($this->traits) : new EmptyNode(),
|
||||
$this->embeddedTemplates ? new Nodes($this->embeddedTemplates) : new EmptyNode(),
|
||||
$stream->getSourceContext(),
|
||||
);
|
||||
|
||||
$traverser = new NodeTraverser($this->env, $this->visitors);
|
||||
|
||||
|
||||
@@ -413,6 +413,31 @@ EOHTML,
|
||||
],
|
||||
'index', 3,
|
||||
],
|
||||
|
||||
// error occurs in an embed tag
|
||||
[
|
||||
[
|
||||
'index' => "
|
||||
{% embed 'base' %}
|
||||
{% endembed %}",
|
||||
'base' => '{% block foo %}{{ foo.bar }}{% endblock %}',
|
||||
],
|
||||
'base', 1,
|
||||
],
|
||||
|
||||
// error occurs in an overridden block from an embed tag
|
||||
[
|
||||
[
|
||||
'index' => "
|
||||
{% embed 'base' %}
|
||||
{% block foo %}
|
||||
{{ foo.bar }}
|
||||
{% endblock %}
|
||||
{% endembed %}",
|
||||
'base' => '{% block foo %}{% endblock %}',
|
||||
],
|
||||
'index', 4,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user