[DomCrawler] [5.0] add type-hint whenever possible

This commit is contained in:
Amrouche Hamza 2019-07-03 08:01:17 +02:00
parent 8fb4741f92
commit 580b126a35
No known key found for this signature in database
GPG Key ID: E45A3DA456145BC1
9 changed files with 52 additions and 135 deletions

View File

@ -136,7 +136,7 @@ abstract class AbstractUriElement
*
* @return string
*/
protected function canonicalizePath($path)
protected function canonicalizePath(string $path)
{
if ('' === $path || '/' === $path) {
return $path;

View File

@ -62,8 +62,6 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* @param mixed $node A Node to use as the base for the crawling
* @param string $uri The current URI
* @param string $baseHref The base href value
*/
public function __construct($node = null, string $uri = null, string $baseHref = null)
{
@ -134,11 +132,8 @@ class Crawler implements \Countable, \IteratorAggregate
* If the charset is not set via the content type, it is assumed to be UTF-8,
* or ISO-8859-1 as a fallback, which is the default charset defined by the
* HTTP 1.1 specification.
*
* @param string $content A string to parse as HTML/XML
* @param string|null $type The content type of the string
*/
public function addContent($content, $type = null)
public function addContent(string $content, string $type = null)
{
if (empty($type)) {
$type = 0 === strpos($content, '<?xml') ? 'application/xml' : 'text/html';
@ -184,11 +179,8 @@ class Crawler implements \Countable, \IteratorAggregate
* internal errors via libxml_use_internal_errors(true)
* and then, get the errors via libxml_get_errors(). Be
* sure to clear errors with libxml_clear_errors() afterward.
*
* @param string $content The HTML content
* @param string $charset The charset
*/
public function addHtmlContent($content, $charset = 'UTF-8')
public function addHtmlContent(string $content, string $charset = 'UTF-8')
{
// Use HTML5 parser if the content is HTML5 and the library is available
$dom = null !== $this->html5Parser && strspn($content, " \t\r\n") === stripos($content, '<!doctype html>') ? $this->parseHtml5($content, $charset) : $this->parseXhtml($content, $charset);
@ -219,13 +211,11 @@ class Crawler implements \Countable, \IteratorAggregate
* and then, get the errors via libxml_get_errors(). Be
* sure to clear errors with libxml_clear_errors() afterward.
*
* @param string $content The XML content
* @param string $charset The charset
* @param int $options Bitwise OR of the libxml option constants
* LIBXML_PARSEHUGE is dangerous, see
* http://symfony.com/blog/security-release-symfony-2-0-17-released
*/
public function addXmlContent($content, $charset = 'UTF-8', $options = LIBXML_NONET)
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)) {
@ -318,11 +308,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a node given its position in the node list.
*
* @param int $position The position
*
* @return self
*/
public function eq($position)
public function eq(int $position)
{
if (isset($this->nodes[$position])) {
return $this->createSubCrawler($this->nodes[$position]);
@ -360,12 +348,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Slices the list of nodes by $offset and $length.
*
* @param int $offset
* @param int $length
*
* @return self
*/
public function slice($offset = 0, $length = null)
public function slice(int $offset = 0, int $length = null)
{
return $this->createSubCrawler(\array_slice($this->nodes, $offset, $length));
}
@ -487,8 +472,6 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the children nodes of the current selection.
*
* @param string|null $selector An optional CSS selector to filter children
*
* @return self
*
* @throws \InvalidArgumentException When current node is empty
@ -515,13 +498,11 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns the attribute value of the first node of the list.
*
* @param string $attribute The attribute name
*
* @return string|null The attribute value or null if the attribute does not exist
*
* @throws \InvalidArgumentException When current node is empty
*/
public function attr($attribute)
public function attr(string $attribute)
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@ -610,11 +591,9 @@ 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.
*
* @param string $xpath An XPath expression
*
* @return array|Crawler An array of evaluation results or a new Crawler instance
*/
public function evaluate($xpath)
public function evaluate(string $xpath)
{
if (null === $this->document) {
throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.');
@ -643,13 +622,10 @@ class Crawler implements \Countable, \IteratorAggregate
*
* $crawler->filter('h1 a')->extract(['_text', 'href']);
*
* @param array $attributes An array of attributes
*
* @return array An array of extracted values
*/
public function extract($attributes)
public function extract(array $attributes)
{
$attributes = (array) $attributes;
$count = \count($attributes);
$data = [];
@ -679,11 +655,9 @@ class Crawler implements \Countable, \IteratorAggregate
* This means that a child selector "div" or "./div" will match only
* the div elements of the current crawler, not their children.
*
* @param string $xpath An XPath expression
*
* @return self
*/
public function filterXPath($xpath)
public function filterXPath(string $xpath)
{
$xpath = $this->relativize($xpath);
@ -700,13 +674,11 @@ class Crawler implements \Countable, \IteratorAggregate
*
* This method only works if you have installed the CssSelector Symfony Component.
*
* @param string $selector A CSS selector
*
* @return self
*
* @throws \RuntimeException if the CssSelector Component is not available
*/
public function filter($selector)
public function filter(string $selector)
{
$converter = $this->createCssSelectorConverter();
@ -717,11 +689,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects links by name or alt value for clickable images.
*
* @param string $value The link text
*
* @return self
*/
public function selectLink($value)
public function selectLink(string $value)
{
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.' '))
@ -731,11 +701,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects images by alt value.
*
* @param string $value The image alt
*
* @return self A new instance of Crawler with the filtered list of nodes
*/
public function selectImage($value)
public function selectImage(string $value)
{
$xpath = sprintf('descendant-or-self::img[contains(normalize-space(string(@alt)), %s)]', static::xpathLiteral($value));
@ -745,11 +713,9 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Selects a button by name or alt value for images.
*
* @param string $value The button text
*
* @return self
*/
public function selectButton($value)
public function selectButton(string $value)
{
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))
@ -759,13 +725,11 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a Link object for the first node in the list.
*
* @param string $method The method for the link (get by default)
*
* @return Link A Link instance
*
* @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement
*/
public function link($method = 'get')
public function link(string $method = 'get')
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@ -845,14 +809,11 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Returns a Form object for the first node in the list.
*
* @param array $values An array of values for the form fields
* @param string $method The method for the form
*
* @return Form A Form instance
*
* @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement
*/
public function form(array $values = null, $method = null)
public function form(array $values = null, string $method = null)
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@ -875,19 +836,13 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* Overloads a default namespace prefix to be used with XPath and CSS expressions.
*
* @param string $prefix
*/
public function setDefaultNamespacePrefix($prefix)
public function setDefaultNamespacePrefix(string $prefix)
{
$this->defaultNamespacePrefix = $prefix;
}
/**
* @param string $prefix
* @param string $namespace
*/
public function registerNamespace($prefix, $namespace)
public function registerNamespace(string $prefix, string $namespace)
{
$this->namespaces[$prefix] = $namespace;
}
@ -909,11 +864,9 @@ class Crawler implements \Countable, \IteratorAggregate
* //prints concat('a', "'", 'b"c')
*
*
* @param string $s String to be escaped
*
* @return string Converted string
*/
public static function xpathLiteral($s)
public static function xpathLiteral(string $s)
{
if (false === strpos($s, "'")) {
return sprintf("'%s'", $s);
@ -944,11 +897,9 @@ class Crawler implements \Countable, \IteratorAggregate
*
* The XPath expression should already be processed to apply it in the context of each node.
*
* @param string $xpath
*
* @return self
*/
private function filterRelativeXPath($xpath)
private function filterRelativeXPath(string $xpath)
{
$prefixes = $this->findNamespacePrefixes($xpath);
@ -1053,11 +1004,9 @@ class Crawler implements \Countable, \IteratorAggregate
}
/**
* @param int $position
*
* @return \DOMElement|null
*/
public function getNode($position)
public function getNode(int $position)
{
if (isset($this->nodes[$position])) {
return $this->nodes[$position];
@ -1082,11 +1031,10 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* @param \DOMElement $node
* @param string $siblingDir
*
* @return array
*/
protected function sibling($node, $siblingDir = 'nextSibling')
protected function sibling($node, string $siblingDir = 'nextSibling')
{
$nodes = [];

View File

@ -270,12 +270,9 @@ class ChoiceFormField extends FormField
/**
* Checks whether given value is in the existing options.
*
* @param string $optionValue
* @param array $options
*
* @return bool
*/
public function containsOption($optionValue, $options)
public function containsOption(string $optionValue, array $options)
{
if ($this->validationDisabled) {
return true;

View File

@ -25,7 +25,7 @@ class FileFormField extends FormField
*
* @throws \InvalidArgumentException When error code doesn't exist
*/
public function setErrorCode($error)
public function setErrorCode(int $error)
{
$codes = [UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, UPLOAD_ERR_PARTIAL, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_NO_TMP_DIR, UPLOAD_ERR_CANT_WRITE, UPLOAD_ERR_EXTENSION];
if (!\in_array($error, $codes)) {
@ -37,20 +37,16 @@ class FileFormField extends FormField
/**
* Sets the value of the field.
*
* @param string $value The value of the field
*/
public function upload($value)
public function upload(?string $value)
{
$this->setValue($value);
}
/**
* Sets the value of the field.
*
* @param string $value The value of the field
*/
public function setValue($value)
public function setValue(?string $value)
{
if (null !== $value && is_readable($value)) {
$error = UPLOAD_ERR_OK;
@ -80,10 +76,8 @@ class FileFormField extends FormField
/**
* Sets path to the file as string for simulating HTTP request.
*
* @param string $path The path to the file
*/
public function setFilePath($path)
public function setFilePath(string $path)
{
parent::setValue($path);
}

View File

@ -99,10 +99,8 @@ abstract class FormField
/**
* Sets the value of the field.
*
* @param string $value The value of the field
*/
public function setValue($value)
public function setValue(?string $value)
{
$this->value = (string) $value;
}

View File

@ -263,21 +263,17 @@ class Form extends Link implements \ArrayAccess
/**
* Returns true if the named field exists.
*
* @param string $name The field name
*
* @return bool true if the field exists, false otherwise
*/
public function has($name)
public function has(string $name)
{
return $this->fields->has($name);
}
/**
* Removes a field from the form.
*
* @param string $name The field name
*/
public function remove($name)
public function remove(string $name)
{
$this->fields->remove($name);
}
@ -285,13 +281,11 @@ class Form extends Link implements \ArrayAccess
/**
* Gets a named field.
*
* @param string $name The field name
*
* @return FormField The field instance
*
* @throws \InvalidArgumentException When field is not present in this form
*/
public function get($name)
public function get(string $name)
{
return $this->fields->get($name);
}

View File

@ -22,7 +22,7 @@ class FormFieldRegistry
{
private $fields = [];
private $base;
private $base = '';
/**
* Adds a field to the registry.
@ -47,11 +47,9 @@ class FormFieldRegistry
}
/**
* Removes a field and its children from the registry.
*
* @param string $name The fully qualified name of the base field
* Removes a field based on the fully qualifed name and its children from the registry.
*/
public function remove($name)
public function remove(string $name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
@ -66,15 +64,13 @@ class FormFieldRegistry
}
/**
* Returns the value of the field and its children.
*
* @param string $name The fully qualified name of the field
* Returns the value of the field based on the fully qualifed name and its children.
*
* @return mixed The value of the field
*
* @throws \InvalidArgumentException if the field does not exist
*/
public function &get($name)
public function &get(string $name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
@ -90,13 +86,11 @@ class FormFieldRegistry
}
/**
* Tests whether the form has the given field.
*
* @param string $name The fully qualified name of the field
* Tests whether the form has the given field based on the fully qualified name.
*
* @return bool Whether the form has the given field
*/
public function has($name)
public function has(string $name)
{
try {
$this->get($name);
@ -108,14 +102,13 @@ class FormFieldRegistry
}
/**
* Set the value of a field and its children.
* Set the value of a field based on the fully qualified name and its children.
*
* @param string $name The fully qualified name of the field
* @param mixed $value The value
*
* @throws \InvalidArgumentException if the field does not exist
*/
public function set($name, $value)
public function set(string $name, $value)
{
$target = &$this->get($name);
if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) {
@ -146,12 +139,11 @@ class FormFieldRegistry
* This function is made private because it allows overriding the $base and
* the $values properties without any type checking.
*
* @param string $base The fully qualified name of the base field
* @param array $values The values of the fields
*
* @return static
*/
private static function create($base, array $values)
private static function create(string $base, array $values)
{
$registry = new static();
$registry->base = $base;
@ -163,13 +155,9 @@ class FormFieldRegistry
/**
* Transforms a PHP array in a list of fully qualified name / value.
*
* @param array $array The PHP array
* @param string $base The name of the base field
* @param array $output The initial values
*
* @return array The list of fields as [string] Fully qualified name => (mixed) value)
*/
private function walk(array $array, $base = '', array &$output = [])
private function walk(array $array, string $base = '', array &$output = [])
{
foreach ($array as $k => $v) {
$path = empty($base) ? $k : sprintf('%s[%s]', $base, $k);
@ -188,11 +176,9 @@ class FormFieldRegistry
*
* getSegments('base[foo][3][]') = ['base', 'foo, '3', ''];
*
* @param string $name The name of the field
*
* @return string[] The list of segments
*/
private function getSegments($name)
private function getSegments(string $name)
{
if (preg_match('/^(?P<base>[^[]+)(?P<extra>(\[.*)|$)/', $name, $m)) {
$segments = [$m['base']];

View File

@ -364,11 +364,11 @@ abstract class AbstractCrawlerTest extends TestCase
{
$crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
$this->assertEquals(['One', 'Two', 'Three'], $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list');
$this->assertEquals(['One', 'Two', 'Three'], $crawler->extract(['_text']), '->extract() returns an array of extracted data from the node list');
$this->assertEquals([['One', 'first'], ['Two', ''], ['Three', '']], $crawler->extract(['_text', 'class']), '->extract() returns an array of extracted data from the node list');
$this->assertEquals([[], [], []], $crawler->extract([]), '->extract() returns empty arrays if the attribute list is empty');
$this->assertEquals([], $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty');
$this->assertEquals([], $this->createTestCrawler()->filterXPath('//ol')->extract(['_text']), '->extract() returns an empty array if the node list is empty');
$this->assertEquals([['One', 'li'], ['Two', 'li'], ['Three', 'li']], $crawler->extract(['_text', '_name']), '->extract() returns an array of extracted data from the node list');
}

View File

@ -96,7 +96,7 @@ class FileFormFieldTest extends FormFieldTestCase
$this->assertEquals(UPLOAD_ERR_FORM_SIZE, $value['error'], '->setErrorCode() sets the file input field error code');
try {
$field->setErrorCode('foobar');
$field->setErrorCode(12345);
$this->fail('->setErrorCode() throws a \InvalidArgumentException if the error code is not valid');
} catch (\InvalidArgumentException $e) {
$this->assertTrue(true, '->setErrorCode() throws a \InvalidArgumentException if the error code is not valid');