init
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Translator;
|
||||
class CssSelectorConverter
|
||||
{
|
||||
private $translator;
|
||||
private $cache;
|
||||
private static $xmlCache = [];
|
||||
private static $htmlCache = [];
|
||||
public function __construct(bool $html = \true)
|
||||
{
|
||||
$this->translator = new Translator();
|
||||
if ($html) {
|
||||
$this->translator->registerExtension(new HtmlExtension($this->translator));
|
||||
$this->cache =& self::$htmlCache;
|
||||
} else {
|
||||
$this->cache =& self::$xmlCache;
|
||||
}
|
||||
$this->translator->registerParserShortcut(new EmptyStringParser())->registerParserShortcut(new ElementParser())->registerParserShortcut(new ClassParser())->registerParserShortcut(new HashParser());
|
||||
}
|
||||
public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::')
|
||||
{
|
||||
return $this->cache[$prefix][$cssExpr] ?? ($this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix));
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ExpressionErrorException extends ParseException
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class InternalErrorException extends ParseException
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ParseException extends \Exception implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
class SyntaxErrorException extends ParseException
|
||||
{
|
||||
public static function unexpectedToken(string $expectedValue, Token $foundToken)
|
||||
{
|
||||
return new self(\sprintf('Expected %s, but %s found.', $expectedValue, $foundToken));
|
||||
}
|
||||
public static function pseudoElementFound(string $pseudoElement, string $unexpectedLocation)
|
||||
{
|
||||
return new self(\sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
|
||||
}
|
||||
public static function unclosedString(int $position)
|
||||
{
|
||||
return new self(\sprintf('Unclosed/invalid string at %s.', $position));
|
||||
}
|
||||
public static function nestedNot()
|
||||
{
|
||||
return new self('Got nested ::not().');
|
||||
}
|
||||
public static function stringAsFunctionArgument()
|
||||
{
|
||||
return new self('String not allowed as function argument.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
abstract class AbstractNode implements NodeInterface
|
||||
{
|
||||
private $nodeName;
|
||||
public function getNodeName() : string
|
||||
{
|
||||
if (null === $this->nodeName) {
|
||||
$this->nodeName = \preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class);
|
||||
}
|
||||
return $this->nodeName;
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class AttributeNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $namespace;
|
||||
private $attribute;
|
||||
private $operator;
|
||||
private $value;
|
||||
public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->namespace = $namespace;
|
||||
$this->attribute = $attribute;
|
||||
$this->operator = $operator;
|
||||
$this->value = $value;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getNamespace() : ?string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
public function getAttribute() : string
|
||||
{
|
||||
return $this->attribute;
|
||||
}
|
||||
public function getOperator() : string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
public function getValue() : ?string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$attribute = $this->namespace ? $this->namespace . '|' . $this->attribute : $this->attribute;
|
||||
return 'exists' === $this->operator ? \sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute) : \sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ClassNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $name;
|
||||
public function __construct(NodeInterface $selector, string $name)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->name = $name;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return \sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class CombinedSelectorNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $combinator;
|
||||
private $subSelector;
|
||||
public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->combinator = $combinator;
|
||||
$this->subSelector = $subSelector;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getCombinator() : string
|
||||
{
|
||||
return $this->combinator;
|
||||
}
|
||||
public function getSubSelector() : NodeInterface
|
||||
{
|
||||
return $this->subSelector;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator;
|
||||
return \sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ElementNode extends AbstractNode
|
||||
{
|
||||
private $namespace;
|
||||
private $element;
|
||||
public function __construct(?string $namespace = null, ?string $element = null)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->element = $element;
|
||||
}
|
||||
public function getNamespace() : ?string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
public function getElement() : ?string
|
||||
{
|
||||
return $this->element;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return new Specificity(0, 0, $this->element ? 1 : 0);
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$element = $this->element ?: '*';
|
||||
return \sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace . '|' . $element : $element);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
class FunctionNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $name;
|
||||
private $arguments;
|
||||
public function __construct(NodeInterface $selector, string $name, array $arguments = [])
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->name = \strtolower($name);
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
public function getArguments() : array
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$arguments = \implode(', ', \array_map(function (Token $token) {
|
||||
return "'" . $token->getValue() . "'";
|
||||
}, $this->arguments));
|
||||
return \sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '[' . $arguments . ']' : '');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class HashNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $id;
|
||||
public function __construct(NodeInterface $selector, string $id)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->id = $id;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getId() : string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return \sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class NegationNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $subSelector;
|
||||
public function __construct(NodeInterface $selector, NodeInterface $subSelector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->subSelector = $subSelector;
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getSubSelector() : NodeInterface
|
||||
{
|
||||
return $this->subSelector;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return \sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface NodeInterface
|
||||
{
|
||||
public function getNodeName() : string;
|
||||
public function getSpecificity() : Specificity;
|
||||
public function __toString() : string;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class PseudoNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $identifier;
|
||||
public function __construct(NodeInterface $selector, string $identifier)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->identifier = \strtolower($identifier);
|
||||
}
|
||||
public function getSelector() : NodeInterface
|
||||
{
|
||||
return $this->selector;
|
||||
}
|
||||
public function getIdentifier() : string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return \sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class SelectorNode extends AbstractNode
|
||||
{
|
||||
private $tree;
|
||||
private $pseudoElement;
|
||||
public function __construct(NodeInterface $tree, ?string $pseudoElement = null)
|
||||
{
|
||||
$this->tree = $tree;
|
||||
$this->pseudoElement = $pseudoElement ? \strtolower($pseudoElement) : null;
|
||||
}
|
||||
public function getTree() : NodeInterface
|
||||
{
|
||||
return $this->tree;
|
||||
}
|
||||
public function getPseudoElement() : ?string
|
||||
{
|
||||
return $this->pseudoElement;
|
||||
}
|
||||
public function getSpecificity() : Specificity
|
||||
{
|
||||
return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return \sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::' . $this->pseudoElement : '');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class Specificity
|
||||
{
|
||||
public const A_FACTOR = 100;
|
||||
public const B_FACTOR = 10;
|
||||
public const C_FACTOR = 1;
|
||||
private $a;
|
||||
private $b;
|
||||
private $c;
|
||||
public function __construct(int $a, int $b, int $c)
|
||||
{
|
||||
$this->a = $a;
|
||||
$this->b = $b;
|
||||
$this->c = $c;
|
||||
}
|
||||
public function plus(self $specificity) : self
|
||||
{
|
||||
return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
|
||||
}
|
||||
public function getValue() : int
|
||||
{
|
||||
return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
|
||||
}
|
||||
public function compareTo(self $specificity) : int
|
||||
{
|
||||
if ($this->a !== $specificity->a) {
|
||||
return $this->a > $specificity->a ? 1 : -1;
|
||||
}
|
||||
if ($this->b !== $specificity->b) {
|
||||
return $this->b > $specificity->b ? 1 : -1;
|
||||
}
|
||||
if ($this->c !== $specificity->c) {
|
||||
return $this->c > $specificity->c ? 1 : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class CommentHandler implements HandlerInterface
|
||||
{
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
if ('/*' !== $reader->getSubstring(2)) {
|
||||
return \false;
|
||||
}
|
||||
$offset = $reader->getOffset('*/');
|
||||
if (\false === $offset) {
|
||||
$reader->moveToEnd();
|
||||
} else {
|
||||
$reader->moveForward($offset + 2);
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
interface HandlerInterface
|
||||
{
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class HashHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
}
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getHashPattern());
|
||||
if (!$match) {
|
||||
return \false;
|
||||
}
|
||||
$value = $this->escaping->escapeUnicode($match[1]);
|
||||
$stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition()));
|
||||
$reader->moveForward(\strlen($match[0]));
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class IdentifierHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
}
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getIdentifierPattern());
|
||||
if (!$match) {
|
||||
return \false;
|
||||
}
|
||||
$value = $this->escaping->escapeUnicode($match[0]);
|
||||
$stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition()));
|
||||
$reader->moveForward(\strlen($match[0]));
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class NumberHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
public function __construct(TokenizerPatterns $patterns)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
}
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getNumberPattern());
|
||||
if (!$match) {
|
||||
return \false;
|
||||
}
|
||||
$stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition()));
|
||||
$reader->moveForward(\strlen($match[0]));
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\InternalErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class StringHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
}
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
$quote = $reader->getSubstring(1);
|
||||
if (!\in_array($quote, ["'", '"'])) {
|
||||
return \false;
|
||||
}
|
||||
$reader->moveForward(1);
|
||||
$match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote));
|
||||
if (!$match) {
|
||||
throw new InternalErrorException(\sprintf('Should have found at least an empty match at %d.', $reader->getPosition()));
|
||||
}
|
||||
// check unclosed strings
|
||||
if (\strlen($match[0]) === $reader->getRemainingLength()) {
|
||||
throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
|
||||
}
|
||||
// check quotes pairs validity
|
||||
if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) {
|
||||
throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
|
||||
}
|
||||
$string = $this->escaping->escapeUnicodeAndNewLine($match[0]);
|
||||
$stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition()));
|
||||
$reader->moveForward(\strlen($match[0]) + 1);
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class WhitespaceHandler implements HandlerInterface
|
||||
{
|
||||
public function handle(Reader $reader, TokenStream $stream) : bool
|
||||
{
|
||||
$match = $reader->findPattern('~^[ \\t\\r\\n\\f]+~');
|
||||
if (\false === $match) {
|
||||
return \false;
|
||||
}
|
||||
$stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition()));
|
||||
$reader->moveForward(\strlen($match[0]));
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
|
||||
class Parser implements ParserInterface
|
||||
{
|
||||
private $tokenizer;
|
||||
public function __construct(?Tokenizer $tokenizer = null)
|
||||
{
|
||||
$this->tokenizer = $tokenizer ?? new Tokenizer();
|
||||
}
|
||||
public function parse(string $source) : array
|
||||
{
|
||||
$reader = new Reader($source);
|
||||
$stream = $this->tokenizer->tokenize($reader);
|
||||
return $this->parseSelectorList($stream);
|
||||
}
|
||||
public static function parseSeries(array $tokens) : array
|
||||
{
|
||||
foreach ($tokens as $token) {
|
||||
if ($token->isString()) {
|
||||
throw SyntaxErrorException::stringAsFunctionArgument();
|
||||
}
|
||||
}
|
||||
$joined = \trim(\implode('', \array_map(function (Token $token) {
|
||||
return $token->getValue();
|
||||
}, $tokens)));
|
||||
$int = function ($string) {
|
||||
if (!\is_numeric($string)) {
|
||||
throw SyntaxErrorException::stringAsFunctionArgument();
|
||||
}
|
||||
return (int) $string;
|
||||
};
|
||||
switch (\true) {
|
||||
case 'odd' === $joined:
|
||||
return [2, 1];
|
||||
case 'even' === $joined:
|
||||
return [2, 0];
|
||||
case 'n' === $joined:
|
||||
return [1, 0];
|
||||
case !\str_contains($joined, 'n'):
|
||||
return [0, $int($joined)];
|
||||
}
|
||||
$split = \explode('n', $joined);
|
||||
$first = $split[0] ?? null;
|
||||
return [$first ? '-' === $first || '+' === $first ? $int($first . '1') : $int($first) : 1, isset($split[1]) && $split[1] ? $int($split[1]) : 0];
|
||||
}
|
||||
private function parseSelectorList(TokenStream $stream) : array
|
||||
{
|
||||
$stream->skipWhitespace();
|
||||
$selectors = [];
|
||||
while (\true) {
|
||||
$selectors[] = $this->parserSelectorNode($stream);
|
||||
if ($stream->getPeek()->isDelimiter([','])) {
|
||||
$stream->getNext();
|
||||
$stream->skipWhitespace();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $selectors;
|
||||
}
|
||||
private function parserSelectorNode(TokenStream $stream) : Node\SelectorNode
|
||||
{
|
||||
[$result, $pseudoElement] = $this->parseSimpleSelector($stream);
|
||||
while (\true) {
|
||||
$stream->skipWhitespace();
|
||||
$peek = $stream->getPeek();
|
||||
if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
|
||||
break;
|
||||
}
|
||||
if (null !== $pseudoElement) {
|
||||
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
|
||||
}
|
||||
if ($peek->isDelimiter(['+', '>', '~'])) {
|
||||
$combinator = $stream->getNext()->getValue();
|
||||
$stream->skipWhitespace();
|
||||
} else {
|
||||
$combinator = ' ';
|
||||
}
|
||||
[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
|
||||
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
|
||||
}
|
||||
return new Node\SelectorNode($result, $pseudoElement);
|
||||
}
|
||||
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = \false) : array
|
||||
{
|
||||
$stream->skipWhitespace();
|
||||
$selectorStart = \count($stream->getUsed());
|
||||
$result = $this->parseElementNode($stream);
|
||||
$pseudoElement = null;
|
||||
while (\true) {
|
||||
$peek = $stream->getPeek();
|
||||
if ($peek->isWhitespace() || $peek->isFileEnd() || $peek->isDelimiter([',', '+', '>', '~']) || $insideNegation && $peek->isDelimiter([')'])) {
|
||||
break;
|
||||
}
|
||||
if (null !== $pseudoElement) {
|
||||
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
|
||||
}
|
||||
if ($peek->isHash()) {
|
||||
$result = new Node\HashNode($result, $stream->getNext()->getValue());
|
||||
} elseif ($peek->isDelimiter(['.'])) {
|
||||
$stream->getNext();
|
||||
$result = new Node\ClassNode($result, $stream->getNextIdentifier());
|
||||
} elseif ($peek->isDelimiter(['['])) {
|
||||
$stream->getNext();
|
||||
$result = $this->parseAttributeNode($result, $stream);
|
||||
} elseif ($peek->isDelimiter([':'])) {
|
||||
$stream->getNext();
|
||||
if ($stream->getPeek()->isDelimiter([':'])) {
|
||||
$stream->getNext();
|
||||
$pseudoElement = $stream->getNextIdentifier();
|
||||
continue;
|
||||
}
|
||||
$identifier = $stream->getNextIdentifier();
|
||||
if (\in_array(\strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) {
|
||||
// Special case: CSS 2.1 pseudo-elements can have a single ':'.
|
||||
// Any new pseudo-element must have two.
|
||||
$pseudoElement = $identifier;
|
||||
continue;
|
||||
}
|
||||
if (!$stream->getPeek()->isDelimiter(['('])) {
|
||||
$result = new Node\PseudoNode($result, $identifier);
|
||||
continue;
|
||||
}
|
||||
$stream->getNext();
|
||||
$stream->skipWhitespace();
|
||||
if ('not' === \strtolower($identifier)) {
|
||||
if ($insideNegation) {
|
||||
throw SyntaxErrorException::nestedNot();
|
||||
}
|
||||
[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, \true);
|
||||
$next = $stream->getNext();
|
||||
if (null !== $argumentPseudoElement) {
|
||||
throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
|
||||
}
|
||||
if (!$next->isDelimiter([')'])) {
|
||||
throw SyntaxErrorException::unexpectedToken('")"', $next);
|
||||
}
|
||||
$result = new Node\NegationNode($result, $argument);
|
||||
} else {
|
||||
$arguments = [];
|
||||
$next = null;
|
||||
while (\true) {
|
||||
$stream->skipWhitespace();
|
||||
$next = $stream->getNext();
|
||||
if ($next->isIdentifier() || $next->isString() || $next->isNumber() || $next->isDelimiter(['+', '-'])) {
|
||||
$arguments[] = $next;
|
||||
} elseif ($next->isDelimiter([')'])) {
|
||||
break;
|
||||
} else {
|
||||
throw SyntaxErrorException::unexpectedToken('an argument', $next);
|
||||
}
|
||||
}
|
||||
if (empty($arguments)) {
|
||||
throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
|
||||
}
|
||||
$result = new Node\FunctionNode($result, $identifier, $arguments);
|
||||
}
|
||||
} else {
|
||||
throw SyntaxErrorException::unexpectedToken('selector', $peek);
|
||||
}
|
||||
}
|
||||
if (\count($stream->getUsed()) === $selectorStart) {
|
||||
throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
|
||||
}
|
||||
return [$result, $pseudoElement];
|
||||
}
|
||||
private function parseElementNode(TokenStream $stream) : Node\ElementNode
|
||||
{
|
||||
$peek = $stream->getPeek();
|
||||
if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
|
||||
if ($peek->isIdentifier()) {
|
||||
$namespace = $stream->getNext()->getValue();
|
||||
} else {
|
||||
$stream->getNext();
|
||||
$namespace = null;
|
||||
}
|
||||
if ($stream->getPeek()->isDelimiter(['|'])) {
|
||||
$stream->getNext();
|
||||
$element = $stream->getNextIdentifierOrStar();
|
||||
} else {
|
||||
$element = $namespace;
|
||||
$namespace = null;
|
||||
}
|
||||
} else {
|
||||
$element = $namespace = null;
|
||||
}
|
||||
return new Node\ElementNode($namespace, $element);
|
||||
}
|
||||
private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream) : Node\AttributeNode
|
||||
{
|
||||
$stream->skipWhitespace();
|
||||
$attribute = $stream->getNextIdentifierOrStar();
|
||||
if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
|
||||
throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
|
||||
}
|
||||
if ($stream->getPeek()->isDelimiter(['|'])) {
|
||||
$stream->getNext();
|
||||
if ($stream->getPeek()->isDelimiter(['='])) {
|
||||
$namespace = null;
|
||||
$stream->getNext();
|
||||
$operator = '|=';
|
||||
} else {
|
||||
$namespace = $attribute;
|
||||
$attribute = $stream->getNextIdentifier();
|
||||
$operator = null;
|
||||
}
|
||||
} else {
|
||||
$namespace = $operator = null;
|
||||
}
|
||||
if (null === $operator) {
|
||||
$stream->skipWhitespace();
|
||||
$next = $stream->getNext();
|
||||
if ($next->isDelimiter([']'])) {
|
||||
return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
|
||||
} elseif ($next->isDelimiter(['='])) {
|
||||
$operator = '=';
|
||||
} elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!']) && $stream->getPeek()->isDelimiter(['='])) {
|
||||
$operator = $next->getValue() . '=';
|
||||
$stream->getNext();
|
||||
} else {
|
||||
throw SyntaxErrorException::unexpectedToken('operator', $next);
|
||||
}
|
||||
}
|
||||
$stream->skipWhitespace();
|
||||
$value = $stream->getNext();
|
||||
if ($value->isNumber()) {
|
||||
// if the value is a number, it's casted into a string
|
||||
$value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
|
||||
}
|
||||
if (!($value->isIdentifier() || $value->isString())) {
|
||||
throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
|
||||
}
|
||||
$stream->skipWhitespace();
|
||||
$next = $stream->getNext();
|
||||
if (!$next->isDelimiter([']'])) {
|
||||
throw SyntaxErrorException::unexpectedToken('"]"', $next);
|
||||
}
|
||||
return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
interface ParserInterface
|
||||
{
|
||||
public function parse(string $source) : array;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class Reader
|
||||
{
|
||||
private $source;
|
||||
private $length;
|
||||
private $position = 0;
|
||||
public function __construct(string $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
$this->length = \strlen($source);
|
||||
}
|
||||
public function isEOF() : bool
|
||||
{
|
||||
return $this->position >= $this->length;
|
||||
}
|
||||
public function getPosition() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
public function getRemainingLength() : int
|
||||
{
|
||||
return $this->length - $this->position;
|
||||
}
|
||||
public function getSubstring(int $length, int $offset = 0) : string
|
||||
{
|
||||
return \substr($this->source, $this->position + $offset, $length);
|
||||
}
|
||||
public function getOffset(string $string)
|
||||
{
|
||||
$position = \strpos($this->source, $string, $this->position);
|
||||
return \false === $position ? \false : $position - $this->position;
|
||||
}
|
||||
public function findPattern(string $pattern)
|
||||
{
|
||||
$source = \substr($this->source, $this->position);
|
||||
if (\preg_match($pattern, $source, $matches)) {
|
||||
return $matches;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function moveForward(int $length)
|
||||
{
|
||||
$this->position += $length;
|
||||
}
|
||||
public function moveToEnd()
|
||||
{
|
||||
$this->position = $this->length;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\ClassNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\ElementNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
class ClassParser implements ParserInterface
|
||||
{
|
||||
public function parse(string $source) : array
|
||||
{
|
||||
// Matches an optional namespace, optional element, and required class
|
||||
// $source = 'test|input.ab6bd_field';
|
||||
// $matches = array (size=4)
|
||||
// 0 => string 'test|input.ab6bd_field' (length=22)
|
||||
// 1 => string 'test' (length=4)
|
||||
// 2 => string 'input' (length=5)
|
||||
// 3 => string 'ab6bd_field' (length=11)
|
||||
if (\preg_match('/^(?:([a-z]++)\\|)?+([\\w-]++|\\*)?+\\.([\\w-]++)$/i', \trim($source), $matches)) {
|
||||
return [new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3]))];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\ElementNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
class ElementParser implements ParserInterface
|
||||
{
|
||||
public function parse(string $source) : array
|
||||
{
|
||||
// Matches an optional namespace, required element or `*`
|
||||
// $source = 'testns|testel';
|
||||
// $matches = array (size=3)
|
||||
// 0 => string 'testns|testel' (length=13)
|
||||
// 1 => string 'testns' (length=6)
|
||||
// 2 => string 'testel' (length=6)
|
||||
if (\preg_match('/^(?:([a-z]++)\\|)?([\\w-]++|\\*)$/i', \trim($source), $matches)) {
|
||||
return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\ElementNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
class EmptyStringParser implements ParserInterface
|
||||
{
|
||||
public function parse(string $source) : array
|
||||
{
|
||||
// Matches an empty string
|
||||
if ('' == $source) {
|
||||
return [new SelectorNode(new ElementNode(null, '*'))];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Shortcut;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\ElementNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\HashNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
class HashParser implements ParserInterface
|
||||
{
|
||||
public function parse(string $source) : array
|
||||
{
|
||||
// Matches an optional namespace, optional element, and required id
|
||||
// $source = 'test|input#ab6bd_field';
|
||||
// $matches = array (size=4)
|
||||
// 0 => string 'test|input#ab6bd_field' (length=22)
|
||||
// 1 => string 'test' (length=4)
|
||||
// 2 => string 'input' (length=5)
|
||||
// 3 => string 'ab6bd_field' (length=11)
|
||||
if (\preg_match('/^(?:([a-z]++)\\|)?+([\\w-]++|\\*)?+#([\\w-]++)$/i', \trim($source), $matches)) {
|
||||
return [new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3]))];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class Token
|
||||
{
|
||||
public const TYPE_FILE_END = 'eof';
|
||||
public const TYPE_DELIMITER = 'delimiter';
|
||||
public const TYPE_WHITESPACE = 'whitespace';
|
||||
public const TYPE_IDENTIFIER = 'identifier';
|
||||
public const TYPE_HASH = 'hash';
|
||||
public const TYPE_NUMBER = 'number';
|
||||
public const TYPE_STRING = 'string';
|
||||
private $type;
|
||||
private $value;
|
||||
private $position;
|
||||
public function __construct(?string $type, ?string $value, ?int $position)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
$this->position = $position;
|
||||
}
|
||||
public function getType() : ?int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
public function getValue() : ?string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
public function getPosition() : ?int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
public function isFileEnd() : bool
|
||||
{
|
||||
return self::TYPE_FILE_END === $this->type;
|
||||
}
|
||||
public function isDelimiter(array $values = []) : bool
|
||||
{
|
||||
if (self::TYPE_DELIMITER !== $this->type) {
|
||||
return \false;
|
||||
}
|
||||
if (empty($values)) {
|
||||
return \true;
|
||||
}
|
||||
return \in_array($this->value, $values);
|
||||
}
|
||||
public function isWhitespace() : bool
|
||||
{
|
||||
return self::TYPE_WHITESPACE === $this->type;
|
||||
}
|
||||
public function isIdentifier() : bool
|
||||
{
|
||||
return self::TYPE_IDENTIFIER === $this->type;
|
||||
}
|
||||
public function isHash() : bool
|
||||
{
|
||||
return self::TYPE_HASH === $this->type;
|
||||
}
|
||||
public function isNumber() : bool
|
||||
{
|
||||
return self::TYPE_NUMBER === $this->type;
|
||||
}
|
||||
public function isString() : bool
|
||||
{
|
||||
return self::TYPE_STRING === $this->type;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->value) {
|
||||
return \sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);
|
||||
}
|
||||
return \sprintf('<%s at %s>', $this->type, $this->position);
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\InternalErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
|
||||
class TokenStream
|
||||
{
|
||||
private $tokens = [];
|
||||
private $used = [];
|
||||
private $cursor = 0;
|
||||
private $peeked;
|
||||
private $peeking = \false;
|
||||
public function push(Token $token) : self
|
||||
{
|
||||
$this->tokens[] = $token;
|
||||
return $this;
|
||||
}
|
||||
public function freeze() : self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function getNext() : Token
|
||||
{
|
||||
if ($this->peeking) {
|
||||
$this->peeking = \false;
|
||||
$this->used[] = $this->peeked;
|
||||
return $this->peeked;
|
||||
}
|
||||
if (!isset($this->tokens[$this->cursor])) {
|
||||
throw new InternalErrorException('Unexpected token stream end.');
|
||||
}
|
||||
return $this->tokens[$this->cursor++];
|
||||
}
|
||||
public function getPeek() : Token
|
||||
{
|
||||
if (!$this->peeking) {
|
||||
$this->peeked = $this->getNext();
|
||||
$this->peeking = \true;
|
||||
}
|
||||
return $this->peeked;
|
||||
}
|
||||
public function getUsed() : array
|
||||
{
|
||||
return $this->used;
|
||||
}
|
||||
public function getNextIdentifier() : string
|
||||
{
|
||||
$next = $this->getNext();
|
||||
if (!$next->isIdentifier()) {
|
||||
throw SyntaxErrorException::unexpectedToken('identifier', $next);
|
||||
}
|
||||
return $next->getValue();
|
||||
}
|
||||
public function getNextIdentifierOrStar() : ?string
|
||||
{
|
||||
$next = $this->getNext();
|
||||
if ($next->isIdentifier()) {
|
||||
return $next->getValue();
|
||||
}
|
||||
if ($next->isDelimiter(['*'])) {
|
||||
return null;
|
||||
}
|
||||
throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
|
||||
}
|
||||
public function skipWhitespace()
|
||||
{
|
||||
$peek = $this->getPeek();
|
||||
if ($peek->isWhitespace()) {
|
||||
$this->getNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Handler;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Reader;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Token;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
class Tokenizer
|
||||
{
|
||||
private $handlers;
|
||||
public function __construct()
|
||||
{
|
||||
$patterns = new TokenizerPatterns();
|
||||
$escaping = new TokenizerEscaping($patterns);
|
||||
$this->handlers = [new Handler\WhitespaceHandler(), new Handler\IdentifierHandler($patterns, $escaping), new Handler\HashHandler($patterns, $escaping), new Handler\StringHandler($patterns, $escaping), new Handler\NumberHandler($patterns), new Handler\CommentHandler()];
|
||||
}
|
||||
public function tokenize(Reader $reader) : TokenStream
|
||||
{
|
||||
$stream = new TokenStream();
|
||||
while (!$reader->isEOF()) {
|
||||
foreach ($this->handlers as $handler) {
|
||||
if ($handler->handle($reader, $stream)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition()));
|
||||
$reader->moveForward(1);
|
||||
}
|
||||
return $stream->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition()))->freeze();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class TokenizerEscaping
|
||||
{
|
||||
private $patterns;
|
||||
public function __construct(TokenizerPatterns $patterns)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
}
|
||||
public function escapeUnicode(string $value) : string
|
||||
{
|
||||
$value = $this->replaceUnicodeSequences($value);
|
||||
return \preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
|
||||
}
|
||||
public function escapeUnicodeAndNewLine(string $value) : string
|
||||
{
|
||||
$value = \preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
|
||||
return $this->escapeUnicode($value);
|
||||
}
|
||||
private function replaceUnicodeSequences(string $value) : string
|
||||
{
|
||||
return \preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
|
||||
$c = \hexdec($match[1]);
|
||||
if (0x80 > ($c %= 0x200000)) {
|
||||
return \chr($c);
|
||||
}
|
||||
if (0x800 > $c) {
|
||||
return \chr(0xc0 | $c >> 6) . \chr(0x80 | $c & 0x3f);
|
||||
}
|
||||
if (0x10000 > $c) {
|
||||
return \chr(0xe0 | $c >> 12) . \chr(0x80 | $c >> 6 & 0x3f) . \chr(0x80 | $c & 0x3f);
|
||||
}
|
||||
return '';
|
||||
}, $value);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class TokenizerPatterns
|
||||
{
|
||||
private $unicodeEscapePattern;
|
||||
private $simpleEscapePattern;
|
||||
private $newLineEscapePattern;
|
||||
private $escapePattern;
|
||||
private $stringEscapePattern;
|
||||
private $nonAsciiPattern;
|
||||
private $nmCharPattern;
|
||||
private $nmStartPattern;
|
||||
private $identifierPattern;
|
||||
private $hashPattern;
|
||||
private $numberPattern;
|
||||
private $quotedStringPattern;
|
||||
public function __construct()
|
||||
{
|
||||
$this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\\r\\n|[ \\n\\r\\t\\f])?';
|
||||
$this->simpleEscapePattern = '\\\\(.)';
|
||||
$this->newLineEscapePattern = '\\\\(?:\\n|\\r\\n|\\r|\\f)';
|
||||
$this->escapePattern = $this->unicodeEscapePattern . '|\\\\[^\\n\\r\\f0-9a-f]';
|
||||
$this->stringEscapePattern = $this->newLineEscapePattern . '|' . $this->escapePattern;
|
||||
$this->nonAsciiPattern = '[^\\x00-\\x7F]';
|
||||
$this->nmCharPattern = '[_a-z0-9-]|' . $this->escapePattern . '|' . $this->nonAsciiPattern;
|
||||
$this->nmStartPattern = '[_a-z]|' . $this->escapePattern . '|' . $this->nonAsciiPattern;
|
||||
$this->identifierPattern = '-?(?:' . $this->nmStartPattern . ')(?:' . $this->nmCharPattern . ')*';
|
||||
$this->hashPattern = '#((?:' . $this->nmCharPattern . ')+)';
|
||||
$this->numberPattern = '[+-]?(?:[0-9]*\\.[0-9]+|[0-9]+)';
|
||||
$this->quotedStringPattern = '([^\\n\\r\\f\\\\%s]|' . $this->stringEscapePattern . ')*';
|
||||
}
|
||||
public function getNewLineEscapePattern() : string
|
||||
{
|
||||
return '~' . $this->newLineEscapePattern . '~';
|
||||
}
|
||||
public function getSimpleEscapePattern() : string
|
||||
{
|
||||
return '~' . $this->simpleEscapePattern . '~';
|
||||
}
|
||||
public function getUnicodeEscapePattern() : string
|
||||
{
|
||||
return '~' . $this->unicodeEscapePattern . '~i';
|
||||
}
|
||||
public function getIdentifierPattern() : string
|
||||
{
|
||||
return '~^' . $this->identifierPattern . '~i';
|
||||
}
|
||||
public function getHashPattern() : string
|
||||
{
|
||||
return '~^' . $this->hashPattern . '~i';
|
||||
}
|
||||
public function getNumberPattern() : string
|
||||
{
|
||||
return '~^' . $this->numberPattern . '~';
|
||||
}
|
||||
public function getQuotedStringPattern(string $quote) : string
|
||||
{
|
||||
return '~^' . \sprintf($this->quotedStringPattern, $quote) . '~i';
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
abstract class AbstractExtension implements ExtensionInterface
|
||||
{
|
||||
public function getNodeTranslators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
public function getCombinationTranslators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
public function getFunctionTranslators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
public function getPseudoClassTranslators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
public function getAttributeMatchingTranslators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Translator;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class AttributeMatchingExtension extends AbstractExtension
|
||||
{
|
||||
public function getAttributeMatchingTranslators() : array
|
||||
{
|
||||
return ['exists' => [$this, 'translateExists'], '=' => [$this, 'translateEquals'], '~=' => [$this, 'translateIncludes'], '|=' => [$this, 'translateDashMatch'], '^=' => [$this, 'translatePrefixMatch'], '$=' => [$this, 'translateSuffixMatch'], '*=' => [$this, 'translateSubstringMatch'], '!=' => [$this, 'translateDifferent']];
|
||||
}
|
||||
public function translateExists(XPathExpr $xpath, string $attribute, ?string $value) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition($attribute);
|
||||
}
|
||||
public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition(\sprintf('%s = %s', $attribute, Translator::getXpathLiteral($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)', $attribute, Translator::getXpathLiteral(' ' . $value . ' ')) : '0');
|
||||
}
|
||||
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))', $attribute, Translator::getXpathLiteral($value), Translator::getXpathLiteral($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)', $attribute, Translator::getXpathLiteral($value)) : '0');
|
||||
}
|
||||
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, Translator::getXpathLiteral($value)) : '0');
|
||||
}
|
||||
public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition($value ? \sprintf('%1$s and contains(%1$s, %2$s)', $attribute, Translator::getXpathLiteral($value)) : '0');
|
||||
}
|
||||
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', $attribute, Translator::getXpathLiteral($value)));
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'attribute-matching';
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class CombinationExtension extends AbstractExtension
|
||||
{
|
||||
public function getCombinationTranslators() : array
|
||||
{
|
||||
return [' ' => [$this, 'translateDescendant'], '>' => [$this, 'translateChild'], '+' => [$this, 'translateDirectAdjacent'], '~' => [$this, 'translateIndirectAdjacent']];
|
||||
}
|
||||
public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath) : XPathExpr
|
||||
{
|
||||
return $xpath->join('/descendant-or-self::*/', $combinedXpath);
|
||||
}
|
||||
public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath) : XPathExpr
|
||||
{
|
||||
return $xpath->join('/', $combinedXpath);
|
||||
}
|
||||
public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath) : XPathExpr
|
||||
{
|
||||
return $xpath->join('/following-sibling::', $combinedXpath)->addNameTest()->addCondition('position() = 1');
|
||||
}
|
||||
public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath) : XPathExpr
|
||||
{
|
||||
return $xpath->join('/following-sibling::', $combinedXpath);
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'combination';
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface ExtensionInterface
|
||||
{
|
||||
public function getNodeTranslators() : array;
|
||||
public function getCombinationTranslators() : array;
|
||||
public function getFunctionTranslators() : array;
|
||||
public function getPseudoClassTranslators() : array;
|
||||
public function getAttributeMatchingTranslators() : array;
|
||||
public function getName() : string;
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\FunctionNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Parser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Translator;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class FunctionExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctionTranslators() : array
|
||||
{
|
||||
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']];
|
||||
}
|
||||
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = \false, bool $addNameTest = \true) : XPathExpr
|
||||
{
|
||||
try {
|
||||
[$a, $b] = Parser::parseSeries($function->getArguments());
|
||||
} catch (SyntaxErrorException $e) {
|
||||
throw new ExpressionErrorException(\sprintf('Invalid series: "%s".', \implode('", "', $function->getArguments())), 0, $e);
|
||||
}
|
||||
$xpath->addStarPrefix();
|
||||
if ($addNameTest) {
|
||||
$xpath->addNameTest();
|
||||
}
|
||||
if (0 === $a) {
|
||||
return $xpath->addCondition('position() = ' . ($last ? 'last() - ' . ($b - 1) : $b));
|
||||
}
|
||||
if ($a < 0) {
|
||||
if ($b < 1) {
|
||||
return $xpath->addCondition('false()');
|
||||
}
|
||||
$sign = '<=';
|
||||
} else {
|
||||
$sign = '>=';
|
||||
}
|
||||
$expr = 'position()';
|
||||
if ($last) {
|
||||
$expr = 'last() - ' . $expr;
|
||||
--$b;
|
||||
}
|
||||
if (0 !== $b) {
|
||||
$expr .= ' - ' . $b;
|
||||
}
|
||||
$conditions = [\sprintf('%s %s 0', $expr, $sign)];
|
||||
if (1 !== $a && -1 !== $a) {
|
||||
$conditions[] = \sprintf('(%s) mod %d = 0', $expr, $a);
|
||||
}
|
||||
return $xpath->addCondition(\implode(' and ', $conditions));
|
||||
// todo: handle an+b, odd, even
|
||||
// an+b means every-a, plus b, e.g., 2n+1 means odd
|
||||
// 0n+b means b
|
||||
// n+0 means a=1, i.e., all elements
|
||||
// an means every a elements, i.e., 2n means even
|
||||
// -n means -1n
|
||||
// -1n+6 means elements 6 and previous
|
||||
}
|
||||
public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function) : XPathExpr
|
||||
{
|
||||
return $this->translateNthChild($xpath, $function, \true);
|
||||
}
|
||||
public function translateNthOfType(XPathExpr $xpath, FunctionNode $function) : XPathExpr
|
||||
{
|
||||
return $this->translateNthChild($xpath, $function, \false, \false);
|
||||
}
|
||||
public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function) : XPathExpr
|
||||
{
|
||||
if ('*' === $xpath->getElement()) {
|
||||
throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
|
||||
}
|
||||
return $this->translateNthChild($xpath, $function, \true, \false);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
return $xpath->addCondition(\sprintf('contains(string(.), %s)', Translator::getXpathLiteral($arguments[0]->getValue())));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
return $xpath->addCondition(\sprintf('lang(%s)', Translator::getXpathLiteral($arguments[0]->getValue())));
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'function';
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\FunctionNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Translator;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class HtmlExtension extends AbstractExtension
|
||||
{
|
||||
public function __construct(Translator $translator)
|
||||
{
|
||||
$translator->getExtension('node')->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, \true)->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, \true);
|
||||
}
|
||||
public function getPseudoClassTranslators() : array
|
||||
{
|
||||
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']];
|
||||
}
|
||||
public function getFunctionTranslators() : array
|
||||
{
|
||||
return ['lang' => [$this, 'translateLang']];
|
||||
}
|
||||
public function translateChecked(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('(@checked ' . "and (name(.) = 'input' or name(.) = 'command')" . "and (@type = 'checkbox' or @type = 'radio'))");
|
||||
}
|
||||
public function translateLink(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
|
||||
}
|
||||
public function translateDisabled(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('(' . '@disabled and' . '(' . "(name(.) = 'input' and @type != 'hidden')" . " or name(.) = 'button'" . " or name(.) = 'select'" . " or name(.) = 'textarea'" . " or name(.) = 'command'" . " or name(.) = 'fieldset'" . " or name(.) = 'optgroup'" . " or name(.) = 'option'" . ')' . ') or (' . "(name(.) = 'input' and @type != 'hidden')" . " or name(.) = 'button'" . " or name(.) = 'select'" . " or name(.) = 'textarea'" . ')' . ' and ancestor::fieldset[@disabled]');
|
||||
// todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
|
||||
}
|
||||
public function translateEnabled(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('(' . '@href and (' . "name(.) = 'a'" . " or name(.) = 'link'" . " or name(.) = 'area'" . ')' . ') or (' . '(' . "name(.) = 'command'" . " or name(.) = 'fieldset'" . " or name(.) = 'optgroup'" . ')' . ' and not(@disabled)' . ') or (' . '(' . "(name(.) = 'input' and @type != 'hidden')" . " or name(.) = 'button'" . " or name(.) = 'select'" . " or name(.) = 'textarea'" . " or name(.) = 'keygen'" . ')' . ' and not (@disabled or ancestor::fieldset[@disabled])' . ') or (' . "name(.) = 'option' and not(" . '@disabled or ancestor::optgroup[@disabled]' . ')' . ')');
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
return $xpath->addCondition(\sprintf('ancestor-or-self::*[@lang][1][starts-with(concat(' . "translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')" . ', %s)]', 'lang', Translator::getXpathLiteral(\strtolower($arguments[0]->getValue()) . '-')));
|
||||
}
|
||||
public function translateSelected(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition("(@selected and name(.) = 'option')");
|
||||
}
|
||||
public function translateInvalid(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
public function translateHover(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
public function translateVisited(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'html';
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\Translator;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class NodeExtension extends AbstractExtension
|
||||
{
|
||||
public const ELEMENT_NAME_IN_LOWER_CASE = 1;
|
||||
public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
|
||||
public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
|
||||
private $flags;
|
||||
public function __construct(int $flags = 0)
|
||||
{
|
||||
$this->flags = $flags;
|
||||
}
|
||||
public function setFlag(int $flag, bool $on) : self
|
||||
{
|
||||
if ($on && !$this->hasFlag($flag)) {
|
||||
$this->flags += $flag;
|
||||
}
|
||||
if (!$on && $this->hasFlag($flag)) {
|
||||
$this->flags -= $flag;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function hasFlag(int $flag) : bool
|
||||
{
|
||||
return (bool) ($this->flags & $flag);
|
||||
}
|
||||
public function getNodeTranslators() : array
|
||||
{
|
||||
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']];
|
||||
}
|
||||
public function translateSelector(Node\SelectorNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
return $translator->nodeToXPath($node->getTree());
|
||||
}
|
||||
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
|
||||
}
|
||||
public function translateNegation(Node\NegationNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
$subXpath = $translator->nodeToXPath($node->getSubSelector());
|
||||
$subXpath->addNameTest();
|
||||
if ($subXpath->getCondition()) {
|
||||
return $xpath->addCondition(\sprintf('not(%s)', $subXpath->getCondition()));
|
||||
}
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
public function translateFunction(Node\FunctionNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
return $translator->addFunction($xpath, $node);
|
||||
}
|
||||
public function translatePseudo(Node\PseudoNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
return $translator->addPseudoClass($xpath, $node->getIdentifier());
|
||||
}
|
||||
public function translateAttribute(Node\AttributeNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$name = $node->getAttribute();
|
||||
$safe = $this->isSafeName($name);
|
||||
if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
|
||||
$name = \strtolower($name);
|
||||
}
|
||||
if ($node->getNamespace()) {
|
||||
$name = \sprintf('%s:%s', $node->getNamespace(), $name);
|
||||
$safe = $safe && $this->isSafeName($node->getNamespace());
|
||||
}
|
||||
$attribute = $safe ? '@' . $name : \sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
|
||||
$value = $node->getValue();
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
|
||||
$value = \strtolower($value);
|
||||
}
|
||||
return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
|
||||
}
|
||||
public function translateClass(Node\ClassNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
|
||||
}
|
||||
public function translateHash(Node\HashNode $node, Translator $translator) : XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
|
||||
}
|
||||
public function translateElement(Node\ElementNode $node) : XPathExpr
|
||||
{
|
||||
$element = $node->getElement();
|
||||
if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
|
||||
$element = \strtolower($element);
|
||||
}
|
||||
if ($element) {
|
||||
$safe = $this->isSafeName($element);
|
||||
} else {
|
||||
$element = '*';
|
||||
$safe = \true;
|
||||
}
|
||||
if ($node->getNamespace()) {
|
||||
$element = \sprintf('%s:%s', $node->getNamespace(), $element);
|
||||
$safe = $safe && $this->isSafeName($node->getNamespace());
|
||||
}
|
||||
$xpath = new XPathExpr('', $element);
|
||||
if (!$safe) {
|
||||
$xpath->addNameTest();
|
||||
}
|
||||
return $xpath;
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'node';
|
||||
}
|
||||
private function isSafeName(string $name) : bool
|
||||
{
|
||||
return 0 < \preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath\Extension;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
class PseudoClassExtension extends AbstractExtension
|
||||
{
|
||||
public function getPseudoClassTranslators() : array
|
||||
{
|
||||
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']];
|
||||
}
|
||||
public function translateRoot(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('not(parent::*)');
|
||||
}
|
||||
public function translateFirstChild(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addStarPrefix()->addNameTest()->addCondition('position() = 1');
|
||||
}
|
||||
public function translateLastChild(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addStarPrefix()->addNameTest()->addCondition('position() = last()');
|
||||
}
|
||||
public function translateFirstOfType(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
if ('*' === $xpath->getElement()) {
|
||||
throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
|
||||
}
|
||||
return $xpath->addStarPrefix()->addCondition('position() = 1');
|
||||
}
|
||||
public function translateLastOfType(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
if ('*' === $xpath->getElement()) {
|
||||
throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
|
||||
}
|
||||
return $xpath->addStarPrefix()->addCondition('position() = last()');
|
||||
}
|
||||
public function translateOnlyChild(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addStarPrefix()->addNameTest()->addCondition('last() = 1');
|
||||
}
|
||||
public function translateOnlyOfType(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
$element = $xpath->getElement();
|
||||
return $xpath->addCondition(\sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
|
||||
}
|
||||
public function translateEmpty(XPathExpr $xpath) : XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('not(*) and not(string-length())');
|
||||
}
|
||||
public function getName() : string
|
||||
{
|
||||
return 'pseudo-class';
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\FunctionNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\NodeInterface;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\Parser;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
class Translator implements TranslatorInterface
|
||||
{
|
||||
private $mainParser;
|
||||
private $shortcutParsers = [];
|
||||
private $extensions = [];
|
||||
private $nodeTranslators = [];
|
||||
private $combinationTranslators = [];
|
||||
private $functionTranslators = [];
|
||||
private $pseudoClassTranslators = [];
|
||||
private $attributeMatchingTranslators = [];
|
||||
public function __construct(?ParserInterface $parser = null)
|
||||
{
|
||||
$this->mainParser = $parser ?? new Parser();
|
||||
$this->registerExtension(new Extension\NodeExtension())->registerExtension(new Extension\CombinationExtension())->registerExtension(new Extension\FunctionExtension())->registerExtension(new Extension\PseudoClassExtension())->registerExtension(new Extension\AttributeMatchingExtension());
|
||||
}
|
||||
public static function getXpathLiteral(string $element) : string
|
||||
{
|
||||
if (!\str_contains($element, "'")) {
|
||||
return "'" . $element . "'";
|
||||
}
|
||||
if (!\str_contains($element, '"')) {
|
||||
return '"' . $element . '"';
|
||||
}
|
||||
$string = $element;
|
||||
$parts = [];
|
||||
while (\true) {
|
||||
if (\false !== ($pos = \strpos($string, "'"))) {
|
||||
$parts[] = \sprintf("'%s'", \substr($string, 0, $pos));
|
||||
$parts[] = "\"'\"";
|
||||
$string = \substr($string, $pos + 1);
|
||||
} else {
|
||||
$parts[] = "'{$string}'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return \sprintf('concat(%s)', \implode(', ', $parts));
|
||||
}
|
||||
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::') : string
|
||||
{
|
||||
$selectors = $this->parseSelectors($cssExpr);
|
||||
foreach ($selectors as $index => $selector) {
|
||||
if (null !== $selector->getPseudoElement()) {
|
||||
throw new ExpressionErrorException('Pseudo-elements are not supported.');
|
||||
}
|
||||
$selectors[$index] = $this->selectorToXPath($selector, $prefix);
|
||||
}
|
||||
return \implode(' | ', $selectors);
|
||||
}
|
||||
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::') : string
|
||||
{
|
||||
return ($prefix ?: '') . $this->nodeToXPath($selector);
|
||||
}
|
||||
public function registerExtension(Extension\ExtensionInterface $extension) : self
|
||||
{
|
||||
$this->extensions[$extension->getName()] = $extension;
|
||||
$this->nodeTranslators = \array_merge($this->nodeTranslators, $extension->getNodeTranslators());
|
||||
$this->combinationTranslators = \array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
|
||||
$this->functionTranslators = \array_merge($this->functionTranslators, $extension->getFunctionTranslators());
|
||||
$this->pseudoClassTranslators = \array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
|
||||
$this->attributeMatchingTranslators = \array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
|
||||
return $this;
|
||||
}
|
||||
public function getExtension(string $name) : Extension\ExtensionInterface
|
||||
{
|
||||
if (!isset($this->extensions[$name])) {
|
||||
throw new ExpressionErrorException(\sprintf('Extension "%s" not registered.', $name));
|
||||
}
|
||||
return $this->extensions[$name];
|
||||
}
|
||||
public function registerParserShortcut(ParserInterface $shortcut) : self
|
||||
{
|
||||
$this->shortcutParsers[] = $shortcut;
|
||||
return $this;
|
||||
}
|
||||
public function nodeToXPath(NodeInterface $node) : XPathExpr
|
||||
{
|
||||
if (!isset($this->nodeTranslators[$node->getNodeName()])) {
|
||||
throw new ExpressionErrorException(\sprintf('Node "%s" not supported.', $node->getNodeName()));
|
||||
}
|
||||
return $this->nodeTranslators[$node->getNodeName()]($node, $this);
|
||||
}
|
||||
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 $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
|
||||
}
|
||||
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 $this->functionTranslators[$function->getName()]($xpath, $function);
|
||||
}
|
||||
public function addPseudoClass(XPathExpr $xpath, string $pseudoClass) : XPathExpr
|
||||
{
|
||||
if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
|
||||
throw new ExpressionErrorException(\sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
|
||||
}
|
||||
return $this->pseudoClassTranslators[$pseudoClass]($xpath);
|
||||
}
|
||||
public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value) : XPathExpr
|
||||
{
|
||||
if (!isset($this->attributeMatchingTranslators[$operator])) {
|
||||
throw new ExpressionErrorException(\sprintf('Attribute matcher operator "%s" not supported.', $operator));
|
||||
}
|
||||
return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
|
||||
}
|
||||
private function parseSelectors(string $css) : array
|
||||
{
|
||||
foreach ($this->shortcutParsers as $shortcut) {
|
||||
$tokens = $shortcut->parse($css);
|
||||
if (!empty($tokens)) {
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
return $this->mainParser->parse($css);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\CssSelector\Node\SelectorNode;
|
||||
interface TranslatorInterface
|
||||
{
|
||||
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::') : string;
|
||||
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::') : string;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\CssSelector\XPath;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class XPathExpr
|
||||
{
|
||||
private $path;
|
||||
private $element;
|
||||
private $condition;
|
||||
public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = \false)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->element = $element;
|
||||
$this->condition = $condition;
|
||||
if ($starPrefix) {
|
||||
$this->addStarPrefix();
|
||||
}
|
||||
}
|
||||
public function getElement() : string
|
||||
{
|
||||
return $this->element;
|
||||
}
|
||||
public function addCondition(string $condition) : self
|
||||
{
|
||||
$this->condition = $this->condition ? \sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
|
||||
return $this;
|
||||
}
|
||||
public function getCondition() : string
|
||||
{
|
||||
return $this->condition;
|
||||
}
|
||||
public function addNameTest() : self
|
||||
{
|
||||
if ('*' !== $this->element) {
|
||||
$this->addCondition('name() = ' . Translator::getXpathLiteral($this->element));
|
||||
$this->element = '*';
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addStarPrefix() : self
|
||||
{
|
||||
$this->path .= '*/';
|
||||
return $this;
|
||||
}
|
||||
public function join(string $combiner, self $expr) : self
|
||||
{
|
||||
$path = $this->__toString() . $combiner;
|
||||
if ('*/' !== $expr->path) {
|
||||
$path .= $expr->path;
|
||||
}
|
||||
$this->path = $path;
|
||||
$this->element = $expr->element;
|
||||
$this->condition = $expr->condition;
|
||||
return $this;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$path = $this->path . $this->element;
|
||||
$condition = null === $this->condition || '' === $this->condition ? '' : '[' . $this->condition . ']';
|
||||
return $path . $condition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
class Alias
|
||||
{
|
||||
private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%alias_id%" service alias is deprecated. You should stop using it, as it will be removed in the future.';
|
||||
private $id;
|
||||
private $public;
|
||||
private $deprecation = [];
|
||||
public function __construct(string $id, bool $public = \false)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->public = $public;
|
||||
}
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
public function setPublic(bool $boolean)
|
||||
{
|
||||
$this->public = $boolean;
|
||||
return $this;
|
||||
}
|
||||
public function setPrivate(bool $boolean)
|
||||
{
|
||||
trigger_deprecation('symfony/dependency-injection', '5.2', 'The "%s()" method is deprecated, use "setPublic()" instead.', __METHOD__);
|
||||
return $this->setPublic(!$boolean);
|
||||
}
|
||||
public function isPrivate()
|
||||
{
|
||||
return !$this->public;
|
||||
}
|
||||
public function setDeprecated()
|
||||
{
|
||||
$args = \func_get_args();
|
||||
if (\func_num_args() < 3) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'The signature of method "%s()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.', __METHOD__);
|
||||
$status = $args[0] ?? \true;
|
||||
if (!$status) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Passing a null message to un-deprecate a node is deprecated.');
|
||||
}
|
||||
$message = (string) ($args[1] ?? null);
|
||||
$package = $version = '';
|
||||
} else {
|
||||
$status = \true;
|
||||
$package = (string) $args[0];
|
||||
$version = (string) $args[1];
|
||||
$message = (string) $args[2];
|
||||
}
|
||||
if ('' !== $message) {
|
||||
if (\preg_match('#[\\r\\n]|\\*/#', $message)) {
|
||||
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
|
||||
}
|
||||
if (!\str_contains($message, '%alias_id%')) {
|
||||
throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.');
|
||||
}
|
||||
}
|
||||
$this->deprecation = $status ? ['package' => $package, 'version' => $version, 'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE] : [];
|
||||
return $this;
|
||||
}
|
||||
public function isDeprecated() : bool
|
||||
{
|
||||
return (bool) $this->deprecation;
|
||||
}
|
||||
public function getDeprecationMessage(string $id) : string
|
||||
{
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'The "%s()" method is deprecated, use "getDeprecation()" instead.', __METHOD__);
|
||||
return $this->getDeprecation($id)['message'];
|
||||
}
|
||||
public function getDeprecation(string $id) : array
|
||||
{
|
||||
return ['package' => $this->deprecation['package'], 'version' => $this->deprecation['version'], 'message' => \str_replace('%alias_id%', $id, $this->deprecation['message'])];
|
||||
}
|
||||
public function __toString()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
final class AbstractArgument
|
||||
{
|
||||
private $text;
|
||||
private $context;
|
||||
public function __construct(string $text = '')
|
||||
{
|
||||
$this->text = \trim($text, '. ');
|
||||
}
|
||||
public function setContext(string $context) : void
|
||||
{
|
||||
$this->context = $context . ' is abstract' . ('' === $this->text ? '' : ': ');
|
||||
}
|
||||
public function getText() : string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
public function getTextWithContext() : string
|
||||
{
|
||||
return $this->context . $this->text . '.';
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface ArgumentInterface
|
||||
{
|
||||
public function getValues();
|
||||
public function setValues(array $values);
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
final class BoundArgument implements ArgumentInterface
|
||||
{
|
||||
public const SERVICE_BINDING = 0;
|
||||
public const DEFAULTS_BINDING = 1;
|
||||
public const INSTANCEOF_BINDING = 2;
|
||||
private static $sequence = 0;
|
||||
private $value;
|
||||
private $identifier;
|
||||
private $used;
|
||||
private $type;
|
||||
private $file;
|
||||
public function __construct($value, bool $trackUsage = \true, int $type = 0, ?string $file = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
if ($trackUsage) {
|
||||
$this->identifier = ++self::$sequence;
|
||||
} else {
|
||||
$this->used = \true;
|
||||
}
|
||||
$this->type = $type;
|
||||
$this->file = $file;
|
||||
}
|
||||
public function getValues() : array
|
||||
{
|
||||
return [$this->value, $this->identifier, $this->used, $this->type, $this->file];
|
||||
}
|
||||
public function setValues(array $values)
|
||||
{
|
||||
if (5 === \count($values)) {
|
||||
[$this->value, $this->identifier, $this->used, $this->type, $this->file] = $values;
|
||||
} else {
|
||||
[$this->value, $this->identifier, $this->used] = $values;
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class IteratorArgument implements ArgumentInterface
|
||||
{
|
||||
use ReferenceSetArgumentTrait;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Reference;
|
||||
trait ReferenceSetArgumentTrait
|
||||
{
|
||||
private $values;
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->setValues($values);
|
||||
}
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
public function setValues(array $values)
|
||||
{
|
||||
foreach ($values as $k => $v) {
|
||||
if (null !== $v && !$v instanceof Reference) {
|
||||
throw new InvalidArgumentException(\sprintf('A "%s" must hold only Reference instances, "%s" given.', __CLASS__, \get_debug_type($v)));
|
||||
}
|
||||
}
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class RewindableGenerator implements \IteratorAggregate, \Countable
|
||||
{
|
||||
private $generator;
|
||||
private $count;
|
||||
public function __construct(callable $generator, $count)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
$this->count = $count;
|
||||
}
|
||||
public function getIterator() : \Traversable
|
||||
{
|
||||
$g = $this->generator;
|
||||
return $g();
|
||||
}
|
||||
public function count() : int
|
||||
{
|
||||
if (\is_callable($count = $this->count)) {
|
||||
$this->count = $count();
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Reference;
|
||||
class ServiceClosureArgument implements ArgumentInterface
|
||||
{
|
||||
private $values;
|
||||
public function __construct(Reference $reference)
|
||||
{
|
||||
$this->values = [$reference];
|
||||
}
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
public function setValues(array $values)
|
||||
{
|
||||
if ([0] !== \array_keys($values) || !($values[0] instanceof Reference || null === $values[0])) {
|
||||
throw new InvalidArgumentException('A ServiceClosureArgument must hold one and only one Reference.');
|
||||
}
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
|
||||
class ServiceLocator extends BaseServiceLocator
|
||||
{
|
||||
private $factory;
|
||||
private $serviceMap;
|
||||
private $serviceTypes;
|
||||
public function __construct(\Closure $factory, array $serviceMap, ?array $serviceTypes = null)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->serviceMap = $serviceMap;
|
||||
$this->serviceTypes = $serviceTypes;
|
||||
parent::__construct($serviceMap);
|
||||
}
|
||||
public function get(string $id)
|
||||
{
|
||||
return isset($this->serviceMap[$id]) ? ($this->factory)(...$this->serviceMap[$id]) : parent::get($id);
|
||||
}
|
||||
public function getProvidedServices() : array
|
||||
{
|
||||
return $this->serviceTypes ?? ($this->serviceTypes = \array_map(function () {
|
||||
return '?';
|
||||
}, $this->serviceMap));
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Reference;
|
||||
class ServiceLocatorArgument implements ArgumentInterface
|
||||
{
|
||||
use ReferenceSetArgumentTrait;
|
||||
private $taggedIteratorArgument;
|
||||
public function __construct($values = [])
|
||||
{
|
||||
if ($values instanceof TaggedIteratorArgument) {
|
||||
$this->taggedIteratorArgument = $values;
|
||||
$this->values = [];
|
||||
} else {
|
||||
$this->setValues($values);
|
||||
}
|
||||
}
|
||||
public function getTaggedIteratorArgument() : ?TaggedIteratorArgument
|
||||
{
|
||||
return $this->taggedIteratorArgument;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class TaggedIteratorArgument extends IteratorArgument
|
||||
{
|
||||
private $tag;
|
||||
private $indexAttribute;
|
||||
private $defaultIndexMethod;
|
||||
private $defaultPriorityMethod;
|
||||
private $needsIndexes = \false;
|
||||
public function __construct(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, bool $needsIndexes = \false, ?string $defaultPriorityMethod = null)
|
||||
{
|
||||
parent::__construct([]);
|
||||
if (null === $indexAttribute && $needsIndexes) {
|
||||
$indexAttribute = \preg_match('/[^.]++$/', $tag, $m) ? $m[0] : $tag;
|
||||
}
|
||||
$this->tag = $tag;
|
||||
$this->indexAttribute = $indexAttribute;
|
||||
$this->defaultIndexMethod = $defaultIndexMethod ?: ($indexAttribute ? 'getDefault' . \str_replace(' ', '', \ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $indexAttribute))) . 'Name' : null);
|
||||
$this->needsIndexes = $needsIndexes;
|
||||
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault' . \str_replace(' ', '', \ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $indexAttribute))) . 'Priority' : null);
|
||||
}
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
public function getIndexAttribute() : ?string
|
||||
{
|
||||
return $this->indexAttribute;
|
||||
}
|
||||
public function getDefaultIndexMethod() : ?string
|
||||
{
|
||||
return $this->defaultIndexMethod;
|
||||
}
|
||||
public function needsIndexes() : bool
|
||||
{
|
||||
return $this->needsIndexes;
|
||||
}
|
||||
public function getDefaultPriorityMethod() : ?string
|
||||
{
|
||||
return $this->defaultPriorityMethod;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class AsTaggedItem
|
||||
{
|
||||
public function __construct(public ?string $index = null, public ?int $priority = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
class Autoconfigure
|
||||
{
|
||||
public function __construct(public ?array $tags = null, public ?array $calls = null, public ?array $bind = null, public bool|string|null $lazy = null, public ?bool $public = null, public ?bool $shared = null, public ?bool $autowire = null, public ?array $properties = null, public array|string|null $configurator = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
class AutoconfigureTag extends Autoconfigure
|
||||
{
|
||||
public function __construct(?string $name = null, array $attributes = [])
|
||||
{
|
||||
parent::__construct(tags: [[$name ?? 0 => $attributes]]);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class TaggedIterator
|
||||
{
|
||||
public function __construct(public string $tag, public ?string $indexAttribute = null, public ?string $defaultIndexMethod = null, public ?string $defaultPriorityMethod = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class TaggedLocator
|
||||
{
|
||||
public function __construct(public string $tag, public ?string $indexAttribute = null, public ?string $defaultIndexMethod = null, public ?string $defaultPriorityMethod = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
final class Target
|
||||
{
|
||||
public $name;
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = \lcfirst(\str_replace(' ', '', \ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $name))));
|
||||
}
|
||||
public static function parseName(\ReflectionParameter $parameter) : string
|
||||
{
|
||||
if (80000 > \PHP_VERSION_ID || !($target = $parameter->getAttributes(self::class)[0] ?? null)) {
|
||||
return $parameter->name;
|
||||
}
|
||||
$name = $target->newInstance()->name;
|
||||
if (!\preg_match('/^[a-zA-Z_\\x7f-\\xff]/', $name)) {
|
||||
if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) {
|
||||
$function = $function->class . '::' . $function->name;
|
||||
} else {
|
||||
$function = $function->name;
|
||||
}
|
||||
throw new InvalidArgumentException(\sprintf('Invalid #[Target] name "%s" on parameter "$%s" of "%s()": the first character must be a letter.', $name, $parameter->name, $function));
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Attribute;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
|
||||
class When
|
||||
{
|
||||
public function __construct(public string $env)
|
||||
{
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
class ChildDefinition extends Definition
|
||||
{
|
||||
private $parent;
|
||||
public function __construct(string $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
}
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
public function setParent(string $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
}
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (\array_key_exists('index_' . $index, $this->arguments)) {
|
||||
return $this->arguments['index_' . $index];
|
||||
}
|
||||
return parent::getArgument($index);
|
||||
}
|
||||
public function replaceArgument($index, $value)
|
||||
{
|
||||
if (\is_int($index)) {
|
||||
$this->arguments['index_' . $index] = $value;
|
||||
} elseif (\str_starts_with($index, '$')) {
|
||||
$this->arguments[$index] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException('The argument must be an existing index or the name of a constructor\'s parameter.');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use MailPoetVendor\Symfony\Contracts\Service\ResetInterface;
|
||||
// Help opcache.preload discover always-needed symbols
|
||||
\class_exists(RewindableGenerator::class);
|
||||
\class_exists(ArgumentServiceLocator::class);
|
||||
class Container implements ContainerInterface, ResetInterface
|
||||
{
|
||||
protected $parameterBag;
|
||||
protected $services = [];
|
||||
protected $privates = [];
|
||||
protected $fileMap = [];
|
||||
protected $methodMap = [];
|
||||
protected $factories = [];
|
||||
protected $aliases = [];
|
||||
protected $loading = [];
|
||||
protected $resolving = [];
|
||||
protected $syntheticIds = [];
|
||||
private $envCache = [];
|
||||
private $compiled = \false;
|
||||
private $getEnv;
|
||||
public function __construct(?ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
$this->parameterBag = $parameterBag ?? new EnvPlaceholderParameterBag();
|
||||
}
|
||||
public function compile()
|
||||
{
|
||||
$this->parameterBag->resolve();
|
||||
$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
|
||||
$this->compiled = \true;
|
||||
}
|
||||
public function isCompiled()
|
||||
{
|
||||
return $this->compiled;
|
||||
}
|
||||
public function getParameterBag()
|
||||
{
|
||||
return $this->parameterBag;
|
||||
}
|
||||
public function getParameter(string $name)
|
||||
{
|
||||
return $this->parameterBag->get($name);
|
||||
}
|
||||
public function hasParameter(string $name)
|
||||
{
|
||||
return $this->parameterBag->has($name);
|
||||
}
|
||||
public function setParameter(string $name, $value)
|
||||
{
|
||||
$this->parameterBag->set($name, $value);
|
||||
}
|
||||
public function set(string $id, ?object $service)
|
||||
{
|
||||
// Runs the internal initializer; used by the dumped container to include always-needed files
|
||||
if (isset($this->privates['service_container']) && $this->privates['service_container'] instanceof \Closure) {
|
||||
$initialize = $this->privates['service_container'];
|
||||
unset($this->privates['service_container']);
|
||||
$initialize();
|
||||
}
|
||||
if ('service_container' === $id) {
|
||||
throw new InvalidArgumentException('You cannot set service "service_container".');
|
||||
}
|
||||
if (!(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) {
|
||||
if (isset($this->syntheticIds[$id]) || !isset($this->getRemovedIds()[$id])) {
|
||||
// no-op
|
||||
} elseif (null === $service) {
|
||||
throw new InvalidArgumentException(\sprintf('The "%s" service is private, you cannot unset it.', $id));
|
||||
} else {
|
||||
throw new InvalidArgumentException(\sprintf('The "%s" service is private, you cannot replace it.', $id));
|
||||
}
|
||||
} elseif (isset($this->services[$id])) {
|
||||
throw new InvalidArgumentException(\sprintf('The "%s" service is already initialized, you cannot replace it.', $id));
|
||||
}
|
||||
if (isset($this->aliases[$id])) {
|
||||
unset($this->aliases[$id]);
|
||||
}
|
||||
if (null === $service) {
|
||||
unset($this->services[$id]);
|
||||
return;
|
||||
}
|
||||
$this->services[$id] = $service;
|
||||
}
|
||||
public function has(string $id)
|
||||
{
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
if (isset($this->services[$id])) {
|
||||
return \true;
|
||||
}
|
||||
if ('service_container' === $id) {
|
||||
return \true;
|
||||
}
|
||||
return isset($this->fileMap[$id]) || isset($this->methodMap[$id]);
|
||||
}
|
||||
public function get(string $id, int $invalidBehavior = 1)
|
||||
{
|
||||
return $this->services[$id] ?? $this->services[$id = $this->aliases[$id] ?? $id] ?? ('service_container' === $id ? $this : ($this->factories[$id] ?? [$this, 'make'])($id, $invalidBehavior));
|
||||
}
|
||||
private function make(string $id, int $invalidBehavior)
|
||||
{
|
||||
if (isset($this->loading[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, \array_merge(\array_keys($this->loading), [$id]));
|
||||
}
|
||||
$this->loading[$id] = \true;
|
||||
try {
|
||||
if (isset($this->fileMap[$id])) {
|
||||
return 4 === $invalidBehavior ? null : $this->load($this->fileMap[$id]);
|
||||
} elseif (isset($this->methodMap[$id])) {
|
||||
return 4 === $invalidBehavior ? null : $this->{$this->methodMap[$id]}();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
unset($this->services[$id]);
|
||||
throw $e;
|
||||
} finally {
|
||||
unset($this->loading[$id]);
|
||||
}
|
||||
if (1 === $invalidBehavior) {
|
||||
if (!$id) {
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
if (isset($this->syntheticIds[$id])) {
|
||||
throw new ServiceNotFoundException($id, null, null, [], \sprintf('The "%s" service is synthetic, it needs to be set at boot time before it can be used.', $id));
|
||||
}
|
||||
if (isset($this->getRemovedIds()[$id])) {
|
||||
throw new ServiceNotFoundException($id, null, null, [], \sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.', $id));
|
||||
}
|
||||
$alternatives = [];
|
||||
foreach ($this->getServiceIds() as $knownId) {
|
||||
if ('' === $knownId || '.' === $knownId[0]) {
|
||||
continue;
|
||||
}
|
||||
$lev = \levenshtein($id, $knownId);
|
||||
if ($lev <= \strlen($id) / 3 || \str_contains($knownId, $id)) {
|
||||
$alternatives[] = $knownId;
|
||||
}
|
||||
}
|
||||
throw new ServiceNotFoundException($id, null, null, $alternatives);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public function initialized(string $id)
|
||||
{
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
if ('service_container' === $id) {
|
||||
return \false;
|
||||
}
|
||||
return isset($this->services[$id]);
|
||||
}
|
||||
public function reset()
|
||||
{
|
||||
$services = $this->services + $this->privates;
|
||||
$this->services = $this->factories = $this->privates = [];
|
||||
foreach ($services as $service) {
|
||||
try {
|
||||
if ($service instanceof ResetInterface) {
|
||||
$service->reset();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function getServiceIds()
|
||||
{
|
||||
return \array_map('strval', \array_unique(\array_merge(['service_container'], \array_keys($this->fileMap), \array_keys($this->methodMap), \array_keys($this->aliases), \array_keys($this->services))));
|
||||
}
|
||||
public function getRemovedIds()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
public static function camelize(string $id)
|
||||
{
|
||||
return \strtr(\ucwords(\strtr($id, ['_' => ' ', '.' => '_ ', '\\' => '_ '])), [' ' => '']);
|
||||
}
|
||||
public static function underscore(string $id)
|
||||
{
|
||||
return \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], \str_replace('_', '.', $id)));
|
||||
}
|
||||
protected function load(string $file)
|
||||
{
|
||||
return require $file;
|
||||
}
|
||||
protected function getEnv(string $name)
|
||||
{
|
||||
if (isset($this->resolving[$envName = "env({$name})"])) {
|
||||
throw new ParameterCircularReferenceException(\array_keys($this->resolving));
|
||||
}
|
||||
if (isset($this->envCache[$name]) || \array_key_exists($name, $this->envCache)) {
|
||||
return $this->envCache[$name];
|
||||
}
|
||||
if (!$this->has($id = 'container.env_var_processors_locator')) {
|
||||
$this->set($id, new ServiceLocator([]));
|
||||
}
|
||||
if (!$this->getEnv) {
|
||||
$this->getEnv = \Closure::fromCallable([$this, 'getEnv']);
|
||||
}
|
||||
$processors = $this->get($id);
|
||||
if (\false !== ($i = \strpos($name, ':'))) {
|
||||
$prefix = \substr($name, 0, $i);
|
||||
$localName = \substr($name, 1 + $i);
|
||||
} else {
|
||||
$prefix = 'string';
|
||||
$localName = $name;
|
||||
}
|
||||
$processor = $processors->has($prefix) ? $processors->get($prefix) : new EnvVarProcessor($this);
|
||||
if (\false === $i) {
|
||||
$prefix = '';
|
||||
}
|
||||
$this->resolving[$envName] = \true;
|
||||
try {
|
||||
return $this->envCache[$name] = $processor->getEnv($prefix, $localName, $this->getEnv);
|
||||
} finally {
|
||||
unset($this->resolving[$envName]);
|
||||
}
|
||||
}
|
||||
protected final function getService($registry, string $id, ?string $method, $load)
|
||||
{
|
||||
if ('service_container' === $id) {
|
||||
return $this;
|
||||
}
|
||||
if (\is_string($load)) {
|
||||
throw new RuntimeException($load);
|
||||
}
|
||||
if (null === $method) {
|
||||
return \false !== $registry ? $this->{$registry}[$id] ?? null : null;
|
||||
}
|
||||
if (\false !== $registry) {
|
||||
return $this->{$registry}[$id] ?? ($this->{$registry}[$id] = $load ? $this->load($method) : $this->{$method}());
|
||||
}
|
||||
if (!$load) {
|
||||
return $this->{$method}();
|
||||
}
|
||||
return ($factory = $this->factories[$id] ?? $this->factories['service_container'][$id] ?? null) ? $factory() : $this->load($method);
|
||||
}
|
||||
private function __clone()
|
||||
{
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface ContainerAwareInterface
|
||||
{
|
||||
public function setContainer(?ContainerInterface $container = null);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
trait ContainerAwareTrait
|
||||
{
|
||||
protected $container;
|
||||
public function setContainer(?ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
||||
+965
@@ -0,0 +1,965 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Composer\InstalledVersions;
|
||||
use MailPoetVendor\Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\ComposerResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\FileExistenceResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\FileResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\GlobResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\ReflectionClassResource;
|
||||
use MailPoetVendor\Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\ServiceLocator;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use MailPoetVendor\Symfony\Component\ExpressionLanguage\Expression;
|
||||
use MailPoetVendor\Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
|
||||
class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
{
|
||||
private $extensions = [];
|
||||
private $extensionsByNs = [];
|
||||
private $definitions = [];
|
||||
private $aliasDefinitions = [];
|
||||
private $resources = [];
|
||||
private $extensionConfigs = [];
|
||||
private $compiler;
|
||||
private $trackResources;
|
||||
private $proxyInstantiator;
|
||||
private $expressionLanguage;
|
||||
private $expressionLanguageProviders = [];
|
||||
private $usedTags = [];
|
||||
private $envPlaceholders = [];
|
||||
private $envCounters = [];
|
||||
private $vendors;
|
||||
private $autoconfiguredInstanceof = [];
|
||||
private $autoconfiguredAttributes = [];
|
||||
private $removedIds = [];
|
||||
private $removedBindingIds = [];
|
||||
private const INTERNAL_TYPES = ['int' => \true, 'float' => \true, 'string' => \true, 'bool' => \true, 'resource' => \true, 'object' => \true, 'array' => \true, 'null' => \true, 'callable' => \true, 'iterable' => \true, 'mixed' => \true];
|
||||
public function __construct(?ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
parent::__construct($parameterBag);
|
||||
$this->trackResources = \interface_exists(ResourceInterface::class);
|
||||
$this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(\true)->setPublic(\true));
|
||||
$this->setAlias(PsrContainerInterface::class, new Alias('service_container', \false))->setDeprecated('symfony/dependency-injection', '5.1', $deprecationMessage = 'The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.');
|
||||
$this->setAlias(ContainerInterface::class, new Alias('service_container', \false))->setDeprecated('symfony/dependency-injection', '5.1', $deprecationMessage);
|
||||
}
|
||||
private $classReflectors;
|
||||
public function setResourceTracking(bool $track)
|
||||
{
|
||||
$this->trackResources = $track;
|
||||
}
|
||||
public function isTrackingResources()
|
||||
{
|
||||
return $this->trackResources;
|
||||
}
|
||||
public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
|
||||
{
|
||||
$this->proxyInstantiator = $proxyInstantiator;
|
||||
}
|
||||
public function registerExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$this->extensions[$extension->getAlias()] = $extension;
|
||||
if (\false !== $extension->getNamespace()) {
|
||||
$this->extensionsByNs[$extension->getNamespace()] = $extension;
|
||||
}
|
||||
}
|
||||
public function getExtension(string $name)
|
||||
{
|
||||
if (isset($this->extensions[$name])) {
|
||||
return $this->extensions[$name];
|
||||
}
|
||||
if (isset($this->extensionsByNs[$name])) {
|
||||
return $this->extensionsByNs[$name];
|
||||
}
|
||||
throw new LogicException(\sprintf('Container extension "%s" is not registered.', $name));
|
||||
}
|
||||
public function getExtensions()
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
public function hasExtension(string $name)
|
||||
{
|
||||
return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
|
||||
}
|
||||
public function getResources()
|
||||
{
|
||||
return \array_values($this->resources);
|
||||
}
|
||||
public function addResource(ResourceInterface $resource)
|
||||
{
|
||||
if (!$this->trackResources) {
|
||||
return $this;
|
||||
}
|
||||
if ($resource instanceof GlobResource && $this->inVendors($resource->getPrefix())) {
|
||||
return $this;
|
||||
}
|
||||
$this->resources[(string) $resource] = $resource;
|
||||
return $this;
|
||||
}
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
if (!$this->trackResources) {
|
||||
return $this;
|
||||
}
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
public function addObjectResource($object)
|
||||
{
|
||||
if ($this->trackResources) {
|
||||
if (\is_object($object)) {
|
||||
$object = \get_class($object);
|
||||
}
|
||||
if (!isset($this->classReflectors[$object])) {
|
||||
$this->classReflectors[$object] = new \ReflectionClass($object);
|
||||
}
|
||||
$class = $this->classReflectors[$object];
|
||||
foreach ($class->getInterfaceNames() as $name) {
|
||||
if (null === ($interface =& $this->classReflectors[$name])) {
|
||||
$interface = new \ReflectionClass($name);
|
||||
}
|
||||
$file = $interface->getFileName();
|
||||
if (\false !== $file && \file_exists($file)) {
|
||||
$this->fileExists($file);
|
||||
}
|
||||
}
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (\false !== $file && \file_exists($file)) {
|
||||
$this->fileExists($file);
|
||||
}
|
||||
foreach ($class->getTraitNames() as $name) {
|
||||
$this->addObjectResource($name);
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function getReflectionClass(?string $class, bool $throw = \true) : ?\ReflectionClass
|
||||
{
|
||||
if (!($class = $this->getParameterBag()->resolveValue($class))) {
|
||||
return null;
|
||||
}
|
||||
if (isset(self::INTERNAL_TYPES[$class])) {
|
||||
return null;
|
||||
}
|
||||
$resource = $classReflector = null;
|
||||
try {
|
||||
if (isset($this->classReflectors[$class])) {
|
||||
$classReflector = $this->classReflectors[$class];
|
||||
} elseif (\class_exists(ClassExistenceResource::class)) {
|
||||
$resource = new ClassExistenceResource($class, \false);
|
||||
$classReflector = $resource->isFresh(0) ? \false : new \ReflectionClass($class);
|
||||
} else {
|
||||
$classReflector = \class_exists($class) ? new \ReflectionClass($class) : \false;
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
if ($throw) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
if ($this->trackResources) {
|
||||
if (!$classReflector) {
|
||||
$this->addResource($resource ?? new ClassExistenceResource($class, \false));
|
||||
} elseif (!$classReflector->isInternal()) {
|
||||
$path = $classReflector->getFileName();
|
||||
if (!$this->inVendors($path)) {
|
||||
$this->addResource(new ReflectionClassResource($classReflector, $this->vendors));
|
||||
}
|
||||
}
|
||||
$this->classReflectors[$class] = $classReflector;
|
||||
}
|
||||
return $classReflector ?: null;
|
||||
}
|
||||
public function fileExists(string $path, $trackContents = \true) : bool
|
||||
{
|
||||
$exists = \file_exists($path);
|
||||
if (!$this->trackResources || $this->inVendors($path)) {
|
||||
return $exists;
|
||||
}
|
||||
if (!$exists) {
|
||||
$this->addResource(new FileExistenceResource($path));
|
||||
return $exists;
|
||||
}
|
||||
if (\is_dir($path)) {
|
||||
if ($trackContents) {
|
||||
$this->addResource(new DirectoryResource($path, \is_string($trackContents) ? $trackContents : null));
|
||||
} else {
|
||||
$this->addResource(new GlobResource($path, '/*', \false));
|
||||
}
|
||||
} elseif ($trackContents) {
|
||||
$this->addResource(new FileResource($path));
|
||||
}
|
||||
return $exists;
|
||||
}
|
||||
public function loadFromExtension(string $extension, ?array $values = null)
|
||||
{
|
||||
if ($this->isCompiled()) {
|
||||
throw new BadMethodCallException('Cannot load from an extension on a compiled container.');
|
||||
}
|
||||
$namespace = $this->getExtension($extension)->getAlias();
|
||||
$this->extensionConfigs[$namespace][] = $values ?? [];
|
||||
return $this;
|
||||
}
|
||||
public function addCompilerPass(CompilerPassInterface $pass, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0)
|
||||
{
|
||||
$this->getCompiler()->addPass($pass, $type, $priority);
|
||||
$this->addObjectResource($pass);
|
||||
return $this;
|
||||
}
|
||||
public function getCompilerPassConfig()
|
||||
{
|
||||
return $this->getCompiler()->getPassConfig();
|
||||
}
|
||||
public function getCompiler()
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler();
|
||||
}
|
||||
return $this->compiler;
|
||||
}
|
||||
public function set(string $id, ?object $service)
|
||||
{
|
||||
if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
|
||||
// setting a synthetic service on a compiled container is alright
|
||||
throw new BadMethodCallException(\sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.', $id));
|
||||
}
|
||||
unset($this->definitions[$id], $this->aliasDefinitions[$id], $this->removedIds[$id]);
|
||||
parent::set($id, $service);
|
||||
}
|
||||
public function removeDefinition(string $id)
|
||||
{
|
||||
if (isset($this->definitions[$id])) {
|
||||
unset($this->definitions[$id]);
|
||||
$this->removedIds[$id] = \true;
|
||||
}
|
||||
}
|
||||
public function has(string $id)
|
||||
{
|
||||
return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
|
||||
}
|
||||
public function get(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
if ($this->isCompiled() && isset($this->removedIds[$id])) {
|
||||
return ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $invalidBehavior ? parent::get($id) : null;
|
||||
}
|
||||
return $this->doGet($id, $invalidBehavior);
|
||||
}
|
||||
private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, ?array &$inlineServices = null, bool $isConstructorArgument = \false)
|
||||
{
|
||||
if (isset($inlineServices[$id])) {
|
||||
return $inlineServices[$id];
|
||||
}
|
||||
if (null === $inlineServices) {
|
||||
$isConstructorArgument = \true;
|
||||
$inlineServices = [];
|
||||
}
|
||||
try {
|
||||
if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) {
|
||||
return $this->privates[$id] ?? parent::get($id, $invalidBehavior);
|
||||
}
|
||||
if (null !== ($service = $this->privates[$id] ?? parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE))) {
|
||||
return $service;
|
||||
}
|
||||
} catch (ServiceCircularReferenceException $e) {
|
||||
if ($isConstructorArgument) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
|
||||
$alias = $this->aliasDefinitions[$id];
|
||||
if ($alias->isDeprecated()) {
|
||||
$deprecation = $alias->getDeprecation($id);
|
||||
trigger_deprecation($deprecation['package'], $deprecation['version'], $deprecation['message']);
|
||||
}
|
||||
return $this->doGet((string) $alias, $invalidBehavior, $inlineServices, $isConstructorArgument);
|
||||
}
|
||||
try {
|
||||
$definition = $this->getDefinition($id);
|
||||
} catch (ServiceNotFoundException $e) {
|
||||
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $invalidBehavior) {
|
||||
return null;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
if ($definition->hasErrors() && ($e = $definition->getErrors())) {
|
||||
throw new RuntimeException(\reset($e));
|
||||
}
|
||||
if ($isConstructorArgument) {
|
||||
$this->loading[$id] = \true;
|
||||
}
|
||||
try {
|
||||
return $this->createService($definition, $inlineServices, $isConstructorArgument, $id);
|
||||
} finally {
|
||||
if ($isConstructorArgument) {
|
||||
unset($this->loading[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function merge(self $container)
|
||||
{
|
||||
if ($this->isCompiled()) {
|
||||
throw new BadMethodCallException('Cannot merge on a compiled container.');
|
||||
}
|
||||
$this->addDefinitions($container->getDefinitions());
|
||||
$this->addAliases($container->getAliases());
|
||||
$this->getParameterBag()->add($container->getParameterBag()->all());
|
||||
if ($this->trackResources) {
|
||||
foreach ($container->getResources() as $resource) {
|
||||
$this->addResource($resource);
|
||||
}
|
||||
}
|
||||
foreach ($this->extensions as $name => $extension) {
|
||||
if (!isset($this->extensionConfigs[$name])) {
|
||||
$this->extensionConfigs[$name] = [];
|
||||
}
|
||||
$this->extensionConfigs[$name] = \array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
|
||||
}
|
||||
if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
|
||||
$envPlaceholders = $container->getParameterBag()->getEnvPlaceholders();
|
||||
$this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
|
||||
} else {
|
||||
$envPlaceholders = [];
|
||||
}
|
||||
foreach ($container->envCounters as $env => $count) {
|
||||
if (!$count && !isset($envPlaceholders[$env])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($this->envCounters[$env])) {
|
||||
$this->envCounters[$env] = $count;
|
||||
} else {
|
||||
$this->envCounters[$env] += $count;
|
||||
}
|
||||
}
|
||||
foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) {
|
||||
if (isset($this->autoconfiguredInstanceof[$interface])) {
|
||||
throw new InvalidArgumentException(\sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface));
|
||||
}
|
||||
$this->autoconfiguredInstanceof[$interface] = $childDefinition;
|
||||
}
|
||||
foreach ($container->getAutoconfiguredAttributes() as $attribute => $configurator) {
|
||||
if (isset($this->autoconfiguredAttributes[$attribute])) {
|
||||
throw new InvalidArgumentException(\sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same attribute.', $attribute));
|
||||
}
|
||||
$this->autoconfiguredAttributes[$attribute] = $configurator;
|
||||
}
|
||||
}
|
||||
public function getExtensionConfig(string $name)
|
||||
{
|
||||
if (!isset($this->extensionConfigs[$name])) {
|
||||
$this->extensionConfigs[$name] = [];
|
||||
}
|
||||
return $this->extensionConfigs[$name];
|
||||
}
|
||||
public function prependExtensionConfig(string $name, array $config)
|
||||
{
|
||||
if (!isset($this->extensionConfigs[$name])) {
|
||||
$this->extensionConfigs[$name] = [];
|
||||
}
|
||||
\array_unshift($this->extensionConfigs[$name], $config);
|
||||
}
|
||||
public function compile(bool $resolveEnvPlaceholders = \false)
|
||||
{
|
||||
$compiler = $this->getCompiler();
|
||||
if ($this->trackResources) {
|
||||
foreach ($compiler->getPassConfig()->getPasses() as $pass) {
|
||||
$this->addObjectResource($pass);
|
||||
}
|
||||
}
|
||||
$bag = $this->getParameterBag();
|
||||
if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) {
|
||||
$compiler->addPass(new ResolveEnvPlaceholdersPass(), PassConfig::TYPE_AFTER_REMOVING, -1000);
|
||||
}
|
||||
$compiler->compile($this);
|
||||
foreach ($this->definitions as $id => $definition) {
|
||||
if ($this->trackResources && $definition->isLazy()) {
|
||||
$this->getReflectionClass($definition->getClass());
|
||||
}
|
||||
}
|
||||
$this->extensionConfigs = [];
|
||||
if ($bag instanceof EnvPlaceholderParameterBag) {
|
||||
if ($resolveEnvPlaceholders) {
|
||||
$this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), \true));
|
||||
}
|
||||
$this->envPlaceholders = $bag->getEnvPlaceholders();
|
||||
}
|
||||
parent::compile();
|
||||
foreach ($this->definitions + $this->aliasDefinitions as $id => $definition) {
|
||||
if (!$definition->isPublic() || $definition->isPrivate()) {
|
||||
$this->removedIds[$id] = \true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function getServiceIds()
|
||||
{
|
||||
return \array_map('strval', \array_unique(\array_merge(\array_keys($this->getDefinitions()), \array_keys($this->aliasDefinitions), parent::getServiceIds())));
|
||||
}
|
||||
public function getRemovedIds()
|
||||
{
|
||||
return $this->removedIds;
|
||||
}
|
||||
public function addAliases(array $aliases)
|
||||
{
|
||||
foreach ($aliases as $alias => $id) {
|
||||
$this->setAlias($alias, $id);
|
||||
}
|
||||
}
|
||||
public function setAliases(array $aliases)
|
||||
{
|
||||
$this->aliasDefinitions = [];
|
||||
$this->addAliases($aliases);
|
||||
}
|
||||
public function setAlias(string $alias, $id)
|
||||
{
|
||||
if ('' === $alias || '\\' === $alias[-1] || \strlen($alias) !== \strcspn($alias, "\x00\r\n'")) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid alias id: "%s".', $alias));
|
||||
}
|
||||
if (\is_string($id)) {
|
||||
$id = new Alias($id);
|
||||
} elseif (!$id instanceof Alias) {
|
||||
throw new InvalidArgumentException('$id must be a string, or an Alias object.');
|
||||
}
|
||||
if ($alias === (string) $id) {
|
||||
throw new InvalidArgumentException(\sprintf('An alias cannot reference itself, got a circular reference on "%s".', $alias));
|
||||
}
|
||||
unset($this->definitions[$alias], $this->removedIds[$alias]);
|
||||
return $this->aliasDefinitions[$alias] = $id;
|
||||
}
|
||||
public function removeAlias(string $alias)
|
||||
{
|
||||
if (isset($this->aliasDefinitions[$alias])) {
|
||||
unset($this->aliasDefinitions[$alias]);
|
||||
$this->removedIds[$alias] = \true;
|
||||
}
|
||||
}
|
||||
public function hasAlias(string $id)
|
||||
{
|
||||
return isset($this->aliasDefinitions[$id]);
|
||||
}
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliasDefinitions;
|
||||
}
|
||||
public function getAlias(string $id)
|
||||
{
|
||||
if (!isset($this->aliasDefinitions[$id])) {
|
||||
throw new InvalidArgumentException(\sprintf('The service alias "%s" does not exist.', $id));
|
||||
}
|
||||
return $this->aliasDefinitions[$id];
|
||||
}
|
||||
public function register(string $id, ?string $class = null)
|
||||
{
|
||||
return $this->setDefinition($id, new Definition($class));
|
||||
}
|
||||
public function autowire(string $id, ?string $class = null)
|
||||
{
|
||||
return $this->setDefinition($id, (new Definition($class))->setAutowired(\true));
|
||||
}
|
||||
public function addDefinitions(array $definitions)
|
||||
{
|
||||
foreach ($definitions as $id => $definition) {
|
||||
$this->setDefinition($id, $definition);
|
||||
}
|
||||
}
|
||||
public function setDefinitions(array $definitions)
|
||||
{
|
||||
$this->definitions = [];
|
||||
$this->addDefinitions($definitions);
|
||||
}
|
||||
public function getDefinitions()
|
||||
{
|
||||
return $this->definitions;
|
||||
}
|
||||
public function setDefinition(string $id, Definition $definition)
|
||||
{
|
||||
if ($this->isCompiled()) {
|
||||
throw new BadMethodCallException('Adding definition to a compiled container is not allowed.');
|
||||
}
|
||||
if ('' === $id || '\\' === $id[-1] || \strlen($id) !== \strcspn($id, "\x00\r\n'")) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service id: "%s".', $id));
|
||||
}
|
||||
unset($this->aliasDefinitions[$id], $this->removedIds[$id]);
|
||||
return $this->definitions[$id] = $definition;
|
||||
}
|
||||
public function hasDefinition(string $id)
|
||||
{
|
||||
return isset($this->definitions[$id]);
|
||||
}
|
||||
public function getDefinition(string $id)
|
||||
{
|
||||
if (!isset($this->definitions[$id])) {
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
return $this->definitions[$id];
|
||||
}
|
||||
public function findDefinition(string $id)
|
||||
{
|
||||
$seen = [];
|
||||
while (isset($this->aliasDefinitions[$id])) {
|
||||
$id = (string) $this->aliasDefinitions[$id];
|
||||
if (isset($seen[$id])) {
|
||||
$seen = \array_values($seen);
|
||||
$seen = \array_slice($seen, \array_search($id, $seen));
|
||||
$seen[] = $id;
|
||||
throw new ServiceCircularReferenceException($id, $seen);
|
||||
}
|
||||
$seen[$id] = $id;
|
||||
}
|
||||
return $this->getDefinition($id);
|
||||
}
|
||||
private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = \false, ?string $id = null, bool $tryProxy = \true)
|
||||
{
|
||||
if (null === $id && isset($inlineServices[$h = \spl_object_hash($definition)])) {
|
||||
return $inlineServices[$h];
|
||||
}
|
||||
if ($definition instanceof ChildDefinition) {
|
||||
throw new RuntimeException(\sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
|
||||
}
|
||||
if ($definition->isSynthetic()) {
|
||||
throw new RuntimeException(\sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
|
||||
}
|
||||
if ($definition->isDeprecated()) {
|
||||
$deprecation = $definition->getDeprecation($id);
|
||||
trigger_deprecation($deprecation['package'], $deprecation['version'], $deprecation['message']);
|
||||
}
|
||||
if ($tryProxy && $definition->isLazy() && !($tryProxy = !($proxy = $this->proxyInstantiator) || $proxy instanceof RealServiceInstantiator)) {
|
||||
$proxy = $proxy->instantiateProxy($this, $definition, $id, function () use($definition, &$inlineServices, $id) {
|
||||
return $this->createService($definition, $inlineServices, \true, $id, \false);
|
||||
});
|
||||
$this->shareService($definition, $proxy, $id, $inlineServices);
|
||||
return $proxy;
|
||||
}
|
||||
$parameterBag = $this->getParameterBag();
|
||||
if (null !== $definition->getFile()) {
|
||||
require_once $parameterBag->resolveValue($definition->getFile());
|
||||
}
|
||||
$arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices, $isConstructorArgument);
|
||||
if (null !== ($factory = $definition->getFactory())) {
|
||||
if (\is_array($factory)) {
|
||||
$factory = [$this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices, $isConstructorArgument), $factory[1]];
|
||||
} elseif (!\is_string($factory)) {
|
||||
throw new RuntimeException(\sprintf('Cannot create service "%s" because of invalid factory.', $id));
|
||||
}
|
||||
}
|
||||
if (null !== $id && $definition->isShared() && (isset($this->services[$id]) || isset($this->privates[$id])) && ($tryProxy || !$definition->isLazy())) {
|
||||
return $this->services[$id] ?? $this->privates[$id];
|
||||
}
|
||||
if (!\array_is_list($arguments)) {
|
||||
$arguments = \array_combine(\array_map(function ($k) {
|
||||
return \preg_replace('/^.*\\$/', '', $k);
|
||||
}, \array_keys($arguments)), $arguments);
|
||||
}
|
||||
if (null !== $factory) {
|
||||
$service = $factory(...$arguments);
|
||||
if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
|
||||
$r = new \ReflectionClass($factory[0]);
|
||||
if (0 < \strpos($r->getDocComment(), "\n * @deprecated ")) {
|
||||
trigger_deprecation('', '', 'The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
|
||||
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
|
||||
if (!$definition->isDeprecated() && 0 < \strpos($r->getDocComment(), "\n * @deprecated ")) {
|
||||
trigger_deprecation('', '', 'The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name);
|
||||
}
|
||||
}
|
||||
$lastWitherIndex = null;
|
||||
foreach ($definition->getMethodCalls() as $k => $call) {
|
||||
if ($call[2] ?? \false) {
|
||||
$lastWitherIndex = $k;
|
||||
}
|
||||
}
|
||||
if (null === $lastWitherIndex && ($tryProxy || !$definition->isLazy())) {
|
||||
// share only if proxying failed, or if not a proxy, and if no withers are found
|
||||
$this->shareService($definition, $service, $id, $inlineServices);
|
||||
}
|
||||
$properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlineServices);
|
||||
foreach ($properties as $name => $value) {
|
||||
$service->{$name} = $value;
|
||||
}
|
||||
foreach ($definition->getMethodCalls() as $k => $call) {
|
||||
$service = $this->callMethod($service, $call, $inlineServices);
|
||||
if ($lastWitherIndex === $k && ($tryProxy || !$definition->isLazy())) {
|
||||
// share only if proxying failed, or if not a proxy, and this is the last wither
|
||||
$this->shareService($definition, $service, $id, $inlineServices);
|
||||
}
|
||||
}
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
if (\is_array($callable)) {
|
||||
$callable[0] = $parameterBag->resolveValue($callable[0]);
|
||||
if ($callable[0] instanceof Reference) {
|
||||
$callable[0] = $this->doGet((string) $callable[0], $callable[0]->getInvalidBehavior(), $inlineServices);
|
||||
} elseif ($callable[0] instanceof Definition) {
|
||||
$callable[0] = $this->createService($callable[0], $inlineServices);
|
||||
}
|
||||
}
|
||||
if (!\is_callable($callable)) {
|
||||
throw new InvalidArgumentException(\sprintf('The configure callable for class "%s" is not a callable.', \get_debug_type($service)));
|
||||
}
|
||||
$callable($service);
|
||||
}
|
||||
return $service;
|
||||
}
|
||||
public function resolveServices($value)
|
||||
{
|
||||
return $this->doResolveServices($value);
|
||||
}
|
||||
private function doResolveServices($value, array &$inlineServices = [], bool $isConstructorArgument = \false)
|
||||
{
|
||||
if (\is_array($value)) {
|
||||
foreach ($value as $k => $v) {
|
||||
$value[$k] = $this->doResolveServices($v, $inlineServices, $isConstructorArgument);
|
||||
}
|
||||
} elseif ($value instanceof ServiceClosureArgument) {
|
||||
$reference = $value->getValues()[0];
|
||||
$value = function () use($reference) {
|
||||
return $this->resolveServices($reference);
|
||||
};
|
||||
} elseif ($value instanceof IteratorArgument) {
|
||||
$value = new RewindableGenerator(function () use($value, &$inlineServices) {
|
||||
foreach ($value->getValues() as $k => $v) {
|
||||
foreach (self::getServiceConditionals($v) as $s) {
|
||||
if (!$this->has($s)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
foreach (self::getInitializedConditionals($v) as $s) {
|
||||
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
(yield $k => $this->doResolveServices($v, $inlineServices));
|
||||
}
|
||||
}, function () use($value) : int {
|
||||
$count = 0;
|
||||
foreach ($value->getValues() as $v) {
|
||||
foreach (self::getServiceConditionals($v) as $s) {
|
||||
if (!$this->has($s)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
foreach (self::getInitializedConditionals($v) as $s) {
|
||||
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
++$count;
|
||||
}
|
||||
return $count;
|
||||
});
|
||||
} elseif ($value instanceof ServiceLocatorArgument) {
|
||||
$refs = $types = [];
|
||||
foreach ($value->getValues() as $k => $v) {
|
||||
if ($v) {
|
||||
$refs[$k] = [$v];
|
||||
$types[$k] = $v instanceof TypedReference ? $v->getType() : '?';
|
||||
}
|
||||
}
|
||||
$value = new ServiceLocator(\Closure::fromCallable([$this, 'resolveServices']), $refs, $types);
|
||||
} elseif ($value instanceof Reference) {
|
||||
$value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices, $isConstructorArgument);
|
||||
} elseif ($value instanceof Definition) {
|
||||
$value = $this->createService($value, $inlineServices, $isConstructorArgument);
|
||||
} elseif ($value instanceof Parameter) {
|
||||
$value = $this->getParameter((string) $value);
|
||||
} elseif ($value instanceof Expression) {
|
||||
$value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this]);
|
||||
} elseif ($value instanceof AbstractArgument) {
|
||||
throw new RuntimeException($value->getTextWithContext());
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
public function findTaggedServiceIds(string $name, bool $throwOnAbstract = \false)
|
||||
{
|
||||
$this->usedTags[] = $name;
|
||||
$tags = [];
|
||||
foreach ($this->getDefinitions() as $id => $definition) {
|
||||
if ($definition->hasTag($name)) {
|
||||
if ($throwOnAbstract && $definition->isAbstract()) {
|
||||
throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must not be abstract.', $id, $name));
|
||||
}
|
||||
$tags[$id] = $definition->getTag($name);
|
||||
}
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
public function findTags()
|
||||
{
|
||||
$tags = [];
|
||||
foreach ($this->getDefinitions() as $id => $definition) {
|
||||
$tags[] = \array_keys($definition->getTags());
|
||||
}
|
||||
return \array_unique(\array_merge([], ...$tags));
|
||||
}
|
||||
public function findUnusedTags()
|
||||
{
|
||||
return \array_values(\array_diff($this->findTags(), $this->usedTags));
|
||||
}
|
||||
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
|
||||
{
|
||||
$this->expressionLanguageProviders[] = $provider;
|
||||
}
|
||||
public function getExpressionLanguageProviders()
|
||||
{
|
||||
return $this->expressionLanguageProviders;
|
||||
}
|
||||
public function registerForAutoconfiguration(string $interface)
|
||||
{
|
||||
if (!isset($this->autoconfiguredInstanceof[$interface])) {
|
||||
$this->autoconfiguredInstanceof[$interface] = new ChildDefinition('');
|
||||
}
|
||||
return $this->autoconfiguredInstanceof[$interface];
|
||||
}
|
||||
public function registerAttributeForAutoconfiguration(string $attributeClass, callable $configurator) : void
|
||||
{
|
||||
$this->autoconfiguredAttributes[$attributeClass] = $configurator;
|
||||
}
|
||||
public function registerAliasForArgument(string $id, string $type, ?string $name = null) : Alias
|
||||
{
|
||||
$name = (new Target($name ?? $id))->name;
|
||||
if (!\preg_match('/^[a-zA-Z_\\x7f-\\xff]/', $name)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid argument name "%s" for service "%s": the first character must be a letter.', $name, $id));
|
||||
}
|
||||
return $this->setAlias($type . ' $' . $name, $id);
|
||||
}
|
||||
public function getAutoconfiguredInstanceof()
|
||||
{
|
||||
return $this->autoconfiguredInstanceof;
|
||||
}
|
||||
public function getAutoconfiguredAttributes() : array
|
||||
{
|
||||
return $this->autoconfiguredAttributes;
|
||||
}
|
||||
public function resolveEnvPlaceholders($value, $format = null, ?array &$usedEnvs = null)
|
||||
{
|
||||
if (null === $format) {
|
||||
$format = '%%env(%s)%%';
|
||||
}
|
||||
$bag = $this->getParameterBag();
|
||||
if (\true === $format) {
|
||||
$value = $bag->resolveValue($value);
|
||||
}
|
||||
if ($value instanceof Definition) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
if (\is_array($value)) {
|
||||
$result = [];
|
||||
foreach ($value as $k => $v) {
|
||||
$result[\is_string($k) ? $this->resolveEnvPlaceholders($k, $format, $usedEnvs) : $k] = $this->resolveEnvPlaceholders($v, $format, $usedEnvs);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
if (!\is_string($value) || 38 > \strlen($value) || !\preg_match('/env[_(]/i', $value)) {
|
||||
return $value;
|
||||
}
|
||||
$envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
|
||||
$completed = \false;
|
||||
foreach ($envPlaceholders as $env => $placeholders) {
|
||||
foreach ($placeholders as $placeholder) {
|
||||
if (\false !== \stripos($value, $placeholder)) {
|
||||
if (\true === $format) {
|
||||
$resolved = $bag->escapeValue($this->getEnv($env));
|
||||
} else {
|
||||
$resolved = \sprintf($format, $env);
|
||||
}
|
||||
if ($placeholder === $value) {
|
||||
$value = $resolved;
|
||||
$completed = \true;
|
||||
} else {
|
||||
if (!\is_string($resolved) && !\is_numeric($resolved)) {
|
||||
throw new RuntimeException(\sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type "%s" inside string value "%s".', $env, \get_debug_type($resolved), $this->resolveEnvPlaceholders($value)));
|
||||
}
|
||||
$value = \str_ireplace($placeholder, $resolved, $value);
|
||||
}
|
||||
$usedEnvs[$env] = $env;
|
||||
$this->envCounters[$env] = isset($this->envCounters[$env]) ? 1 + $this->envCounters[$env] : 1;
|
||||
if ($completed) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
public function getEnvCounters()
|
||||
{
|
||||
$bag = $this->getParameterBag();
|
||||
$envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
|
||||
foreach ($envPlaceholders as $env => $placeholders) {
|
||||
if (!isset($this->envCounters[$env])) {
|
||||
$this->envCounters[$env] = 0;
|
||||
}
|
||||
}
|
||||
return $this->envCounters;
|
||||
}
|
||||
public function log(CompilerPassInterface $pass, string $message)
|
||||
{
|
||||
$this->getCompiler()->log($pass, $this->resolveEnvPlaceholders($message));
|
||||
}
|
||||
public static final function willBeAvailable(string $package, string $class, array $parentPackages) : bool
|
||||
{
|
||||
$skipDeprecation = 3 < \func_num_args() && \func_get_arg(3);
|
||||
$hasRuntimeApi = \class_exists(InstalledVersions::class);
|
||||
if (!$hasRuntimeApi && !$skipDeprecation) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.4', 'Calling "%s" when dependencies have been installed with Composer 1 is deprecated. Consider upgrading to Composer 2.', __METHOD__);
|
||||
}
|
||||
if (!\class_exists($class) && !\interface_exists($class, \false) && !\trait_exists($class, \false)) {
|
||||
return \false;
|
||||
}
|
||||
if (!$hasRuntimeApi || !InstalledVersions::isInstalled($package) || InstalledVersions::isInstalled($package, \false)) {
|
||||
return \true;
|
||||
}
|
||||
// the package is installed but in dev-mode only, check if this applies to one of the parent packages too
|
||||
$rootPackage = InstalledVersions::getRootPackage()['name'] ?? '';
|
||||
if ('symfony/symfony' === $rootPackage) {
|
||||
return \true;
|
||||
}
|
||||
foreach ($parentPackages as $parentPackage) {
|
||||
if ($rootPackage === $parentPackage || InstalledVersions::isInstalled($parentPackage) && !InstalledVersions::isInstalled($parentPackage, \false)) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function getRemovedBindingIds() : array
|
||||
{
|
||||
return $this->removedBindingIds;
|
||||
}
|
||||
public function removeBindings(string $id)
|
||||
{
|
||||
if ($this->hasDefinition($id)) {
|
||||
foreach ($this->getDefinition($id)->getBindings() as $key => $binding) {
|
||||
[, $bindingId] = $binding->getValues();
|
||||
$this->removedBindingIds[(int) $bindingId] = \true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static function getServiceConditionals($value) : array
|
||||
{
|
||||
$services = [];
|
||||
if (\is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
$services = \array_unique(\array_merge($services, self::getServiceConditionals($v)));
|
||||
}
|
||||
} elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
|
||||
$services[] = (string) $value;
|
||||
}
|
||||
return $services;
|
||||
}
|
||||
public static function getInitializedConditionals($value) : array
|
||||
{
|
||||
$services = [];
|
||||
if (\is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
$services = \array_unique(\array_merge($services, self::getInitializedConditionals($v)));
|
||||
}
|
||||
} elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()) {
|
||||
$services[] = (string) $value;
|
||||
}
|
||||
return $services;
|
||||
}
|
||||
public static function hash($value)
|
||||
{
|
||||
$hash = \substr(\base64_encode(\hash('sha256', \serialize($value), \true)), 0, 7);
|
||||
return \str_replace(['/', '+'], ['.', '_'], $hash);
|
||||
}
|
||||
protected function getEnv(string $name)
|
||||
{
|
||||
$value = parent::getEnv($name);
|
||||
$bag = $this->getParameterBag();
|
||||
if (!\is_string($value) || !$bag instanceof EnvPlaceholderParameterBag) {
|
||||
return $value;
|
||||
}
|
||||
$envPlaceholders = $bag->getEnvPlaceholders();
|
||||
if (isset($envPlaceholders[$name][$value])) {
|
||||
$bag = new ParameterBag($bag->all());
|
||||
return $bag->unescapeValue($bag->get("env({$name})"));
|
||||
}
|
||||
foreach ($envPlaceholders as $env => $placeholders) {
|
||||
if (isset($placeholders[$value])) {
|
||||
return $this->getEnv($env);
|
||||
}
|
||||
}
|
||||
$this->resolving["env({$name})"] = \true;
|
||||
try {
|
||||
return $bag->unescapeValue($this->resolveEnvPlaceholders($bag->escapeValue($value), \true));
|
||||
} finally {
|
||||
unset($this->resolving["env({$name})"]);
|
||||
}
|
||||
}
|
||||
private function callMethod(object $service, array $call, array &$inlineServices)
|
||||
{
|
||||
foreach (self::getServiceConditionals($call[1]) as $s) {
|
||||
if (!$this->has($s)) {
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
foreach (self::getInitializedConditionals($call[1]) as $s) {
|
||||
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) {
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
$result = $service->{$call[0]}(...$this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices));
|
||||
return empty($call[2]) ? $service : $result;
|
||||
}
|
||||
private function shareService(Definition $definition, $service, ?string $id, array &$inlineServices)
|
||||
{
|
||||
$inlineServices[$id ?? \spl_object_hash($definition)] = $service;
|
||||
if (null !== $id && $definition->isShared()) {
|
||||
if ($definition->isPrivate() && $this->isCompiled()) {
|
||||
$this->privates[$id] = $service;
|
||||
} else {
|
||||
$this->services[$id] = $service;
|
||||
}
|
||||
unset($this->loading[$id]);
|
||||
}
|
||||
}
|
||||
private function getExpressionLanguage() : ExpressionLanguage
|
||||
{
|
||||
if (null === $this->expressionLanguage) {
|
||||
if (!\class_exists(\MailPoetVendor\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) {
|
||||
throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
|
||||
}
|
||||
$this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
|
||||
}
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
private function inVendors(string $path) : bool
|
||||
{
|
||||
if (null === $this->vendors) {
|
||||
$this->vendors = (new ComposerResource())->getVendors();
|
||||
}
|
||||
$path = \realpath($path) ?: $path;
|
||||
foreach ($this->vendors as $vendor) {
|
||||
if (\str_starts_with($path, $vendor) && \false !== \strpbrk(\substr($path, \strlen($vendor), 1), '/' . \DIRECTORY_SEPARATOR)) {
|
||||
$this->addResource(new FileResource($vendor . '/composer/installed.json'));
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
interface ContainerInterface extends PsrContainerInterface
|
||||
{
|
||||
public const RUNTIME_EXCEPTION_ON_INVALID_REFERENCE = 0;
|
||||
public const EXCEPTION_ON_INVALID_REFERENCE = 1;
|
||||
public const NULL_ON_INVALID_REFERENCE = 2;
|
||||
public const IGNORE_ON_INVALID_REFERENCE = 3;
|
||||
public const IGNORE_ON_UNINITIALIZED_REFERENCE = 4;
|
||||
public function set(string $id, ?object $service);
|
||||
public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
public function has(string $id);
|
||||
public function initialized(string $id);
|
||||
public function getParameter(string $name);
|
||||
public function hasParameter(string $name);
|
||||
public function setParameter(string $name, $value);
|
||||
}
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
class Definition
|
||||
{
|
||||
private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.';
|
||||
private $class;
|
||||
private $file;
|
||||
private $factory;
|
||||
private $shared = \true;
|
||||
private $deprecation = [];
|
||||
private $properties = [];
|
||||
private $calls = [];
|
||||
private $instanceof = [];
|
||||
private $autoconfigured = \false;
|
||||
private $configurator;
|
||||
private $tags = [];
|
||||
private $public = \false;
|
||||
private $synthetic = \false;
|
||||
private $abstract = \false;
|
||||
private $lazy = \false;
|
||||
private $decoratedService;
|
||||
private $autowired = \false;
|
||||
private $changes = [];
|
||||
private $bindings = [];
|
||||
private $errors = [];
|
||||
protected $arguments = [];
|
||||
public $innerServiceId;
|
||||
public $decorationOnInvalid;
|
||||
public function __construct(?string $class = null, array $arguments = [])
|
||||
{
|
||||
if (null !== $class) {
|
||||
$this->setClass($class);
|
||||
}
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
public function getChanges()
|
||||
{
|
||||
return $this->changes;
|
||||
}
|
||||
public function setChanges(array $changes)
|
||||
{
|
||||
$this->changes = $changes;
|
||||
return $this;
|
||||
}
|
||||
public function setFactory($factory)
|
||||
{
|
||||
$this->changes['factory'] = \true;
|
||||
if (\is_string($factory) && \str_contains($factory, '::')) {
|
||||
$factory = \explode('::', $factory, 2);
|
||||
} elseif ($factory instanceof Reference) {
|
||||
$factory = [$factory, '__invoke'];
|
||||
}
|
||||
$this->factory = $factory;
|
||||
return $this;
|
||||
}
|
||||
public function getFactory()
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
public function setDecoratedService(?string $id, ?string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
if ($renamedId && $id === $renamedId) {
|
||||
throw new InvalidArgumentException(\sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
|
||||
}
|
||||
$this->changes['decorated_service'] = \true;
|
||||
if (null === $id) {
|
||||
$this->decoratedService = null;
|
||||
} else {
|
||||
$this->decoratedService = [$id, $renamedId, $priority];
|
||||
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
|
||||
$this->decoratedService[] = $invalidBehavior;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function getDecoratedService()
|
||||
{
|
||||
return $this->decoratedService;
|
||||
}
|
||||
public function setClass(?string $class)
|
||||
{
|
||||
$this->changes['class'] = \true;
|
||||
$this->class = $class;
|
||||
return $this;
|
||||
}
|
||||
public function getClass()
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
return $this;
|
||||
}
|
||||
public function setProperties(array $properties)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
return $this;
|
||||
}
|
||||
public function getProperties()
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
public function setProperty(string $name, $value)
|
||||
{
|
||||
$this->properties[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
public function addArgument($argument)
|
||||
{
|
||||
$this->arguments[] = $argument;
|
||||
return $this;
|
||||
}
|
||||
public function replaceArgument($index, $argument)
|
||||
{
|
||||
if (0 === \count($this->arguments)) {
|
||||
throw new OutOfBoundsException(\sprintf('Cannot replace arguments for class "%s" if none have been configured yet.', $this->class));
|
||||
}
|
||||
if (\is_int($index) && ($index < 0 || $index > \count($this->arguments) - 1)) {
|
||||
throw new OutOfBoundsException(\sprintf('The index "%d" is not in the range [0, %d] of the arguments of class "%s".', $index, \count($this->arguments) - 1, $this->class));
|
||||
}
|
||||
if (!\array_key_exists($index, $this->arguments)) {
|
||||
throw new OutOfBoundsException(\sprintf('The argument "%s" doesn\'t exist in class "%s".', $index, $this->class));
|
||||
}
|
||||
$this->arguments[$index] = $argument;
|
||||
return $this;
|
||||
}
|
||||
public function setArgument($key, $value)
|
||||
{
|
||||
$this->arguments[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (!\array_key_exists($index, $this->arguments)) {
|
||||
throw new OutOfBoundsException(\sprintf('The argument "%s" doesn\'t exist in class "%s".', $index, $this->class));
|
||||
}
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
public function setMethodCalls(array $calls = [])
|
||||
{
|
||||
$this->calls = [];
|
||||
foreach ($calls as $call) {
|
||||
$this->addMethodCall($call[0], $call[1], $call[2] ?? \false);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addMethodCall(string $method, array $arguments = [], bool $returnsClone = \false)
|
||||
{
|
||||
if (empty($method)) {
|
||||
throw new InvalidArgumentException('Method name cannot be empty.');
|
||||
}
|
||||
$this->calls[] = $returnsClone ? [$method, $arguments, \true] : [$method, $arguments];
|
||||
return $this;
|
||||
}
|
||||
public function removeMethodCall(string $method)
|
||||
{
|
||||
foreach ($this->calls as $i => $call) {
|
||||
if ($call[0] === $method) {
|
||||
unset($this->calls[$i]);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function hasMethodCall(string $method)
|
||||
{
|
||||
foreach ($this->calls as $call) {
|
||||
if ($call[0] === $method) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function getMethodCalls()
|
||||
{
|
||||
return $this->calls;
|
||||
}
|
||||
public function setInstanceofConditionals(array $instanceof)
|
||||
{
|
||||
$this->instanceof = $instanceof;
|
||||
return $this;
|
||||
}
|
||||
public function getInstanceofConditionals()
|
||||
{
|
||||
return $this->instanceof;
|
||||
}
|
||||
public function setAutoconfigured(bool $autoconfigured)
|
||||
{
|
||||
$this->changes['autoconfigured'] = \true;
|
||||
$this->autoconfigured = $autoconfigured;
|
||||
return $this;
|
||||
}
|
||||
public function isAutoconfigured()
|
||||
{
|
||||
return $this->autoconfigured;
|
||||
}
|
||||
public function setTags(array $tags)
|
||||
{
|
||||
$this->tags = $tags;
|
||||
return $this;
|
||||
}
|
||||
public function getTags()
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
public function getTag(string $name)
|
||||
{
|
||||
return $this->tags[$name] ?? [];
|
||||
}
|
||||
public function addTag(string $name, array $attributes = [])
|
||||
{
|
||||
$this->tags[$name][] = $attributes;
|
||||
return $this;
|
||||
}
|
||||
public function hasTag(string $name)
|
||||
{
|
||||
return isset($this->tags[$name]);
|
||||
}
|
||||
public function clearTag(string $name)
|
||||
{
|
||||
unset($this->tags[$name]);
|
||||
return $this;
|
||||
}
|
||||
public function clearTags()
|
||||
{
|
||||
$this->tags = [];
|
||||
return $this;
|
||||
}
|
||||
public function setFile(?string $file)
|
||||
{
|
||||
$this->changes['file'] = \true;
|
||||
$this->file = $file;
|
||||
return $this;
|
||||
}
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
public function setShared(bool $shared)
|
||||
{
|
||||
$this->changes['shared'] = \true;
|
||||
$this->shared = $shared;
|
||||
return $this;
|
||||
}
|
||||
public function isShared()
|
||||
{
|
||||
return $this->shared;
|
||||
}
|
||||
public function setPublic(bool $boolean)
|
||||
{
|
||||
$this->changes['public'] = \true;
|
||||
$this->public = $boolean;
|
||||
return $this;
|
||||
}
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
public function setPrivate(bool $boolean)
|
||||
{
|
||||
trigger_deprecation('symfony/dependency-injection', '5.2', 'The "%s()" method is deprecated, use "setPublic()" instead.', __METHOD__);
|
||||
return $this->setPublic(!$boolean);
|
||||
}
|
||||
public function isPrivate()
|
||||
{
|
||||
return !$this->public;
|
||||
}
|
||||
public function setLazy(bool $lazy)
|
||||
{
|
||||
$this->changes['lazy'] = \true;
|
||||
$this->lazy = $lazy;
|
||||
return $this;
|
||||
}
|
||||
public function isLazy()
|
||||
{
|
||||
return $this->lazy;
|
||||
}
|
||||
public function setSynthetic(bool $boolean)
|
||||
{
|
||||
$this->synthetic = $boolean;
|
||||
if (!isset($this->changes['public'])) {
|
||||
$this->setPublic(\true);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function isSynthetic()
|
||||
{
|
||||
return $this->synthetic;
|
||||
}
|
||||
public function setAbstract(bool $boolean)
|
||||
{
|
||||
$this->abstract = $boolean;
|
||||
return $this;
|
||||
}
|
||||
public function isAbstract()
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
public function setDeprecated()
|
||||
{
|
||||
$args = \func_get_args();
|
||||
if (\func_num_args() < 3) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'The signature of method "%s()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.', __METHOD__);
|
||||
$status = $args[0] ?? \true;
|
||||
if (!$status) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Passing a null message to un-deprecate a node is deprecated.');
|
||||
}
|
||||
$message = (string) ($args[1] ?? null);
|
||||
$package = $version = '';
|
||||
} else {
|
||||
$status = \true;
|
||||
$package = (string) $args[0];
|
||||
$version = (string) $args[1];
|
||||
$message = (string) $args[2];
|
||||
}
|
||||
if ('' !== $message) {
|
||||
if (\preg_match('#[\\r\\n]|\\*/#', $message)) {
|
||||
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
|
||||
}
|
||||
if (!\str_contains($message, '%service_id%')) {
|
||||
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
|
||||
}
|
||||
}
|
||||
$this->changes['deprecated'] = \true;
|
||||
$this->deprecation = $status ? ['package' => $package, 'version' => $version, 'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE] : [];
|
||||
return $this;
|
||||
}
|
||||
public function isDeprecated()
|
||||
{
|
||||
return (bool) $this->deprecation;
|
||||
}
|
||||
public function getDeprecationMessage(string $id)
|
||||
{
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'The "%s()" method is deprecated, use "getDeprecation()" instead.', __METHOD__);
|
||||
return $this->getDeprecation($id)['message'];
|
||||
}
|
||||
public function getDeprecation(string $id) : array
|
||||
{
|
||||
return ['package' => $this->deprecation['package'], 'version' => $this->deprecation['version'], 'message' => \str_replace('%service_id%', $id, $this->deprecation['message'])];
|
||||
}
|
||||
public function setConfigurator($configurator)
|
||||
{
|
||||
$this->changes['configurator'] = \true;
|
||||
if (\is_string($configurator) && \str_contains($configurator, '::')) {
|
||||
$configurator = \explode('::', $configurator, 2);
|
||||
} elseif ($configurator instanceof Reference) {
|
||||
$configurator = [$configurator, '__invoke'];
|
||||
}
|
||||
$this->configurator = $configurator;
|
||||
return $this;
|
||||
}
|
||||
public function getConfigurator()
|
||||
{
|
||||
return $this->configurator;
|
||||
}
|
||||
public function isAutowired()
|
||||
{
|
||||
return $this->autowired;
|
||||
}
|
||||
public function setAutowired(bool $autowired)
|
||||
{
|
||||
$this->changes['autowired'] = \true;
|
||||
$this->autowired = $autowired;
|
||||
return $this;
|
||||
}
|
||||
public function getBindings()
|
||||
{
|
||||
return $this->bindings;
|
||||
}
|
||||
public function setBindings(array $bindings)
|
||||
{
|
||||
foreach ($bindings as $key => $binding) {
|
||||
if (0 < \strpos($key, '$') && $key !== ($k = \preg_replace('/[ \\t]*\\$/', ' $', $key))) {
|
||||
unset($bindings[$key]);
|
||||
$bindings[$key = $k] = $binding;
|
||||
}
|
||||
if (!$binding instanceof BoundArgument) {
|
||||
$bindings[$key] = new BoundArgument($binding);
|
||||
}
|
||||
}
|
||||
$this->bindings = $bindings;
|
||||
return $this;
|
||||
}
|
||||
public function addError($error)
|
||||
{
|
||||
if ($error instanceof self) {
|
||||
$this->errors = \array_merge($this->errors, $error->errors);
|
||||
} else {
|
||||
$this->errors[] = $error;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function getErrors()
|
||||
{
|
||||
foreach ($this->errors as $i => $error) {
|
||||
if ($error instanceof \Closure) {
|
||||
$this->errors[$i] = (string) $error();
|
||||
} elseif (!\is_string($error)) {
|
||||
$this->errors[$i] = (string) $error;
|
||||
}
|
||||
}
|
||||
return $this->errors;
|
||||
}
|
||||
public function hasErrors() : bool
|
||||
{
|
||||
return (bool) $this->errors;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface EnvVarLoaderInterface
|
||||
{
|
||||
public function loadEnvVars() : array;
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
class EnvVarProcessor implements EnvVarProcessorInterface
|
||||
{
|
||||
private $container;
|
||||
private $loaders;
|
||||
private $loadedVars = [];
|
||||
public function __construct(ContainerInterface $container, ?\Traversable $loaders = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->loaders = $loaders ?? new \ArrayIterator();
|
||||
}
|
||||
public static function getProvidedTypes()
|
||||
{
|
||||
return ['base64' => 'string', 'bool' => 'bool', 'not' => 'bool', 'const' => 'bool|int|float|string|array', 'csv' => 'array', 'file' => 'string', 'float' => 'float', 'int' => 'int', 'json' => 'array', 'key' => 'bool|int|float|string|array', 'url' => 'array', 'query_string' => 'array', 'resolve' => 'string', 'default' => 'bool|int|float|string|array', 'string' => 'string', 'trim' => 'string', 'require' => 'bool|int|float|string|array'];
|
||||
}
|
||||
public function getEnv(string $prefix, string $name, \Closure $getEnv)
|
||||
{
|
||||
$i = \strpos($name, ':');
|
||||
if ('key' === $prefix) {
|
||||
if (\false === $i) {
|
||||
throw new RuntimeException(\sprintf('Invalid env "key:%s": a key specifier should be provided.', $name));
|
||||
}
|
||||
$next = \substr($name, $i + 1);
|
||||
$key = \substr($name, 0, $i);
|
||||
$array = $getEnv($next);
|
||||
if (!\is_array($array)) {
|
||||
throw new RuntimeException(\sprintf('Resolved value of "%s" did not result in an array value.', $next));
|
||||
}
|
||||
if (!isset($array[$key]) && !\array_key_exists($key, $array)) {
|
||||
throw new EnvNotFoundException(\sprintf('Key "%s" not found in %s (resolved from "%s").', $key, \json_encode($array), $next));
|
||||
}
|
||||
return $array[$key];
|
||||
}
|
||||
if ('default' === $prefix) {
|
||||
if (\false === $i) {
|
||||
throw new RuntimeException(\sprintf('Invalid env "default:%s": a fallback parameter should be provided.', $name));
|
||||
}
|
||||
$next = \substr($name, $i + 1);
|
||||
$default = \substr($name, 0, $i);
|
||||
if ('' !== $default && !$this->container->hasParameter($default)) {
|
||||
throw new RuntimeException(\sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.', $name, $default));
|
||||
}
|
||||
try {
|
||||
$env = $getEnv($next);
|
||||
if ('' !== $env && null !== $env) {
|
||||
return $env;
|
||||
}
|
||||
} catch (EnvNotFoundException $e) {
|
||||
// no-op
|
||||
}
|
||||
return '' === $default ? null : $this->container->getParameter($default);
|
||||
}
|
||||
if ('file' === $prefix || 'require' === $prefix) {
|
||||
if (!\is_scalar($file = $getEnv($name))) {
|
||||
throw new RuntimeException(\sprintf('Invalid file name: env var "%s" is non-scalar.', $name));
|
||||
}
|
||||
if (!\is_file($file)) {
|
||||
throw new EnvNotFoundException(\sprintf('File "%s" not found (resolved from "%s").', $file, $name));
|
||||
}
|
||||
if ('file' === $prefix) {
|
||||
return \file_get_contents($file);
|
||||
} else {
|
||||
return require $file;
|
||||
}
|
||||
}
|
||||
$returnNull = \false;
|
||||
if ('' === $prefix) {
|
||||
$returnNull = \true;
|
||||
$prefix = 'string';
|
||||
}
|
||||
if (\false !== $i || 'string' !== $prefix) {
|
||||
$env = $getEnv($name);
|
||||
} elseif (isset($_ENV[$name])) {
|
||||
$env = $_ENV[$name];
|
||||
} elseif (isset($_SERVER[$name]) && !\str_starts_with($name, 'HTTP_')) {
|
||||
$env = $_SERVER[$name];
|
||||
} elseif (\false === ($env = \getenv($name)) || null === $env) {
|
||||
// null is a possible value because of thread safety issues
|
||||
foreach ($this->loadedVars as $vars) {
|
||||
if (\false !== ($env = $vars[$name] ?? \false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (\false === $env || null === $env) {
|
||||
$loaders = $this->loaders;
|
||||
$this->loaders = new \ArrayIterator();
|
||||
try {
|
||||
$i = 0;
|
||||
$ended = \true;
|
||||
$count = $loaders instanceof \Countable ? $loaders->count() : 0;
|
||||
foreach ($loaders as $loader) {
|
||||
if (\count($this->loadedVars) > $i++) {
|
||||
continue;
|
||||
}
|
||||
$this->loadedVars[] = $vars = $loader->loadEnvVars();
|
||||
if (\false !== ($env = $vars[$name] ?? \false)) {
|
||||
$ended = \false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($ended || $count === $i) {
|
||||
$loaders = $this->loaders;
|
||||
}
|
||||
} catch (ParameterCircularReferenceException $e) {
|
||||
// skip loaders that need an env var that is not defined
|
||||
} finally {
|
||||
$this->loaders = $loaders;
|
||||
}
|
||||
}
|
||||
if (\false === $env || null === $env) {
|
||||
if (!$this->container->hasParameter("env({$name})")) {
|
||||
throw new EnvNotFoundException(\sprintf('Environment variable not found: "%s".', $name));
|
||||
}
|
||||
$env = $this->container->getParameter("env({$name})");
|
||||
}
|
||||
}
|
||||
if (null === $env) {
|
||||
if ($returnNull) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($this->getProvidedTypes()[$prefix])) {
|
||||
throw new RuntimeException(\sprintf('Unsupported env var prefix "%s".', $prefix));
|
||||
}
|
||||
if (!\in_array($prefix, ['string', 'bool', 'not', 'int', 'float'], \true)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (null !== $env && !\is_scalar($env)) {
|
||||
throw new RuntimeException(\sprintf('Non-scalar env var "%s" cannot be cast to "%s".', $name, $prefix));
|
||||
}
|
||||
if ('string' === $prefix) {
|
||||
return (string) $env;
|
||||
}
|
||||
if (\in_array($prefix, ['bool', 'not'], \true)) {
|
||||
$env = (bool) ((\filter_var($env, \FILTER_VALIDATE_BOOLEAN) ?: \filter_var($env, \FILTER_VALIDATE_INT)) ?: \filter_var($env, \FILTER_VALIDATE_FLOAT));
|
||||
return 'not' === $prefix ? !$env : $env;
|
||||
}
|
||||
if ('int' === $prefix) {
|
||||
if (null !== $env && \false === ($env = \filter_var($env, \FILTER_VALIDATE_INT) ?: \filter_var($env, \FILTER_VALIDATE_FLOAT))) {
|
||||
throw new RuntimeException(\sprintf('Non-numeric env var "%s" cannot be cast to int.', $name));
|
||||
}
|
||||
return (int) $env;
|
||||
}
|
||||
if ('float' === $prefix) {
|
||||
if (null !== $env && \false === ($env = \filter_var($env, \FILTER_VALIDATE_FLOAT))) {
|
||||
throw new RuntimeException(\sprintf('Non-numeric env var "%s" cannot be cast to float.', $name));
|
||||
}
|
||||
return (float) $env;
|
||||
}
|
||||
if ('const' === $prefix) {
|
||||
if (!\defined($env)) {
|
||||
throw new RuntimeException(\sprintf('Env var "%s" maps to undefined constant "%s".', $name, $env));
|
||||
}
|
||||
return \constant($env);
|
||||
}
|
||||
if ('base64' === $prefix) {
|
||||
return \base64_decode(\strtr($env, '-_', '+/'));
|
||||
}
|
||||
if ('json' === $prefix) {
|
||||
$env = \json_decode($env, \true);
|
||||
if (\JSON_ERROR_NONE !== \json_last_error()) {
|
||||
throw new RuntimeException(\sprintf('Invalid JSON in env var "%s": ', $name) . \json_last_error_msg());
|
||||
}
|
||||
if (null !== $env && !\is_array($env)) {
|
||||
throw new RuntimeException(\sprintf('Invalid JSON env var "%s": array or null expected, "%s" given.', $name, \get_debug_type($env)));
|
||||
}
|
||||
return $env;
|
||||
}
|
||||
if ('url' === $prefix) {
|
||||
$params = \parse_url($env);
|
||||
if (\false === $params) {
|
||||
throw new RuntimeException(\sprintf('Invalid URL in env var "%s".', $name));
|
||||
}
|
||||
if (!isset($params['scheme'], $params['host'])) {
|
||||
throw new RuntimeException(\sprintf('Invalid URL env var "%s": schema and host expected, "%s" given.', $name, $env));
|
||||
}
|
||||
$params += ['port' => null, 'user' => null, 'pass' => null, 'path' => null, 'query' => null, 'fragment' => null];
|
||||
$params['user'] = null !== $params['user'] ? \rawurldecode($params['user']) : null;
|
||||
$params['pass'] = null !== $params['pass'] ? \rawurldecode($params['pass']) : null;
|
||||
// remove the '/' separator
|
||||
$params['path'] = '/' === ($params['path'] ?? '/') ? '' : \substr($params['path'], 1);
|
||||
return $params;
|
||||
}
|
||||
if ('query_string' === $prefix) {
|
||||
$queryString = \parse_url($env, \PHP_URL_QUERY) ?: $env;
|
||||
\parse_str($queryString, $result);
|
||||
return $result;
|
||||
}
|
||||
if ('resolve' === $prefix) {
|
||||
return \preg_replace_callback('/%%|%([^%\\s]+)%/', function ($match) use($name, $getEnv) {
|
||||
if (!isset($match[1])) {
|
||||
return '%';
|
||||
}
|
||||
if (\str_starts_with($match[1], 'env(') && \str_ends_with($match[1], ')') && 'env()' !== $match[1]) {
|
||||
$value = $getEnv(\substr($match[1], 4, -1));
|
||||
} else {
|
||||
$value = $this->container->getParameter($match[1]);
|
||||
}
|
||||
if (!\is_scalar($value)) {
|
||||
throw new RuntimeException(\sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.', $match[1], $name, \get_debug_type($value)));
|
||||
}
|
||||
return $value;
|
||||
}, $env);
|
||||
}
|
||||
if ('csv' === $prefix) {
|
||||
return \str_getcsv($env, ',', '"', \PHP_VERSION_ID >= 70400 ? '' : '\\');
|
||||
}
|
||||
if ('trim' === $prefix) {
|
||||
return \trim($env);
|
||||
}
|
||||
throw new RuntimeException(\sprintf('Unsupported env var prefix "%s" for env name "%s".', $prefix, $name));
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
interface EnvVarProcessorInterface
|
||||
{
|
||||
public function getEnv(string $prefix, string $name, \Closure $getEnv);
|
||||
public static function getProvidedTypes();
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class AutowiringFailedException extends RuntimeException
|
||||
{
|
||||
private $serviceId;
|
||||
private $messageCallback;
|
||||
public function __construct(string $serviceId, $message = '', int $code = 0, ?\Throwable $previous = null)
|
||||
{
|
||||
$this->serviceId = $serviceId;
|
||||
if ($message instanceof \Closure && \function_exists('xdebug_is_enabled') && \xdebug_is_enabled()) {
|
||||
$message = $message();
|
||||
}
|
||||
if (!$message instanceof \Closure) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
return;
|
||||
}
|
||||
$this->messageCallback = $message;
|
||||
parent::__construct('', $code, $previous);
|
||||
$this->message = new class($this->message, $this->messageCallback)
|
||||
{
|
||||
private $message;
|
||||
private $messageCallback;
|
||||
public function __construct(&$message, &$messageCallback)
|
||||
{
|
||||
$this->message =& $message;
|
||||
$this->messageCallback =& $messageCallback;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$messageCallback = $this->messageCallback;
|
||||
$this->messageCallback = null;
|
||||
try {
|
||||
return $this->message = $messageCallback();
|
||||
} catch (\Throwable $e) {
|
||||
return $this->message = $e->getMessage();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
public function getMessageCallback() : ?\Closure
|
||||
{
|
||||
return $this->messageCallback;
|
||||
}
|
||||
public function getServiceId()
|
||||
{
|
||||
return $this->serviceId;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class EnvNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class EnvParameterException extends InvalidArgumentException
|
||||
{
|
||||
public function __construct(array $envs, ?\Throwable $previous = null, string $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.')
|
||||
{
|
||||
parent::__construct(\sprintf($message, \implode('", "', $envs)), 0, $previous);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Psr\Container\ContainerExceptionInterface;
|
||||
interface ExceptionInterface extends ContainerExceptionInterface, \Throwable
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class InvalidParameterTypeException extends InvalidArgumentException
|
||||
{
|
||||
public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter)
|
||||
{
|
||||
$acceptedType = $parameter->getType();
|
||||
$acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType;
|
||||
$this->code = $type;
|
||||
$function = $parameter->getDeclaringFunction();
|
||||
$functionName = $function instanceof \ReflectionMethod ? \sprintf('%s::%s', $function->getDeclaringClass()->getName(), $function->getName()) : $function->getName();
|
||||
parent::__construct(\sprintf('Invalid definition for service "%s": argument %d of "%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $functionName, $acceptedType, $type));
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class LogicException extends \LogicException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ParameterCircularReferenceException extends RuntimeException
|
||||
{
|
||||
private $parameters;
|
||||
public function __construct(array $parameters, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct(\sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], \implode('" > "', $parameters), $parameters[0]), 0, $previous);
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Psr\Container\NotFoundExceptionInterface;
|
||||
class ParameterNotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface
|
||||
{
|
||||
private $key;
|
||||
private $sourceId;
|
||||
private $sourceKey;
|
||||
private $alternatives;
|
||||
private $nonNestedAlternative;
|
||||
public function __construct(string $key, ?string $sourceId = null, ?string $sourceKey = null, ?\Throwable $previous = null, array $alternatives = [], ?string $nonNestedAlternative = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->sourceId = $sourceId;
|
||||
$this->sourceKey = $sourceKey;
|
||||
$this->alternatives = $alternatives;
|
||||
$this->nonNestedAlternative = $nonNestedAlternative;
|
||||
parent::__construct('', 0, $previous);
|
||||
$this->updateRepr();
|
||||
}
|
||||
public function updateRepr()
|
||||
{
|
||||
if (null !== $this->sourceId) {
|
||||
$this->message = \sprintf('The service "%s" has a dependency on a non-existent parameter "%s".', $this->sourceId, $this->key);
|
||||
} elseif (null !== $this->sourceKey) {
|
||||
$this->message = \sprintf('The parameter "%s" has a dependency on a non-existent parameter "%s".', $this->sourceKey, $this->key);
|
||||
} else {
|
||||
$this->message = \sprintf('You have requested a non-existent parameter "%s".', $this->key);
|
||||
}
|
||||
if ($this->alternatives) {
|
||||
if (1 == \count($this->alternatives)) {
|
||||
$this->message .= ' Did you mean this: "';
|
||||
} else {
|
||||
$this->message .= ' Did you mean one of these: "';
|
||||
}
|
||||
$this->message .= \implode('", "', $this->alternatives) . '"?';
|
||||
} elseif (null !== $this->nonNestedAlternative) {
|
||||
$this->message .= ' You cannot access nested array items, do you want to inject "' . $this->nonNestedAlternative . '" instead?';
|
||||
}
|
||||
}
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
public function getSourceId()
|
||||
{
|
||||
return $this->sourceId;
|
||||
}
|
||||
public function getSourceKey()
|
||||
{
|
||||
return $this->sourceKey;
|
||||
}
|
||||
public function setSourceId(?string $sourceId)
|
||||
{
|
||||
$this->sourceId = $sourceId;
|
||||
$this->updateRepr();
|
||||
}
|
||||
public function setSourceKey(?string $sourceKey)
|
||||
{
|
||||
$this->sourceKey = $sourceKey;
|
||||
$this->updateRepr();
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class ServiceCircularReferenceException extends RuntimeException
|
||||
{
|
||||
private $serviceId;
|
||||
private $path;
|
||||
public function __construct(string $serviceId, array $path, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct(\sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, \implode(' -> ', $path)), 0, $previous);
|
||||
$this->serviceId = $serviceId;
|
||||
$this->path = $path;
|
||||
}
|
||||
public function getServiceId()
|
||||
{
|
||||
return $this->serviceId;
|
||||
}
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user