merged branch jfsimon/issue-6747 (PR #7281)

This PR was squashed before being merged into the 2.1 branch (closes #7281).

Commits
-------

e3547c6 [TwigBridge] fixes

Discussion
----------

[TwigBridge] fixes `TranslationDefaultDomainNodeVisitor`

... by adding scope management.

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #6747

---------------------------------------------------------------------------

by vicb at 2013-03-06T15:14:57Z

Are `open` and `close` good names ? I would prefer `addChild` and `getParent` as there is nothing that is really opened or closed ?

Edit: by looking at the code a second time, I think open & close make sense .

---------------------------------------------------------------------------

by jfsimon at 2013-03-07T13:46:13Z

@vicb I know this is not consistent with the rest of the framework.
I dont think @fabpot will like them.

---------------------------------------------------------------------------

by stof at 2013-03-07T13:53:14Z

what about enter and leave ? It would be consistent with the naming used for scopes in the DI component

---------------------------------------------------------------------------

by vicb at 2013-03-07T13:59:35Z

@stof I like your proposal. My main concern being "leave" (former "close"), @jfsimon could you throw when a scope is used after it has been left ?

---------------------------------------------------------------------------

by jfsimon at 2013-03-07T14:01:56Z

go for enter/leave, but why throwing an exception on using a leaved scope?

---------------------------------------------------------------------------

by vicb at 2013-03-07T14:05:22Z

because if you have a ref to a left scope, you can still use it which is bad
This commit is contained in:
Fabien Potencier 2013-03-12 11:55:49 +01:00
commit e508ecc729
2 changed files with 151 additions and 7 deletions

View File

@ -0,0 +1,125 @@
<?php
namespace Symfony\Bridge\Twig\NodeVisitor;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*/
class Scope
{
/**
* @var Scope|null
*/
private $parent;
/**
* @var Scope[]
*/
private $children;
/**
* @var array
*/
private $data;
/**
* @var boolean
*/
private $left;
/**
* @param Scope $parent
*/
public function __construct(Scope $parent = null)
{
$this->parent = $parent;
$this->left = false;
}
/**
* Opens a new child scope.
*
* @return Scope
*/
public function enter()
{
$child = new self($this);
$this->children[] = $child;
return $child;
}
/**
* Closes current scope and returns parent one.
*
* @return Scope|null
*/
public function leave()
{
$this->left = true;
return $this->parent;
}
/**
* Stores data into current scope.
*
* @param string $key
* @param mixed $value
*
* @throws \LogicException
*
* @return Scope Current scope
*/
public function set($key, $value)
{
if ($this->left) {
throw new \LogicException('Left scope is not mutable.');
}
$this->data[$key] = $value;
return $this;
}
/**
* Tests if a data is visible from current scope.
*
* @param string $key
*
* @return boolean
*/
public function has($key)
{
if (array_key_exists($key, $this->data)) {
return true;
}
if (null === $this->parent) {
return false;
}
return $this->parent->has($key);
}
/**
* Returns data visible from current scope.
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function get($key, $default = null)
{
if (array_key_exists($key, $this->data)) {
return $this->data[$key];
}
if (null === $this->parent) {
return $default;
}
return $this->parent->get($key, $default);
}
}

View File

@ -21,32 +21,47 @@ use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
*/
class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
{
private $domain;
/**
* @var Scope
*/
private $scope;
/**
* Constructor.
*/
public function __construct()
{
$this->scope = new Scope();
}
/**
* {@inheritdoc}
*/
public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
{
if ($node instanceof \Twig_Node_Block) {
$this->scope = $this->scope->enter();
}
if ($node instanceof \Twig_Node_Module) {
$this->domain = null;
$this->scope->set('domain', null);
}
if ($node instanceof TransDefaultDomainNode) {
if ($node->getNode('expr') instanceof \Twig_Node_Expression_Constant) {
$this->domain = $node->getNode('expr');
$this->scope->set('domain', $node->getNode('expr'));
return $node;
} else {
$var = $env->getParser()->getVarName();
$name = new \Twig_Node_Expression_AssignName($var, $node->getLine());
$this->domain = new \Twig_Node_Expression_Name($var, $node->getLine());
$this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getLine()));
return new \Twig_Node_Set(false, new \Twig_Node(array($name)), new \Twig_Node(array($node->getNode('expr'))), $node->getLine());
}
}
if (null === $this->domain) {
if (!$this->scope->has('domain')) {
return $node;
}
@ -58,11 +73,11 @@ class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
$arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine()));
}
$arguments->setNode($ind, $this->domain);
$arguments->setNode($ind, $this->scope->get('domain'));
}
} elseif ($node instanceof TransNode) {
if (null === $node->getNode('domain')) {
$node->setNode('domain', $this->domain);
$node->setNode('domain', $this->scope->get('domain'));
}
}
@ -78,6 +93,10 @@ class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
return false;
}
if ($node instanceof \Twig_Node_Block) {
$this->scope = $this->scope->leave();
}
return $node;
}