Update core 8.3.0

This commit is contained in:
Rob Davies 2017-04-13 15:53:35 +01:00
parent da7a7918f8
commit cd7a898e66
6144 changed files with 132297 additions and 87747 deletions

View file

@ -18,7 +18,7 @@ use Symfony\Component\CssSelector\CssSelectorConverter;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Crawler extends \SplObjectStorage
class Crawler implements \Countable, \IteratorAggregate
{
/**
* @var string The current URI
@ -45,6 +45,11 @@ class Crawler extends \SplObjectStorage
*/
private $document;
/**
* @var \DOMElement[]
*/
private $nodes = array();
/**
* Whether the Crawler contains HTML or XML content (used when converting CSS to XPath).
*
@ -72,7 +77,7 @@ class Crawler extends \SplObjectStorage
*/
public function clear()
{
parent::removeAll($this);
$this->nodes = array();
$this->document = null;
}
@ -294,25 +299,19 @@ class Crawler extends \SplObjectStorage
}
if (null !== $this->document && $this->document !== $node->ownerDocument) {
@trigger_error('Attaching DOM nodes from multiple documents in a Crawler is deprecated as of 2.8 and will be forbidden in 3.0.', E_USER_DEPRECATED);
throw new \InvalidArgumentException('Attaching DOM nodes from multiple documents in the same crawler is forbidden.');
}
if (null === $this->document) {
$this->document = $node->ownerDocument;
}
parent::attach($node);
}
// Don't add duplicate nodes in the Crawler
if (in_array($node, $this->nodes, true)) {
return;
}
// Serializing and unserializing a crawler creates DOM objects in a corrupted state. DOM elements are not properly serializable.
public function unserialize($serialized)
{
throw new \BadMethodCallException('A Crawler cannot be serialized.');
}
public function serialize()
{
throw new \BadMethodCallException('A Crawler cannot be serialized.');
$this->nodes[] = $node;
}
/**
@ -320,14 +319,12 @@ class Crawler extends \SplObjectStorage
*
* @param int $position The position
*
* @return self
* @return Crawler A new instance of the Crawler with the selected node, or an empty Crawler if it does not exist
*/
public function eq($position)
{
foreach ($this as $i => $node) {
if ($i == $position) {
return $this->createSubCrawler($node);
}
if (isset($this->nodes[$position])) {
return $this->createSubCrawler($this->nodes[$position]);
}
return $this->createSubCrawler(null);
@ -352,7 +349,7 @@ class Crawler extends \SplObjectStorage
public function each(\Closure $closure)
{
$data = array();
foreach ($this as $i => $node) {
foreach ($this->nodes as $i => $node) {
$data[] = $closure($this->createSubCrawler($node), $i);
}
@ -365,11 +362,11 @@ class Crawler extends \SplObjectStorage
* @param int $offset
* @param int $length
*
* @return self
* @return Crawler A Crawler instance with the sliced nodes
*/
public function slice($offset = 0, $length = -1)
public function slice($offset = 0, $length = null)
{
return $this->createSubCrawler(iterator_to_array(new \LimitIterator($this, $offset, $length)));
return $this->createSubCrawler(array_slice($this->nodes, $offset, $length));
}
/**
@ -379,12 +376,12 @@ class Crawler extends \SplObjectStorage
*
* @param \Closure $closure An anonymous function
*
* @return self
* @return Crawler A Crawler instance with the selected nodes
*/
public function reduce(\Closure $closure)
{
$nodes = array();
foreach ($this as $i => $node) {
foreach ($this->nodes as $i => $node) {
if (false !== $closure($this->createSubCrawler($node), $i)) {
$nodes[] = $node;
}
@ -396,7 +393,7 @@ class Crawler extends \SplObjectStorage
/**
* Returns the first node of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the first selected node
*/
public function first()
{
@ -406,23 +403,23 @@ class Crawler extends \SplObjectStorage
/**
* Returns the last node of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the last selected node
*/
public function last()
{
return $this->eq(count($this) - 1);
return $this->eq(count($this->nodes) - 1);
}
/**
* Returns the siblings nodes of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the sibling nodes
*
* @throws \InvalidArgumentException When current node is empty
*/
public function siblings()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -432,13 +429,13 @@ class Crawler extends \SplObjectStorage
/**
* Returns the next siblings nodes of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the next sibling nodes
*
* @throws \InvalidArgumentException When current node is empty
*/
public function nextAll()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -448,13 +445,13 @@ class Crawler extends \SplObjectStorage
/**
* Returns the previous sibling nodes of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the previous sibling nodes
*
* @throws \InvalidArgumentException
*/
public function previousAll()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -464,13 +461,13 @@ class Crawler extends \SplObjectStorage
/**
* Returns the parents nodes of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the parents nodes of the current selection
*
* @throws \InvalidArgumentException When current node is empty
*/
public function parents()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -489,13 +486,13 @@ class Crawler extends \SplObjectStorage
/**
* Returns the children nodes of the current selection.
*
* @return self
* @return Crawler A Crawler instance with the children nodes
*
* @throws \InvalidArgumentException When current node is empty
*/
public function children()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -515,7 +512,7 @@ class Crawler extends \SplObjectStorage
*/
public function attr($attribute)
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -533,7 +530,7 @@ class Crawler extends \SplObjectStorage
*/
public function nodeName()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -549,7 +546,7 @@ class Crawler extends \SplObjectStorage
*/
public function text()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -565,7 +562,7 @@ class Crawler extends \SplObjectStorage
*/
public function html()
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -596,7 +593,7 @@ class Crawler extends \SplObjectStorage
$count = count($attributes);
$data = array();
foreach ($this as $node) {
foreach ($this->nodes as $node) {
$elements = array();
foreach ($attributes as $attribute) {
if ('_text' === $attribute) {
@ -622,7 +619,7 @@ class Crawler extends \SplObjectStorage
*
* @param string $xpath An XPath expression
*
* @return self
* @return Crawler A new instance of Crawler with the filtered list of nodes
*/
public function filterXPath($xpath)
{
@ -643,7 +640,7 @@ class Crawler extends \SplObjectStorage
*
* @param string $selector A CSS selector
*
* @return self
* @return Crawler A new instance of Crawler with the filtered list of nodes
*
* @throws \RuntimeException if the CssSelector Component is not available
*/
@ -664,7 +661,7 @@ class Crawler extends \SplObjectStorage
*
* @param string $value The link text
*
* @return self
* @return Crawler A new instance of Crawler with the filtered list of nodes
*/
public function selectLink($value)
{
@ -679,7 +676,7 @@ class Crawler extends \SplObjectStorage
*
* @param string $value The button text
*
* @return self
* @return Crawler A new instance of Crawler with the filtered list of nodes
*/
public function selectButton($value)
{
@ -702,7 +699,7 @@ class Crawler extends \SplObjectStorage
*/
public function link($method = 'get')
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -725,7 +722,7 @@ class Crawler extends \SplObjectStorage
public function links()
{
$links = array();
foreach ($this as $node) {
foreach ($this->nodes as $node) {
if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', get_class($node)));
}
@ -748,7 +745,7 @@ class Crawler extends \SplObjectStorage
*/
public function form(array $values = null, $method = null)
{
if (!count($this)) {
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}
@ -830,127 +827,7 @@ class Crawler extends \SplObjectStorage
}
}
return sprintf('concat(%s)', implode(', ', $parts));
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function attach($object, $data = null)
{
$this->triggerDeprecation(__METHOD__);
parent::attach($object, $data);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function detach($object)
{
$this->triggerDeprecation(__METHOD__);
parent::detach($object);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function contains($object)
{
$this->triggerDeprecation(__METHOD__);
return parent::contains($object);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function addAll($storage)
{
$this->triggerDeprecation(__METHOD__);
parent::addAll($storage);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function removeAll($storage)
{
$this->triggerDeprecation(__METHOD__);
parent::removeAll($storage);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function removeAllExcept($storage)
{
$this->triggerDeprecation(__METHOD__);
parent::removeAllExcept($storage);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function getInfo()
{
$this->triggerDeprecation(__METHOD__);
return parent::getInfo();
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function setInfo($data)
{
$this->triggerDeprecation(__METHOD__);
parent::setInfo($data);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function offsetExists($object)
{
$this->triggerDeprecation(__METHOD__);
return parent::offsetExists($object);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function offsetSet($object, $data = null)
{
$this->triggerDeprecation(__METHOD__);
parent::offsetSet($object, $data);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function offsetUnset($object)
{
$this->triggerDeprecation(__METHOD__);
parent::offsetUnset($object);
}
/**
* @deprecated Using the SplObjectStorage API on the Crawler is deprecated as of 2.8 and will be removed in 3.0.
*/
public function offsetGet($object)
{
$this->triggerDeprecation(__METHOD__);
return parent::offsetGet($object);
return sprintf('concat(%s)', implode($parts, ', '));
}
/**
@ -960,7 +837,7 @@ class Crawler extends \SplObjectStorage
*
* @param string $xpath
*
* @return self
* @return Crawler
*/
private function filterRelativeXPath($xpath)
{
@ -968,7 +845,7 @@ class Crawler extends \SplObjectStorage
$crawler = $this->createSubCrawler(null);
foreach ($this as $node) {
foreach ($this->nodes as $node) {
$domxpath = $this->createDOMXPath($node->ownerDocument, $prefixes);
$crawler->add($domxpath->query($xpath, $node));
}
@ -990,59 +867,29 @@ class Crawler extends \SplObjectStorage
{
$expressions = array();
$unionPattern = '/\|(?![^\[]*\])/';
// An expression which will never match to replace expressions which cannot match in the crawler
// We cannot simply drop
$nonMatchingExpression = 'a[name() = "b"]';
$xpathLen = strlen($xpath);
$openedBrackets = 0;
$startPosition = strspn($xpath, " \t\n\r\0\x0B");
// Split any unions into individual expressions.
foreach (preg_split($unionPattern, $xpath) as $expression) {
$expression = trim($expression);
$parenthesis = '';
for ($i = $startPosition; $i <= $xpathLen; ++$i) {
$i += strcspn($xpath, '"\'[]|', $i);
if ($i < $xpathLen) {
switch ($xpath[$i]) {
case '"':
case "'":
if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) {
return $xpath; // The XPath expression is invalid
}
continue 2;
case '[':
++$openedBrackets;
continue 2;
case ']':
--$openedBrackets;
continue 2;
}
}
if ($openedBrackets) {
continue;
// If the union is inside some braces, we need to preserve the opening braces and apply
// the change only inside it.
if (preg_match('/^[\(\s*]+/', $expression, $matches)) {
$parenthesis = $matches[0];
$expression = substr($expression, strlen($parenthesis));
}
if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) {
// If the union is inside some braces, we need to preserve the opening braces and apply
// the change only inside it.
$j = 1 + strspn($xpath, "( \t\n\r\0\x0B", $startPosition + 1);
$parenthesis = substr($xpath, $startPosition, $j);
$startPosition += $j;
} else {
$parenthesis = '';
}
$expression = rtrim(substr($xpath, $startPosition, $i - $startPosition));
// BC for Symfony 2.4 and lower were elements were adding in a fake _root parent
if (0 === strpos($expression, '/_root/')) {
@trigger_error('XPath expressions referencing the fake root node are deprecated since version 2.8 and will be unsupported in 3.0. Please use "./" instead of "/_root/".', E_USER_DEPRECATED);
$expression = './'.substr($expression, 7);
} elseif (0 === strpos($expression, 'self::*/')) {
if (0 === strpos($expression, 'self::*/')) {
$expression = './'.substr($expression, 8);
}
// add prefix before absolute element selector
if ('' === $expression) {
if (empty($expression)) {
$expression = $nonMatchingExpression;
} elseif (0 === strpos($expression, '//')) {
$expression = 'descendant-or-self::'.substr($expression, 2);
@ -1052,15 +899,10 @@ class Crawler extends \SplObjectStorage
$expression = 'self::'.substr($expression, 2);
} elseif (0 === strpos($expression, 'child::')) {
$expression = 'self::'.substr($expression, 7);
} elseif ('/' === $expression[0] || 0 === strpos($expression, 'self::')) {
// the only direct child in Symfony 2.4 and lower is _root, which is already handled previously
// so let's drop the expression entirely
$expression = $nonMatchingExpression;
} elseif ('.' === $expression[0]) {
// '.' is the fake root element in Symfony 2.4 and lower, which is excluded from results
} elseif ('/' === $expression[0] || '.' === $expression[0] || 0 === strpos($expression, 'self::')) {
$expression = $nonMatchingExpression;
} elseif (0 === strpos($expression, 'descendant::')) {
$expression = 'descendant-or-self::'.substr($expression, 12);
$expression = 'descendant-or-self::'.substr($expression, strlen('descendant::'));
} elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) {
// the fake root has no parent, preceding or following nodes and also no attributes (even no namespace attributes)
$expression = $nonMatchingExpression;
@ -1068,16 +910,9 @@ class Crawler extends \SplObjectStorage
$expression = 'self::'.$expression;
}
$expressions[] = $parenthesis.$expression;
if ($i === $xpathLen) {
return implode(' | ', $expressions);
}
$i += strspn($xpath, " \t\n\r\0\x0B", $i + 1);
$startPosition = $i + 1;
}
return $xpath; // The XPath expression is invalid
return implode(' | ', $expressions);
}
/**
@ -1087,13 +922,27 @@ class Crawler extends \SplObjectStorage
*/
public function getNode($position)
{
foreach ($this as $i => $node) {
if ($i == $position) {
return $node;
}
if (isset($this->nodes[$position])) {
return $this->nodes[$position];
}
}
/**
* @return int
*/
public function count()
{
return count($this->nodes);
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->nodes);
}
/**
* @param \DOMElement $node
* @param string $siblingDir
@ -1187,23 +1036,4 @@ class Crawler extends \SplObjectStorage
return $crawler;
}
private function triggerDeprecation($methodName, $useTrace = false)
{
if ($useTrace || defined('HHVM_VERSION')) {
if (PHP_VERSION_ID >= 50400) {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
} else {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
// The SplObjectStorage class performs calls to its own methods. These
// method calls must not lead to triggered deprecation notices.
if (isset($trace[2]['class']) && 'SplObjectStorage' === $trace[2]['class']) {
return;
}
}
@trigger_error('The '.$methodName.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
}