laravel-6 support

This commit is contained in:
RafficMohammed
2023-01-08 01:17:22 +05:30
parent 1a5c16ae4b
commit 774eed8b0e
4962 changed files with 279380 additions and 297961 deletions

View File

@@ -26,40 +26,40 @@ abstract class AbstractExtension implements ExtensionInterface
/**
* {@inheritdoc}
*/
public function getNodeTranslators()
public function getNodeTranslators(): array
{
return array();
return [];
}
/**
* {@inheritdoc}
*/
public function getCombinationTranslators()
public function getCombinationTranslators(): array
{
return array();
return [];
}
/**
* {@inheritdoc}
*/
public function getFunctionTranslators()
public function getFunctionTranslators(): array
{
return array();
return [];
}
/**
* {@inheritdoc}
*/
public function getPseudoClassTranslators()
public function getPseudoClassTranslators(): array
{
return array();
return [];
}
/**
* {@inheritdoc}
*/
public function getAttributeMatchingTranslators()
public function getAttributeMatchingTranslators(): array
{
return array();
return [];
}
}

View File

@@ -29,52 +29,31 @@ class AttributeMatchingExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getAttributeMatchingTranslators()
public function getAttributeMatchingTranslators(): array
{
return array(
'exists' => array($this, 'translateExists'),
'=' => array($this, 'translateEquals'),
'~=' => array($this, 'translateIncludes'),
'|=' => array($this, 'translateDashMatch'),
'^=' => array($this, 'translatePrefixMatch'),
'$=' => array($this, 'translateSuffixMatch'),
'*=' => array($this, 'translateSubstringMatch'),
'!=' => array($this, 'translateDifferent'),
);
return [
'exists' => [$this, 'translateExists'],
'=' => [$this, 'translateEquals'],
'~=' => [$this, 'translateIncludes'],
'|=' => [$this, 'translateDashMatch'],
'^=' => [$this, 'translatePrefixMatch'],
'$=' => [$this, 'translateSuffixMatch'],
'*=' => [$this, 'translateSubstringMatch'],
'!=' => [$this, 'translateDifferent'],
];
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateExists(XPathExpr $xpath, $attribute, $value)
public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($attribute);
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateEquals(XPathExpr $xpath, $attribute, $value)
public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value)));
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateIncludes(XPathExpr $xpath, $attribute, $value)
public function translateIncludes(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)',
@@ -83,14 +62,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateDashMatch(XPathExpr $xpath, $attribute, $value)
public function translateDashMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
'%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))',
@@ -100,14 +72,7 @@ class AttributeMatchingExtension extends AbstractExtension
));
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translatePrefixMatch(XPathExpr $xpath, $attribute, $value)
public function translatePrefixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and starts-with(%1$s, %2$s)',
@@ -116,31 +81,17 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateSuffixMatch(XPathExpr $xpath, $attribute, $value)
public function translateSuffixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s',
$attribute,
strlen($value) - 1,
\strlen($value) - 1,
Translator::getXpathLiteral($value)
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateSubstringMatch(XPathExpr $xpath, $attribute, $value)
public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(%1$s, %2$s)',
@@ -149,14 +100,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateDifferent(XPathExpr $xpath, $attribute, $value)
public function translateDifferent(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
$value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s',
@@ -168,7 +112,7 @@ class AttributeMatchingExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'attribute-matching';
}

View File

@@ -28,45 +28,27 @@ class CombinationExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getCombinationTranslators()
public function getCombinationTranslators(): array
{
return array(
' ' => array($this, 'translateDescendant'),
'>' => array($this, 'translateChild'),
'+' => array($this, 'translateDirectAdjacent'),
'~' => array($this, 'translateIndirectAdjacent'),
);
return [
' ' => [$this, 'translateDescendant'],
'>' => [$this, 'translateChild'],
'+' => [$this, 'translateDirectAdjacent'],
'~' => [$this, 'translateIndirectAdjacent'],
];
}
/**
* @param XPathExpr $xpath
* @param XPathExpr $combinedXpath
*
* @return XPathExpr
*/
public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath)
public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/descendant-or-self::*/', $combinedXpath);
}
/**
* @param XPathExpr $xpath
* @param XPathExpr $combinedXpath
*
* @return XPathExpr
*/
public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath)
public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/', $combinedXpath);
}
/**
* @param XPathExpr $xpath
* @param XPathExpr $combinedXpath
*
* @return XPathExpr
*/
public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath
->join('/following-sibling::', $combinedXpath)
@@ -74,13 +56,7 @@ class CombinationExtension extends AbstractExtension
->addCondition('position() = 1');
}
/**
* @param XPathExpr $xpath
* @param XPathExpr $combinedXpath
*
* @return XPathExpr
*/
public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/following-sibling::', $combinedXpath);
}
@@ -88,7 +64,7 @@ class CombinationExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'combination';
}

View File

@@ -30,40 +30,38 @@ interface ExtensionInterface
*
* @return callable[]
*/
public function getNodeTranslators();
public function getNodeTranslators(): array;
/**
* Returns combination translators.
*
* @return callable[]
*/
public function getCombinationTranslators();
public function getCombinationTranslators(): array;
/**
* Returns function translators.
*
* @return callable[]
*/
public function getFunctionTranslators();
public function getFunctionTranslators(): array;
/**
* Returns pseudo-class translators.
*
* @return callable[]
*/
public function getPseudoClassTranslators();
public function getPseudoClassTranslators(): array;
/**
* Returns attribute operation translators.
*
* @return callable[]
*/
public function getAttributeMatchingTranslators();
public function getAttributeMatchingTranslators(): array;
/**
* Returns extension name.
*
* @return string
*/
public function getName();
public function getName(): string;
}

View File

@@ -33,34 +33,27 @@ class FunctionExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getFunctionTranslators()
public function getFunctionTranslators(): array
{
return array(
'nth-child' => array($this, 'translateNthChild'),
'nth-last-child' => array($this, 'translateNthLastChild'),
'nth-of-type' => array($this, 'translateNthOfType'),
'nth-last-of-type' => array($this, 'translateNthLastOfType'),
'contains' => array($this, 'translateContains'),
'lang' => array($this, 'translateLang'),
);
return [
'nth-child' => [$this, 'translateNthChild'],
'nth-last-child' => [$this, 'translateNthLastChild'],
'nth-of-type' => [$this, 'translateNthOfType'],
'nth-last-of-type' => [$this, 'translateNthLastOfType'],
'contains' => [$this, 'translateContains'],
'lang' => [$this, 'translateLang'],
];
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
* @param bool $last
* @param bool $addNameTest
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true)
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
{
try {
list($a, $b) = Parser::parseSeries($function->getArguments());
[$a, $b] = Parser::parseSeries($function->getArguments());
} catch (SyntaxErrorException $e) {
throw new ExpressionErrorException(sprintf('Invalid series: %s', implode(', ', $function->getArguments())), 0, $e);
throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e);
}
$xpath->addStarPrefix();
@@ -93,7 +86,7 @@ class FunctionExtension extends AbstractExtension
$expr .= ' - '.$b;
}
$conditions = array(sprintf('%s %s 0', $expr, $sign));
$conditions = [sprintf('%s %s 0', $expr, $sign)];
if (1 !== $a && -1 !== $a) {
$conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
@@ -110,37 +103,20 @@ class FunctionExtension extends AbstractExtension
// -1n+6 means elements 6 and previous
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*/
public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function)
public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, true);
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*/
public function translateNthOfType(XPathExpr $xpath, FunctionNode $function)
public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, false, false);
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function)
public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
@@ -150,22 +126,14 @@ class FunctionExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateContains(XPathExpr $xpath, FunctionNode $function)
public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException(
'Expected a single string or identifier for :contains(), got '
.implode(', ', $arguments)
);
throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
}
}
@@ -176,22 +144,14 @@ class FunctionExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateLang(XPathExpr $xpath, FunctionNode $function)
public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException(
'Expected a single string or identifier for :lang(), got '
.implode(', ', $arguments)
);
throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
}
}
@@ -204,7 +164,7 @@ class FunctionExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'function';
}

View File

@@ -28,11 +28,6 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
*/
class HtmlExtension extends AbstractExtension
{
/**
* Constructor.
*
* @param Translator $translator
*/
public function __construct(Translator $translator)
{
$translator
@@ -44,36 +39,31 @@ class HtmlExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getPseudoClassTranslators()
public function getPseudoClassTranslators(): array
{
return array(
'checked' => array($this, 'translateChecked'),
'link' => array($this, 'translateLink'),
'disabled' => array($this, 'translateDisabled'),
'enabled' => array($this, 'translateEnabled'),
'selected' => array($this, 'translateSelected'),
'invalid' => array($this, 'translateInvalid'),
'hover' => array($this, 'translateHover'),
'visited' => array($this, 'translateVisited'),
);
return [
'checked' => [$this, 'translateChecked'],
'link' => [$this, 'translateLink'],
'disabled' => [$this, 'translateDisabled'],
'enabled' => [$this, 'translateEnabled'],
'selected' => [$this, 'translateSelected'],
'invalid' => [$this, 'translateInvalid'],
'hover' => [$this, 'translateHover'],
'visited' => [$this, 'translateVisited'],
];
}
/**
* {@inheritdoc}
*/
public function getFunctionTranslators()
public function getFunctionTranslators(): array
{
return array(
'lang' => array($this, 'translateLang'),
);
return [
'lang' => [$this, 'translateLang'],
];
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateChecked(XPathExpr $xpath)
public function translateChecked(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'(@checked '
@@ -82,22 +72,12 @@ class HtmlExtension extends AbstractExtension
);
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateLink(XPathExpr $xpath)
public function translateLink(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateDisabled(XPathExpr $xpath)
public function translateDisabled(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'('
@@ -123,12 +103,7 @@ class HtmlExtension extends AbstractExtension
// todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateEnabled(XPathExpr $xpath)
public function translateEnabled(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'('
@@ -162,22 +137,14 @@ class HtmlExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateLang(XPathExpr $xpath, FunctionNode $function)
public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException(
'Expected a single string or identifier for :lang(), got '
.implode(', ', $arguments)
);
throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
}
}
@@ -190,42 +157,22 @@ class HtmlExtension extends AbstractExtension
));
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateSelected(XPathExpr $xpath)
public function translateSelected(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition("(@selected and name(.) = 'option')");
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateInvalid(XPathExpr $xpath)
public function translateInvalid(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateHover(XPathExpr $xpath)
public function translateHover(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateVisited(XPathExpr $xpath)
public function translateVisited(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}
@@ -233,7 +180,7 @@ class HtmlExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'html';
}

View File

@@ -27,32 +27,21 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
*/
class NodeExtension extends AbstractExtension
{
const ELEMENT_NAME_IN_LOWER_CASE = 1;
const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
public const ELEMENT_NAME_IN_LOWER_CASE = 1;
public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
/**
* @var int
*/
private $flags;
/**
* Constructor.
*
* @param int $flags
*/
public function __construct($flags = 0)
public function __construct(int $flags = 0)
{
$this->flags = $flags;
}
/**
* @param int $flag
* @param bool $on
*
* @return $this
*/
public function setFlag($flag, $on)
public function setFlag(int $flag, bool $on): self
{
if ($on && !$this->hasFlag($flag)) {
$this->flags += $flag;
@@ -65,63 +54,40 @@ class NodeExtension extends AbstractExtension
return $this;
}
/**
* @param int $flag
*
* @return bool
*/
public function hasFlag($flag)
public function hasFlag(int $flag): bool
{
return $this->flags & $flag;
return (bool) ($this->flags & $flag);
}
/**
* {@inheritdoc}
*/
public function getNodeTranslators()
public function getNodeTranslators(): array
{
return array(
'Selector' => array($this, 'translateSelector'),
'CombinedSelector' => array($this, 'translateCombinedSelector'),
'Negation' => array($this, 'translateNegation'),
'Function' => array($this, 'translateFunction'),
'Pseudo' => array($this, 'translatePseudo'),
'Attribute' => array($this, 'translateAttribute'),
'Class' => array($this, 'translateClass'),
'Hash' => array($this, 'translateHash'),
'Element' => array($this, 'translateElement'),
);
return [
'Selector' => [$this, 'translateSelector'],
'CombinedSelector' => [$this, 'translateCombinedSelector'],
'Negation' => [$this, 'translateNegation'],
'Function' => [$this, 'translateFunction'],
'Pseudo' => [$this, 'translatePseudo'],
'Attribute' => [$this, 'translateAttribute'],
'Class' => [$this, 'translateClass'],
'Hash' => [$this, 'translateHash'],
'Element' => [$this, 'translateElement'],
];
}
/**
* @param Node\SelectorNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateSelector(Node\SelectorNode $node, Translator $translator)
public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
{
return $translator->nodeToXPath($node->getTree());
}
/**
* @param Node\CombinedSelectorNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
{
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
}
/**
* @param Node\NegationNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateNegation(Node\NegationNode $node, Translator $translator)
public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
$subXpath = $translator->nodeToXPath($node->getSubSelector());
@@ -134,39 +100,21 @@ class NodeExtension extends AbstractExtension
return $xpath->addCondition('0');
}
/**
* @param Node\FunctionNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateFunction(Node\FunctionNode $node, Translator $translator)
public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addFunction($xpath, $node);
}
/**
* @param Node\PseudoNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translatePseudo(Node\PseudoNode $node, Translator $translator)
public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addPseudoClass($xpath, $node->getIdentifier());
}
/**
* @param Node\AttributeNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateAttribute(Node\AttributeNode $node, Translator $translator)
public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
{
$name = $node->getAttribute();
$safe = $this->isSafeName($name);
@@ -191,42 +139,25 @@ class NodeExtension extends AbstractExtension
return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
}
/**
* @param Node\ClassNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateClass(Node\ClassNode $node, Translator $translator)
public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
}
/**
* @param Node\HashNode $node
* @param Translator $translator
*
* @return XPathExpr
*/
public function translateHash(Node\HashNode $node, Translator $translator)
public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
}
/**
* @param Node\ElementNode $node
*
* @return XPathExpr
*/
public function translateElement(Node\ElementNode $node)
public function translateElement(Node\ElementNode $node): XPathExpr
{
$element = $node->getElement();
if ($this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
$element = strtolower($element);
}
@@ -254,19 +185,12 @@ class NodeExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'node';
}
/**
* Tests if given name is safe.
*
* @param string $name
*
* @return bool
*/
private function isSafeName($name)
private function isSafeName(string $name): bool
{
return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
}

View File

@@ -29,36 +29,26 @@ class PseudoClassExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getPseudoClassTranslators()
public function getPseudoClassTranslators(): array
{
return array(
'root' => array($this, 'translateRoot'),
'first-child' => array($this, 'translateFirstChild'),
'last-child' => array($this, 'translateLastChild'),
'first-of-type' => array($this, 'translateFirstOfType'),
'last-of-type' => array($this, 'translateLastOfType'),
'only-child' => array($this, 'translateOnlyChild'),
'only-of-type' => array($this, 'translateOnlyOfType'),
'empty' => array($this, 'translateEmpty'),
);
return [
'root' => [$this, 'translateRoot'],
'first-child' => [$this, 'translateFirstChild'],
'last-child' => [$this, 'translateLastChild'],
'first-of-type' => [$this, 'translateFirstOfType'],
'last-of-type' => [$this, 'translateLastOfType'],
'only-child' => [$this, 'translateOnlyChild'],
'only-of-type' => [$this, 'translateOnlyOfType'],
'empty' => [$this, 'translateEmpty'],
];
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateRoot(XPathExpr $xpath)
public function translateRoot(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('not(parent::*)');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateFirstChild(XPathExpr $xpath)
public function translateFirstChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
@@ -66,12 +56,7 @@ class PseudoClassExtension extends AbstractExtension
->addCondition('position() = 1');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateLastChild(XPathExpr $xpath)
public function translateLastChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
@@ -80,13 +65,9 @@ class PseudoClassExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateFirstOfType(XPathExpr $xpath)
public function translateFirstOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
@@ -98,13 +79,9 @@ class PseudoClassExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateLastOfType(XPathExpr $xpath)
public function translateLastOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
@@ -115,12 +92,7 @@ class PseudoClassExtension extends AbstractExtension
->addCondition('position() = last()');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateOnlyChild(XPathExpr $xpath)
public function translateOnlyChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
@@ -128,28 +100,14 @@ class PseudoClassExtension extends AbstractExtension
->addCondition('last() = 1');
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateOnlyOfType(XPathExpr $xpath)
public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
}
$element = $xpath->getElement();
return $xpath->addCondition('last() = 1');
return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
}
/**
* @param XPathExpr $xpath
*
* @return XPathExpr
*/
public function translateEmpty(XPathExpr $xpath)
public function translateEmpty(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('not(*) and not(string-length())');
}
@@ -157,7 +115,7 @@ class PseudoClassExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'pseudo-class';
}

View File

@@ -30,49 +30,27 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
*/
class Translator implements TranslatorInterface
{
/**
* @var ParserInterface
*/
private $mainParser;
/**
* @var ParserInterface[]
*/
private $shortcutParsers = array();
private $shortcutParsers = [];
/**
* @var Extension\ExtensionInterface
* @var Extension\ExtensionInterface[]
*/
private $extensions = array();
private $extensions = [];
/**
* @var array
*/
private $nodeTranslators = array();
/**
* @var array
*/
private $combinationTranslators = array();
/**
* @var array
*/
private $functionTranslators = array();
/**
* @var array
*/
private $pseudoClassTranslators = array();
/**
* @var array
*/
private $attributeMatchingTranslators = array();
private $nodeTranslators = [];
private $combinationTranslators = [];
private $functionTranslators = [];
private $pseudoClassTranslators = [];
private $attributeMatchingTranslators = [];
public function __construct(ParserInterface $parser = null)
{
$this->mainParser = $parser ?: new Parser();
$this->mainParser = $parser ?? new Parser();
$this
->registerExtension(new Extension\NodeExtension())
@@ -83,23 +61,18 @@ class Translator implements TranslatorInterface
;
}
/**
* @param string $element
*
* @return string
*/
public static function getXpathLiteral($element)
public static function getXpathLiteral(string $element): string
{
if (false === strpos($element, "'")) {
if (!str_contains($element, "'")) {
return "'".$element."'";
}
if (false === strpos($element, '"')) {
if (!str_contains($element, '"')) {
return '"'.$element.'"';
}
$string = $element;
$parts = array();
$parts = [];
while (true) {
if (false !== $pos = strpos($string, "'")) {
$parts[] = sprintf("'%s'", substr($string, 0, $pos));
@@ -111,13 +84,13 @@ class Translator implements TranslatorInterface
}
}
return sprintf('concat(%s)', implode($parts, ', '));
return sprintf('concat(%s)', implode(', ', $parts));
}
/**
* {@inheritdoc}
*/
public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::')
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
{
$selectors = $this->parseSelectors($cssExpr);
@@ -136,19 +109,15 @@ class Translator implements TranslatorInterface
/**
* {@inheritdoc}
*/
public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::')
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
{
return ($prefix ?: '').$this->nodeToXPath($selector);
}
/**
* Registers an extension.
*
* @param Extension\ExtensionInterface $extension
*
* @return $this
*/
public function registerExtension(Extension\ExtensionInterface $extension)
public function registerExtension(Extension\ExtensionInterface $extension): self
{
$this->extensions[$extension->getName()] = $extension;
@@ -162,13 +131,9 @@ class Translator implements TranslatorInterface
}
/**
* @param string $name
*
* @return Extension\ExtensionInterface
*
* @throws ExpressionErrorException
*/
public function getExtension($name)
public function getExtension(string $name): Extension\ExtensionInterface
{
if (!isset($this->extensions[$name])) {
throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
@@ -178,13 +143,9 @@ class Translator implements TranslatorInterface
}
/**
* Registers a shortcut parser.
*
* @param ParserInterface $shortcut
*
* @return $this
*/
public function registerParserShortcut(ParserInterface $shortcut)
public function registerParserShortcut(ParserInterface $shortcut): self
{
$this->shortcutParsers[] = $shortcut;
@@ -192,98 +153,69 @@ class Translator implements TranslatorInterface
}
/**
* @param NodeInterface $node
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function nodeToXPath(NodeInterface $node)
public function nodeToXPath(NodeInterface $node): XPathExpr
{
if (!isset($this->nodeTranslators[$node->getNodeName()])) {
throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
}
return call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this);
return $this->nodeTranslators[$node->getNodeName()]($node, $this);
}
/**
* @param string $combiner
* @param NodeInterface $xpath
* @param NodeInterface $combinedXpath
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addCombination($combiner, NodeInterface $xpath, NodeInterface $combinedXpath)
public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
{
if (!isset($this->combinationTranslators[$combiner])) {
throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
}
return call_user_func($this->combinationTranslators[$combiner], $this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addFunction(XPathExpr $xpath, FunctionNode $function)
public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if (!isset($this->functionTranslators[$function->getName()])) {
throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
}
return call_user_func($this->functionTranslators[$function->getName()], $xpath, $function);
return $this->functionTranslators[$function->getName()]($xpath, $function);
}
/**
* @param XPathExpr $xpath
* @param string $pseudoClass
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addPseudoClass(XPathExpr $xpath, $pseudoClass)
public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
{
if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
}
return call_user_func($this->pseudoClassTranslators[$pseudoClass], $xpath);
return $this->pseudoClassTranslators[$pseudoClass]($xpath);
}
/**
* @param XPathExpr $xpath
* @param string $operator
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addAttributeMatching(XPathExpr $xpath, $operator, $attribute, $value)
public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, $value): XPathExpr
{
if (!isset($this->attributeMatchingTranslators[$operator])) {
throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
}
return call_user_func($this->attributeMatchingTranslators[$operator], $xpath, $attribute, $value);
return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
}
/**
* @param string $css
*
* @return SelectorNode[]
*/
private function parseSelectors($css)
private function parseSelectors(string $css): array
{
foreach ($this->shortcutParsers as $shortcut) {
$tokens = $shortcut->parse($css);

View File

@@ -27,21 +27,11 @@ interface TranslatorInterface
{
/**
* Translates a CSS selector to an XPath expression.
*
* @param string $cssExpr
* @param string $prefix
*
* @return string
*/
public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::');
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string;
/**
* Translates a parsed selector node to an XPath expression.
*
* @param SelectorNode $selector
* @param string $prefix
*
* @return string
*/
public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::');
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string;
}

View File

@@ -23,28 +23,11 @@ namespace Symfony\Component\CssSelector\XPath;
*/
class XPathExpr
{
/**
* @var string
*/
private $path;
/**
* @var string
*/
private $element;
/**
* @var string
*/
private $condition;
/**
* @param string $path
* @param string $element
* @param string $condition
* @param bool $starPrefix
*/
public function __construct($path = '', $element = '*', $condition = '', $starPrefix = false)
public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
{
$this->path = $path;
$this->element = $element;
@@ -55,38 +38,24 @@ class XPathExpr
}
}
/**
* @return string
*/
public function getElement()
public function getElement(): string
{
return $this->element;
}
/**
* @param $condition
*
* @return $this
*/
public function addCondition($condition)
public function addCondition(string $condition): self
{
$this->condition = $this->condition ? sprintf('%s and (%s)', $this->condition, $condition) : $condition;
$this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
return $this;
}
/**
* @return string
*/
public function getCondition()
public function getCondition(): string
{
return $this->condition;
}
/**
* @return $this
*/
public function addNameTest()
public function addNameTest(): self
{
if ('*' !== $this->element) {
$this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
@@ -96,10 +65,7 @@ class XPathExpr
return $this;
}
/**
* @return $this
*/
public function addStarPrefix()
public function addStarPrefix(): self
{
$this->path .= '*/';
@@ -109,12 +75,9 @@ class XPathExpr
/**
* Joins another XPathExpr with a combiner.
*
* @param string $combiner
* @param XPathExpr $expr
*
* @return $this
*/
public function join($combiner, XPathExpr $expr)
public function join(string $combiner, self $expr): self
{
$path = $this->__toString().$combiner;
@@ -129,10 +92,7 @@ class XPathExpr
return $this;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$path = $this->path.$this->element;
$condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';