package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

View File

@@ -55,49 +55,39 @@ abstract class AbstractUriElement
/**
* Gets the node associated with this link.
*
* @return \DOMElement
*/
public function getNode()
public function getNode(): \DOMElement
{
return $this->node;
}
/**
* Gets the method associated with this link.
*
* @return string
*/
public function getMethod()
public function getMethod(): string
{
return $this->method ?? 'GET';
}
/**
* Gets the URI associated with this link.
*
* @return string
*/
public function getUri()
public function getUri(): string
{
return UriResolver::resolve($this->getRawUri(), $this->currentUri);
}
/**
* Returns raw URI data.
*
* @return string
*/
abstract protected function getRawUri();
abstract protected function getRawUri(): string;
/**
* Returns the canonicalized URI path (see RFC 3986, section 5.2.4).
*
* @param string $path URI path
*
* @return string
*/
protected function canonicalizePath(string $path)
protected function canonicalizePath(string $path): string
{
if ('' === $path || '/' === $path) {
return $path;

View File

@@ -1,6 +1,11 @@
CHANGELOG
=========
6.0
---
* Remove `Crawler::parents()` method, use `ancestors()` instead
5.4
---

View File

@@ -30,62 +30,44 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* The default namespace prefix to be used with XPath and CSS expressions.
*
* @var string
*/
private $defaultNamespacePrefix = 'default';
private string $defaultNamespacePrefix = 'default';
/**
* A map of manually registered namespaces.
*
* @var array<string, string>
*/
private $namespaces = [];
private array $namespaces = [];
/**
* A map of cached namespaces.
*
* @var \ArrayObject
*/
private $cachedNamespaces;
private \ArrayObject $cachedNamespaces;
/**
* The base href value.
*
* @var string|null
*/
private $baseHref;
/**
* @var \DOMDocument|null
*/
private $document;
private ?string $baseHref;
private ?\DOMDocument $document = null;
/**
* @var list<\DOMNode>
*/
private $nodes = [];
private array $nodes = [];
/**
* Whether the Crawler contains HTML or XML content (used when converting CSS to XPath).
*
* @var bool
*/
private $isHtml = true;
private bool $isHtml = true;
/**
* @var HTML5|null
*/
private $html5Parser;
private HTML5 $html5Parser;
/**
* @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A Node to use as the base for the crawling
*/
public function __construct($node = null, string $uri = null, string $baseHref = null)
public function __construct(\DOMNodeList|\DOMNode|array|string $node = null, string $uri = null, string $baseHref = null)
{
$this->uri = $uri;
$this->baseHref = $baseHref ?: $uri;
$this->html5Parser = class_exists(HTML5::class) ? new HTML5(['disable_html_ns' => true]) : null;
$this->html5Parser = new HTML5(['disable_html_ns' => true]);
$this->cachedNamespaces = new \ArrayObject();
$this->add($node);
@@ -93,20 +75,16 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the current URI.
*
* @return string|null
*/
public function getUri()
public function getUri(): ?string
{
return $this->uri;
}
/**
* Returns base href.
*
* @return string|null
*/
public function getBaseHref()
public function getBaseHref(): ?string
{
return $this->baseHref;
}
@@ -131,7 +109,7 @@ class Crawler implements \Countable, \IteratorAggregate
*
* @throws \InvalidArgumentException when node is not the expected type
*/
public function add($node)
public function add(\DOMNodeList|\DOMNode|array|string|null $node)
{
if ($node instanceof \DOMNodeList) {
$this->addNodeList($node);
@@ -230,14 +208,11 @@ class Crawler implements \Countable, \IteratorAggregate
public function addXmlContent(string $content, string $charset = 'UTF-8', int $options = \LIBXML_NONET)
{
// remove the default namespace if it's the only namespace to make XPath expressions simpler
if (!preg_match('/xmlns:/', $content)) {
if (!str_contains($content, 'xmlns:')) {
$content = str_replace('xmlns', 'ns', $content);
}
$internalErrors = libxml_use_internal_errors(true);
if (\LIBXML_VERSION < 20900) {
$disableEntities = libxml_disable_entity_loader(true);
}
$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;
@@ -247,9 +222,6 @@ class Crawler implements \Countable, \IteratorAggregate
}
libxml_use_internal_errors($internalErrors);
if (\LIBXML_VERSION < 20900) {
libxml_disable_entity_loader($disableEntities);
}
$this->addDocument($dom);
@@ -309,9 +281,7 @@ class Crawler implements \Countable, \IteratorAggregate
throw new \InvalidArgumentException('Attaching DOM nodes from multiple documents in the same crawler is forbidden.');
}
if (null === $this->document) {
$this->document = $node->ownerDocument;
}
$this->document ??= $node->ownerDocument;
// Don't add duplicate nodes in the Crawler
if (\in_array($node, $this->nodes, true)) {
@@ -323,10 +293,8 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a node given its position in the node list.
*
* @return static
*/
public function eq(int $position)
public function eq(int $position): static
{
if (isset($this->nodes[$position])) {
return $this->createSubCrawler($this->nodes[$position]);
@@ -351,7 +319,7 @@ class Crawler implements \Countable, \IteratorAggregate
*
* @return array An array of values returned by the anonymous function
*/
public function each(\Closure $closure)
public function each(\Closure $closure): array
{
$data = [];
foreach ($this->nodes as $i => $node) {
@@ -363,10 +331,8 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Slices the list of nodes by $offset and $length.
*
* @return static
*/
public function slice(int $offset = 0, int $length = null)
public function slice(int $offset = 0, int $length = null): static
{
return $this->createSubCrawler(\array_slice($this->nodes, $offset, $length));
}
@@ -377,10 +343,8 @@ class Crawler implements \Countable, \IteratorAggregate
* To remove a node from the list, the anonymous function must return false.
*
* @param \Closure $closure An anonymous function
*
* @return static
*/
public function reduce(\Closure $closure)
public function reduce(\Closure $closure): static
{
$nodes = [];
foreach ($this->nodes as $i => $node) {
@@ -394,20 +358,16 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the first node of the current selection.
*
* @return static
*/
public function first()
public function first(): static
{
return $this->eq(0);
}
/**
* Returns the last node of the current selection.
*
* @return static
*/
public function last()
public function last(): static
{
return $this->eq(\count($this->nodes) - 1);
}
@@ -415,11 +375,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the siblings nodes of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException When current node is empty
*/
public function siblings()
public function siblings(): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -470,11 +428,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the next siblings nodes of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException When current node is empty
*/
public function nextAll()
public function nextAll(): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -486,11 +442,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the previous sibling nodes of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException
*/
public function previousAll()
public function previousAll(): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -499,28 +453,12 @@ class Crawler implements \Countable, \IteratorAggregate
return $this->createSubCrawler($this->sibling($this->getNode(0), 'previousSibling'));
}
/**
* Returns the parent nodes of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException When current node is empty
*/
public function parents()
{
trigger_deprecation('symfony/dom-crawler', '5.3', 'The %s() method is deprecated, use ancestors() instead.', __METHOD__);
return $this->ancestors();
}
/**
* Returns the ancestors of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException When the current node is empty
*/
public function ancestors()
public function ancestors(): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -541,12 +479,10 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the children nodes of the current selection.
*
* @return static
*
* @throws \InvalidArgumentException When current node is empty
* @throws \RuntimeException If the CssSelector Component is not available and $selector is provided
*/
public function children(string $selector = null)
public function children(string $selector = null): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -567,11 +503,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the attribute value of the first node of the list.
*
* @return string|null
*
* @throws \InvalidArgumentException When current node is empty
*/
public function attr(string $attribute)
public function attr(string $attribute): ?string
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -585,11 +519,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the node name of the first node of the list.
*
* @return string
*
* @throws \InvalidArgumentException When current node is empty
*/
public function nodeName()
public function nodeName(): string
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -606,11 +538,9 @@ class Crawler implements \Countable, \IteratorAggregate
* @param string|null $default When not null: the value to return when the current node is empty
* @param bool $normalizeWhitespace Whether whitespaces should be trimmed and normalized to single spaces
*
* @return string
*
* @throws \InvalidArgumentException When current node is empty
*/
public function text(string $default = null, bool $normalizeWhitespace = true)
public function text(string $default = null, bool $normalizeWhitespace = true): string
{
if (!$this->nodes) {
if (null !== $default) {
@@ -642,11 +572,9 @@ class Crawler implements \Countable, \IteratorAggregate
*
* @param string|null $default When not null: the value to return when the current node is empty
*
* @return string
*
* @throws \InvalidArgumentException When current node is empty
*/
public function html(string $default = null)
public function html(string $default = null): string
{
if (!$this->nodes) {
if (null !== $default) {
@@ -659,7 +587,7 @@ class Crawler implements \Countable, \IteratorAggregate
$node = $this->getNode(0);
$owner = $node->ownerDocument;
if (null !== $this->html5Parser && '<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
if ('<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
$owner = $this->html5Parser;
}
@@ -680,7 +608,7 @@ class Crawler implements \Countable, \IteratorAggregate
$node = $this->getNode(0);
$owner = $node->ownerDocument;
if (null !== $this->html5Parser && '<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
if ('<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
$owner = $this->html5Parser;
}
@@ -692,10 +620,8 @@ class Crawler implements \Countable, \IteratorAggregate
*
* Since an XPath expression might evaluate to either a simple type or a \DOMNodeList,
* this method will return either an array of simple types or a new Crawler instance.
*
* @return array|Crawler
*/
public function evaluate(string $xpath)
public function evaluate(string $xpath): array|Crawler
{
if (null === $this->document) {
throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.');
@@ -723,10 +649,8 @@ class Crawler implements \Countable, \IteratorAggregate
* Example:
*
* $crawler->filter('h1 a')->extract(['_text', 'href']);
*
* @return array
*/
public function extract(array $attributes)
public function extract(array $attributes): array
{
$count = \count($attributes);
@@ -756,10 +680,8 @@ class Crawler implements \Countable, \IteratorAggregate
* is considered as a fake parent of the elements inside it.
* This means that a child selector "div" or "./div" will match only
* the div elements of the current crawler, not their children.
*
* @return static
*/
public function filterXPath(string $xpath)
public function filterXPath(string $xpath): static
{
$xpath = $this->relativize($xpath);
@@ -776,11 +698,9 @@ class Crawler implements \Countable, \IteratorAggregate
*
* This method only works if you have installed the CssSelector Symfony Component.
*
* @return static
*
* @throws \RuntimeException if the CssSelector Component is not available
*/
public function filter(string $selector)
public function filter(string $selector): static
{
$converter = $this->createCssSelectorConverter();
@@ -790,10 +710,8 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects links by name or alt value for clickable images.
*
* @return static
*/
public function selectLink(string $value)
public function selectLink(string $value): static
{
return $this->filterRelativeXPath(
sprintf('descendant-or-self::a[contains(concat(\' \', normalize-space(string(.)), \' \'), %1$s) or ./img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %1$s)]]', static::xpathLiteral(' '.$value.' '))
@@ -802,10 +720,8 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects images by alt value.
*
* @return static
*/
public function selectImage(string $value)
public function selectImage(string $value): static
{
$xpath = sprintf('descendant-or-self::img[contains(normalize-space(string(@alt)), %s)]', static::xpathLiteral($value));
@@ -814,10 +730,8 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects a button by name or alt value for images.
*
* @return static
*/
public function selectButton(string $value)
public function selectButton(string $value): static
{
return $this->filterRelativeXPath(
sprintf('descendant-or-self::input[((contains(%1$s, "submit") or contains(%1$s, "button")) and contains(concat(\' \', normalize-space(string(@value)), \' \'), %2$s)) or (contains(%1$s, "image") and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %2$s)) or @id=%3$s or @name=%3$s] | descendant-or-self::button[contains(concat(\' \', normalize-space(string(.)), \' \'), %2$s) or @id=%3$s or @name=%3$s]', 'translate(@type, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")', static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value))
@@ -827,11 +741,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a Link object for the first node in the list.
*
* @return Link
*
* @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement
*/
public function link(string $method = 'get')
public function link(string $method = 'get'): Link
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -853,7 +765,7 @@ class Crawler implements \Countable, \IteratorAggregate
*
* @throws \InvalidArgumentException If the current node list contains non-DOMElement instances
*/
public function links()
public function links(): array
{
$links = [];
foreach ($this->nodes as $node) {
@@ -870,11 +782,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns an Image object for the first node in the list.
*
* @return Image
*
* @throws \InvalidArgumentException If the current node list is empty
*/
public function image()
public function image(): Image
{
if (!\count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -894,7 +804,7 @@ class Crawler implements \Countable, \IteratorAggregate
*
* @return Image[]
*/
public function images()
public function images(): array
{
$images = [];
foreach ($this as $node) {
@@ -911,11 +821,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a Form object for the first node in the list.
*
* @return Form
*
* @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement
*/
public function form(array $values = null, string $method = null)
public function form(array $values = null, string $method = null): Form
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -964,10 +872,8 @@ class Crawler implements \Countable, \IteratorAggregate
*
* echo Crawler::xpathLiteral('a\'b"c');
* //prints concat('a', "'", 'b"c')
*
* @return string
*/
public static function xpathLiteral(string $s)
public static function xpathLiteral(string $s): string
{
if (!str_contains($s, "'")) {
return sprintf("'%s'", $s);
@@ -997,10 +903,8 @@ class Crawler implements \Countable, \IteratorAggregate
* Filters the list of nodes with an XPath expression.
*
* The XPath expression should already be processed to apply it in the context of each node.
*
* @return static
*/
private function filterRelativeXPath(string $xpath): object
private function filterRelativeXPath(string $xpath): static
{
$crawler = $this->createSubCrawler(null);
if (null === $this->document) {
@@ -1106,19 +1010,12 @@ class Crawler implements \Countable, \IteratorAggregate
return $xpath; // The XPath expression is invalid
}
/**
* @return \DOMNode|null
*/
public function getNode(int $position)
public function getNode(int $position): ?\DOMNode
{
return $this->nodes[$position] ?? null;
}
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
public function count(): int
{
return \count($this->nodes);
}
@@ -1126,16 +1023,12 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* @return \ArrayIterator<int, \DOMNode>
*/
#[\ReturnTypeWillChange]
public function getIterator()
public function getIterator(): \ArrayIterator
{
return new \ArrayIterator($this->nodes);
}
/**
* @return array
*/
protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling')
protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling'): array
{
$nodes = [];
@@ -1159,9 +1052,6 @@ class Crawler implements \Countable, \IteratorAggregate
$htmlContent = $this->convertToHtmlEntities($htmlContent, $charset);
$internalErrors = libxml_use_internal_errors(true);
if (\LIBXML_VERSION < 20900) {
$disableEntities = libxml_disable_entity_loader(true);
}
$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;
@@ -1171,9 +1061,6 @@ class Crawler implements \Countable, \IteratorAggregate
}
libxml_use_internal_errors($internalErrors);
if (\LIBXML_VERSION < 20900) {
libxml_disable_entity_loader($disableEntities);
}
return $dom;
}
@@ -1187,11 +1074,11 @@ class Crawler implements \Countable, \IteratorAggregate
try {
return mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], $charset);
} catch (\Exception|\ValueError $e) {
} catch (\Exception|\ValueError) {
try {
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
$htmlContent = mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8');
} catch (\Exception|\ValueError $e) {
} catch (\Exception|\ValueError) {
}
return $htmlContent;
@@ -1249,10 +1136,8 @@ class Crawler implements \Countable, \IteratorAggregate
* Creates a crawler for some subnodes.
*
* @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $nodes
*
* @return static
*/
private function createSubCrawler($nodes): object
private function createSubCrawler(\DOMNodeList|\DOMNode|array|string|null $nodes): static
{
$crawler = new static($nodes, $this->uri, $this->baseHref);
$crawler->isHtml = $this->isHtml;
@@ -1291,12 +1176,10 @@ class Crawler implements \Countable, \IteratorAggregate
private function canParseHtml5String(string $content): bool
{
if (null === $this->html5Parser) {
return false;
}
if (false === ($pos = stripos($content, '<!doctype html>'))) {
return false;
}
$header = substr($content, 0, $pos);
return '' === $header || $this->isValidHtml5Heading($header);

View File

@@ -20,29 +20,17 @@ namespace Symfony\Component\DomCrawler\Field;
*/
class ChoiceFormField extends FormField
{
/**
* @var string
*/
private $type;
/**
* @var bool
*/
private $multiple;
/**
* @var array
*/
private $options;
/**
* @var bool
*/
private $validationDisabled = false;
private string $type;
private bool $multiple;
private array $options;
private bool $validationDisabled = false;
/**
* Returns true if the field should be included in the submitted values.
*
* @return bool true if the field should be included in the submitted values, false otherwise
*/
public function hasValue()
public function hasValue(): bool
{
// don't send a value for unchecked checkboxes
if (\in_array($this->type, ['checkbox', 'radio']) && null === $this->value) {
@@ -54,10 +42,8 @@ class ChoiceFormField extends FormField
/**
* Check if the current selected option is disabled.
*
* @return bool
*/
public function isDisabled()
public function isDisabled(): bool
{
if (parent::isDisabled() && 'select' === $this->type) {
return true;
@@ -74,10 +60,8 @@ class ChoiceFormField extends FormField
/**
* Sets the value of the field.
*
* @param string|array $value The value of the field
*/
public function select($value)
public function select(string|array|bool $value)
{
$this->setValue($value);
}
@@ -113,11 +97,9 @@ class ChoiceFormField extends FormField
/**
* Sets the value of the field.
*
* @param string|array|bool|null $value The value of the field
*
* @throws \InvalidArgumentException When value type provided is not correct
*/
public function setValue($value)
public function setValue(string|array|bool|null $value)
{
if ('checkbox' === $this->type && false === $value) {
// uncheck
@@ -175,20 +157,16 @@ class ChoiceFormField extends FormField
/**
* Returns the type of the choice field (radio, select, or checkbox).
*
* @return string
*/
public function getType()
public function getType(): string
{
return $this->type;
}
/**
* Returns true if the field accepts multiple values.
*
* @return bool
*/
public function isMultiple()
public function isMultiple(): bool
{
return $this->multiple;
}
@@ -244,7 +222,7 @@ class ChoiceFormField extends FormField
}
// if no option is selected and if it is a simple select box, take the first option as the value
if (!$found && !$this->multiple && !empty($this->options)) {
if (!$found && !$this->multiple && $this->options) {
$this->value = $this->options[0]['value'];
}
}
@@ -268,11 +246,9 @@ class ChoiceFormField extends FormField
/**
* Checks whether given value is in the existing options.
*
* @internal since Symfony 5.3
*
* @return bool
* @internal
*/
public function containsOption(string $optionValue, array $options)
public function containsOption(string $optionValue, array $options): bool
{
if ($this->validationDisabled) {
return true;
@@ -290,11 +266,9 @@ class ChoiceFormField extends FormField
/**
* Returns list of available field options.
*
* @internal since Symfony 5.3
*
* @return array
* @internal
*/
public function availableOptionValues()
public function availableOptionValues(): array
{
$values = [];
@@ -308,11 +282,11 @@ class ChoiceFormField extends FormField
/**
* Disables the internal validation of the field.
*
* @internal since Symfony 5.3
* @internal
*
* @return $this
*/
public function disableValidation()
public function disableValidation(): static
{
$this->validationDisabled = true;

View File

@@ -57,10 +57,8 @@ abstract class FormField
/**
* Returns the label tag associated to the field or null if none.
*
* @return \DOMElement|null
*/
public function getLabel()
public function getLabel(): ?\DOMElement
{
$xpath = new \DOMXPath($this->node->ownerDocument);
@@ -78,20 +76,16 @@ abstract class FormField
/**
* Returns the name of the field.
*
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
/**
* Gets the value of the field.
*
* @return string|array|null
*/
public function getValue()
public function getValue(): string|array|null
{
return $this->value;
}
@@ -106,20 +100,16 @@ abstract class FormField
/**
* Returns true if the field should be included in the submitted values.
*
* @return bool
*/
public function hasValue()
public function hasValue(): bool
{
return true;
}
/**
* Check if the current field is disabled.
*
* @return bool
*/
public function isDisabled()
public function isDisabled(): bool
{
return $this->node->hasAttribute('disabled');
}

View File

@@ -21,20 +21,9 @@ use Symfony\Component\DomCrawler\Field\FormField;
*/
class Form extends Link implements \ArrayAccess
{
/**
* @var \DOMElement
*/
private $button;
/**
* @var FormFieldRegistry
*/
private $fields;
/**
* @var string
*/
private $baseHref;
private \DOMElement $button;
private FormFieldRegistry $fields;
private ?string $baseHref;
/**
* @param \DOMElement $node A \DOMElement instance
@@ -54,10 +43,8 @@ class Form extends Link implements \ArrayAccess
/**
* Gets the form node associated with this form.
*
* @return \DOMElement
*/
public function getFormNode()
public function getFormNode(): \DOMElement
{
return $this->node;
}
@@ -69,7 +56,7 @@ class Form extends Link implements \ArrayAccess
*
* @return $this
*/
public function setValues(array $values)
public function setValues(array $values): static
{
foreach ($values as $name => $value) {
$this->fields->set($name, $value);
@@ -82,10 +69,8 @@ class Form extends Link implements \ArrayAccess
* Gets the field values.
*
* The returned array does not include file fields (@see getFiles).
*
* @return array
*/
public function getValues()
public function getValues(): array
{
$values = [];
foreach ($this->fields->all() as $name => $field) {
@@ -103,10 +88,8 @@ class Form extends Link implements \ArrayAccess
/**
* Gets the file field values.
*
* @return array
*/
public function getFiles()
public function getFiles(): array
{
if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
return [];
@@ -132,10 +115,8 @@ class Form extends Link implements \ArrayAccess
*
* This method converts fields with the array notation
* (like foo[bar] to arrays) like PHP does.
*
* @return array
*/
public function getPhpValues()
public function getPhpValues(): array
{
$values = [];
foreach ($this->getValues() as $name => $value) {
@@ -159,10 +140,8 @@ class Form extends Link implements \ArrayAccess
* (@see getPhpValues), rather than uploaded files found in $_FILES.
* For a compound file field foo[bar] it will create foo[bar][name],
* instead of foo[name][bar] which would be found in $_FILES.
*
* @return array
*/
public function getPhpFiles()
public function getPhpFiles(): array
{
$values = [];
foreach ($this->getFiles() as $name => $value) {
@@ -195,10 +174,8 @@ class Form extends Link implements \ArrayAccess
* The returned URI is not the same as the form "action" attribute.
* This method merges the value if the method is GET to mimics
* browser behavior.
*
* @return string
*/
public function getUri()
public function getUri(): string
{
$uri = parent::getUri();
@@ -219,7 +196,7 @@ class Form extends Link implements \ArrayAccess
return $uri;
}
protected function getRawUri()
protected function getRawUri(): string
{
// If the form was created from a button rather than the form node, check for HTML5 action overrides
if ($this->button !== $this->node && $this->button->getAttribute('formaction')) {
@@ -233,10 +210,8 @@ class Form extends Link implements \ArrayAccess
* Gets the form method.
*
* If no method is defined in the form, GET is returned.
*
* @return string
*/
public function getMethod()
public function getMethod(): string
{
if (null !== $this->method) {
return $this->method;
@@ -262,10 +237,8 @@ class Form extends Link implements \ArrayAccess
/**
* Returns true if the named field exists.
*
* @return bool
*/
public function has(string $name)
public function has(string $name): bool
{
return $this->fields->has($name);
}
@@ -285,7 +258,7 @@ class Form extends Link implements \ArrayAccess
*
* @throws \InvalidArgumentException When field is not present in this form
*/
public function get(string $name)
public function get(string $name): FormField|array
{
return $this->fields->get($name);
}
@@ -303,7 +276,7 @@ class Form extends Link implements \ArrayAccess
*
* @return FormField[]
*/
public function all()
public function all(): array
{
return $this->fields->all();
}
@@ -312,11 +285,8 @@ class Form extends Link implements \ArrayAccess
* Returns true if the named field exists.
*
* @param string $name The field name
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($name)
public function offsetExists(mixed $name): bool
{
return $this->has($name);
}
@@ -330,8 +300,7 @@ class Form extends Link implements \ArrayAccess
*
* @throws \InvalidArgumentException if the field does not exist
*/
#[\ReturnTypeWillChange]
public function offsetGet($name)
public function offsetGet(mixed $name): FormField|array
{
return $this->fields->get($name);
}
@@ -342,12 +311,9 @@ class Form extends Link implements \ArrayAccess
* @param string $name The field name
* @param string|array $value The value of the field
*
* @return void
*
* @throws \InvalidArgumentException if the field does not exist
*/
#[\ReturnTypeWillChange]
public function offsetSet($name, $value)
public function offsetSet(mixed $name, mixed $value): void
{
$this->fields->set($name, $value);
}
@@ -356,11 +322,8 @@ class Form extends Link implements \ArrayAccess
* Removes a field from the form.
*
* @param string $name The field name
*
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($name)
public function offsetUnset(mixed $name): void
{
$this->fields->remove($name);
}
@@ -370,7 +333,7 @@ class Form extends Link implements \ArrayAccess
*
* @return $this
*/
public function disableValidation()
public function disableValidation(): static
{
foreach ($this->fields->all() as $field) {
if ($field instanceof Field\ChoiceFormField) {

View File

@@ -20,9 +20,8 @@ use Symfony\Component\DomCrawler\Field\FormField;
*/
class FormFieldRegistry
{
private $fields = [];
private $base = '';
private array $fields = [];
private string $base = '';
/**
* Adds a field to the registry.
@@ -70,7 +69,7 @@ class FormFieldRegistry
*
* @throws \InvalidArgumentException if the field does not exist
*/
public function &get(string $name)
public function &get(string $name): FormField|array
{
$segments = $this->getSegments($name);
$target = &$this->fields;
@@ -94,7 +93,7 @@ class FormFieldRegistry
$this->get($name);
return true;
} catch (\InvalidArgumentException $e) {
} catch (\InvalidArgumentException) {
return false;
}
}
@@ -102,11 +101,9 @@ class FormFieldRegistry
/**
* Set the value of a field based on the fully qualified name and its children.
*
* @param mixed $value The value
*
* @throws \InvalidArgumentException if the field does not exist
*/
public function set(string $name, $value)
public function set(string $name, mixed $value)
{
$target = &$this->get($name);
if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) {

View File

@@ -21,7 +21,7 @@ class Image extends AbstractUriElement
parent::__construct($node, $currentUri, 'GET');
}
protected function getRawUri()
protected function getRawUri(): string
{
return $this->node->getAttribute('src');
}

View File

@@ -18,7 +18,7 @@ namespace Symfony\Component\DomCrawler;
*/
class Link extends AbstractUriElement
{
protected function getRawUri()
protected function getRawUri(): string
{
return $this->node->getAttribute('href');
}

View File

@@ -16,9 +16,9 @@ use Symfony\Component\DomCrawler\Crawler;
final class CrawlerSelectorAttributeValueSame extends Constraint
{
private $selector;
private $attribute;
private $expectedText;
private string $selector;
private string $attribute;
private string $expectedText;
public function __construct(string $selector, string $attribute, string $expectedText)
{
@@ -27,9 +27,6 @@ final class CrawlerSelectorAttributeValueSame extends Constraint
$this->expectedText = $expectedText;
}
/**
* {@inheritdoc}
*/
public function toString(): string
{
return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText);
@@ -37,8 +34,6 @@ final class CrawlerSelectorAttributeValueSame extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function matches($crawler): bool
{
@@ -52,8 +47,6 @@ final class CrawlerSelectorAttributeValueSame extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function failureDescription($crawler): string
{

View File

@@ -16,16 +16,13 @@ use Symfony\Component\DomCrawler\Crawler;
final class CrawlerSelectorExists extends Constraint
{
private $selector;
private string $selector;
public function __construct(string $selector)
{
$this->selector = $selector;
}
/**
* {@inheritdoc}
*/
public function toString(): string
{
return sprintf('matches selector "%s"', $this->selector);
@@ -33,8 +30,6 @@ final class CrawlerSelectorExists extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function matches($crawler): bool
{
@@ -43,8 +38,6 @@ final class CrawlerSelectorExists extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function failureDescription($crawler): string
{

View File

@@ -16,10 +16,10 @@ use Symfony\Component\DomCrawler\Crawler;
final class CrawlerSelectorTextContains extends Constraint
{
private $selector;
private $expectedText;
private $hasNode = false;
private $nodeText;
private string $selector;
private string $expectedText;
private bool $hasNode = false;
private string $nodeText;
public function __construct(string $selector, string $expectedText)
{
@@ -27,9 +27,6 @@ final class CrawlerSelectorTextContains extends Constraint
$this->expectedText = $expectedText;
}
/**
* {@inheritdoc}
*/
public function toString(): string
{
if ($this->hasNode) {
@@ -41,8 +38,6 @@ final class CrawlerSelectorTextContains extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function matches($crawler): bool
{
@@ -56,13 +51,11 @@ final class CrawlerSelectorTextContains extends Constraint
$this->hasNode = true;
$this->nodeText = $crawler->text(null, true);
return false !== mb_strpos($this->nodeText, $this->expectedText);
return str_contains($this->nodeText, $this->expectedText);
}
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function failureDescription($crawler): string
{

View File

@@ -16,8 +16,8 @@ use Symfony\Component\DomCrawler\Crawler;
final class CrawlerSelectorTextSame extends Constraint
{
private $selector;
private $expectedText;
private string $selector;
private string $expectedText;
public function __construct(string $selector, string $expectedText)
{
@@ -25,9 +25,6 @@ final class CrawlerSelectorTextSame extends Constraint
$this->expectedText = $expectedText;
}
/**
* {@inheritdoc}
*/
public function toString(): string
{
return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText);
@@ -35,8 +32,6 @@ final class CrawlerSelectorTextSame extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function matches($crawler): bool
{
@@ -50,8 +45,6 @@ final class CrawlerSelectorTextSame extends Constraint
/**
* @param Crawler $crawler
*
* {@inheritdoc}
*/
protected function failureDescription($crawler): string
{

View File

@@ -58,7 +58,7 @@ class UriResolver
}
// absolute URL with relative schema
if (0 === strpos($uri, '//')) {
if (str_starts_with($uri, '//')) {
return preg_replace('#^([^/]*)//.*$#', '$1', $baseUriCleaned).$uri;
}
@@ -85,7 +85,7 @@ class UriResolver
return $path;
}
if ('.' === substr($path, -1)) {
if (str_ends_with($path, '.')) {
$path .= '/';
}

View File

@@ -16,18 +16,13 @@
}
],
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/css-selector": "^4.4|^5.0|^6.0",
"masterminds/html5": "^2.6"
},
"conflict": {
"masterminds/html5": "<2.6"
"require-dev": {
"symfony/css-selector": "^5.4|^6.0"
},
"suggest": {
"symfony/css-selector": ""