Skip to content

Commit

Permalink
Refactored the CssSelector to remove the circular object graph
Browse files Browse the repository at this point in the history
This allows the translator and its extensions to be garbage collected
based on the refcount rather than requiring the garbage collector run,
making it much more likely to happen at the end of the
CssSelector::toXPath call.
  • Loading branch information
stof committed Jun 27, 2014
1 parent 803b06b commit 994f81f
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 33 deletions.
Expand Up @@ -24,6 +24,8 @@ interface ExtensionInterface
/**
* Returns node translators.
*
* These callables will receive the node as first argument and the translator as second argument.
*
* @return callable[]
*/
public function getNodeTranslators();
Expand Down
63 changes: 32 additions & 31 deletions src/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
Expand Up @@ -29,11 +29,6 @@ class NodeExtension extends AbstractExtension
const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;

/**
* @var Translator
*/
private $translator;

/**
* @var int
*/
Expand All @@ -42,12 +37,10 @@ class NodeExtension extends AbstractExtension
/**
* Constructor.
*
* @param Translator $translator
* @param int $flags
* @param int $flags
*/
public function __construct(Translator $translator, $flags = 0)
public function __construct($flags = 0)
{
$this->translator = $translator;
$this->flags = $flags;
}

Expand Down Expand Up @@ -100,33 +93,36 @@ public function getNodeTranslators()

/**
* @param Node\SelectorNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateSelector(Node\SelectorNode $node)
public function translateSelector(Node\SelectorNode $node, Translator $translator)
{
return $this->translator->nodeToXPath($node->getTree());
return $translator->nodeToXPath($node->getTree());
}

/**
* @param Node\CombinedSelectorNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateCombinedSelector(Node\CombinedSelectorNode $node)
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
{
return $this->translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
}

/**
* @param Node\NegationNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateNegation(Node\NegationNode $node)
public function translateNegation(Node\NegationNode $node, Translator $translator)
{
$xpath = $this->translator->nodeToXPath($node->getSelector());
$subXpath = $this->translator->nodeToXPath($node->getSubSelector());
$xpath = $translator->nodeToXPath($node->getSelector());
$subXpath = $translator->nodeToXPath($node->getSubSelector());
$subXpath->addNameTest();

if ($subXpath->getCondition()) {
Expand All @@ -138,34 +134,37 @@ public function translateNegation(Node\NegationNode $node)

/**
* @param Node\FunctionNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateFunction(Node\FunctionNode $node)
public function translateFunction(Node\FunctionNode $node, Translator $translator)
{
$xpath = $this->translator->nodeToXPath($node->getSelector());
$xpath = $translator->nodeToXPath($node->getSelector());

return $this->translator->addFunction($xpath, $node);
return $translator->addFunction($xpath, $node);
}

/**
* @param Node\PseudoNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translatePseudo(Node\PseudoNode $node)
public function translatePseudo(Node\PseudoNode $node, Translator $translator)
{
$xpath = $this->translator->nodeToXPath($node->getSelector());
$xpath = $translator->nodeToXPath($node->getSelector());

return $this->translator->addPseudoClass($xpath, $node->getIdentifier());
return $translator->addPseudoClass($xpath, $node->getIdentifier());
}

/**
* @param Node\AttributeNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateAttribute(Node\AttributeNode $node)
public function translateAttribute(Node\AttributeNode $node, Translator $translator)
{
$name = $node->getAttribute();
$safe = $this->isSafeName($name);
Expand All @@ -181,37 +180,39 @@ public function translateAttribute(Node\AttributeNode $node)

$attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
$value = $node->getValue();
$xpath = $this->translator->nodeToXPath($node->getSelector());
$xpath = $translator->nodeToXPath($node->getSelector());

if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
$value = strtolower($value);
}

return $this->translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
}

/**
* @param Node\ClassNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateClass(Node\ClassNode $node)
public function translateClass(Node\ClassNode $node, Translator $translator)
{
$xpath = $this->translator->nodeToXPath($node->getSelector());
$xpath = $translator->nodeToXPath($node->getSelector());

return $this->translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
}

/**
* @param Node\HashNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateHash(Node\HashNode $node)
public function translateHash(Node\HashNode $node, Translator $translator)
{
$xpath = $this->translator->nodeToXPath($node->getSelector());
$xpath = $translator->nodeToXPath($node->getSelector());

return $this->translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/CssSelector/XPath/Translator.php
Expand Up @@ -76,7 +76,7 @@ public function __construct(ParserInterface $parser = null)
$this->mainParser = $parser ?: new Parser();

$this
->registerExtension(new Extension\NodeExtension($this))
->registerExtension(new Extension\NodeExtension())
->registerExtension(new Extension\CombinationExtension())
->registerExtension(new Extension\FunctionExtension())
->registerExtension(new Extension\PseudoClassExtension())
Expand Down Expand Up @@ -207,7 +207,7 @@ public function nodeToXPath(NodeInterface $node)
throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
}

return call_user_func($this->nodeTranslators[$node->getNodeName()], $node);
return call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this);
}

/**
Expand Down

0 comments on commit 994f81f

Please sign in to comment.