This commit is contained in:
emmymayo
2025-02-05 23:15:46 +01:00
commit 7269c99357
16995 changed files with 3389680 additions and 0 deletions
@@ -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));
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
if (!defined('ABSPATH')) exit;
interface ExceptionInterface extends \Throwable
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
if (!defined('ABSPATH')) exit;
class ExpressionErrorException extends ParseException
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
if (!defined('ABSPATH')) exit;
class InternalErrorException extends ParseException
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\CssSelector\Exception;
if (!defined('ABSPATH')) exit;
class ParseException extends \Exception implements ExceptionInterface
{
}
@@ -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,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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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,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;
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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());
}
}
@@ -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;
}
}
@@ -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 [];
}
}
@@ -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 [];
}
}
@@ -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 [];
}
}
@@ -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 [];
}
}
@@ -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);
}
}
@@ -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();
}
}
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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';
}
}
@@ -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 [];
}
}
@@ -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';
}
}
@@ -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';
}
}
@@ -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;
}
@@ -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';
}
}
@@ -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';
}
}
@@ -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);
}
}
@@ -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';
}
}
@@ -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);
}
}
@@ -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,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;
}
}
@@ -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 . '.';
}
}
@@ -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);
}
@@ -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;
}
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Argument;
if (!defined('ABSPATH')) exit;
class IteratorArgument implements ArgumentInterface
{
use ReferenceSetArgumentTrait;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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));
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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)
{
}
}
@@ -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)
{
}
}
@@ -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]]);
}
}
@@ -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)
{
}
}
@@ -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)
{
}
}
@@ -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;
}
}
@@ -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)
{
}
}
@@ -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;
}
}
@@ -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()
{
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
if (!defined('ABSPATH')) exit;
interface ContainerAwareInterface
{
public function setContainer(?ContainerInterface $container = null);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
@@ -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;
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection;
if (!defined('ABSPATH')) exit;
interface EnvVarLoaderInterface
{
public function loadEnvVars() : array;
}
@@ -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));
}
}
@@ -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();
}
@@ -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;
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class EnvNotFoundException extends InvalidArgumentException
{
}
@@ -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);
}
}
@@ -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
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
@@ -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));
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class LogicException extends \LogicException implements ExceptionInterface
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}
@@ -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;
}
}
@@ -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();
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\DependencyInjection\Exception;
if (!defined('ABSPATH')) exit;
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
@@ -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