| 1 |
<?php |
| 2 |
|
| 3 |
/* |
| 4 |
* This file is part of the Symfony package. |
| 5 |
* |
| 6 |
* (c) Fabien Potencier <[email protected]> |
| 7 |
* |
| 8 |
* For the full copyright and license information, please view the LICENSE |
| 9 |
* file that was distributed with this source code. |
| 10 |
*/ |
| 11 |
|
| 12 |
namespace Symfony\Component\DomCrawler; |
| 13 |
|
| 14 |
/** |
| 15 |
* Any HTML element that can link to an URI. |
| 16 |
* |
| 17 |
* @author Fabien Potencier <[email protected]> |
| 18 |
*/ |
| 19 |
abstract class AbstractUriElement |
| 20 |
{ |
| 21 |
/** |
| 22 |
* @var \DOMElement |
| 23 |
*/ |
| 24 |
protected $node; |
| 25 |
|
| 26 |
/** |
| 27 |
* @var string|null The method to use for the element |
| 28 |
*/ |
| 29 |
protected $method; |
| 30 |
|
| 31 |
/** |
| 32 |
* @var string The URI of the page where the element is embedded (or the base href) |
| 33 |
*/ |
| 34 |
protected $currentUri; |
| 35 |
|
| 36 |
/** |
| 37 |
* @param \DOMElement $node A \DOMElement instance |
| 38 |
* @param string|null $currentUri The URI of the page where the link is embedded (or the base href) |
| 39 |
* @param string|null $method The method to use for the link (GET by default) |
| 40 |
* |
| 41 |
* @throws \InvalidArgumentException if the node is not a link |
| 42 |
*/ |
| 43 |
public function __construct(\DOMElement $node, string $currentUri = null, ?string $method = 'GET') |
| 44 |
{ |
| 45 |
$this->setNode($node); |
| 46 |
$this->method = $method ? strtoupper($method) : null; |
| 47 |
$this->currentUri = $currentUri; |
| 48 |
|
| 49 |
$elementUriIsRelative = null === parse_url(trim($this->getRawUri()), \PHP_URL_SCHEME); |
| 50 |
$baseUriIsAbsolute = null !== $this->currentUri && \in_array(strtolower(substr($this->currentUri, 0, 4)), ['http', 'file']); |
| 51 |
if ($elementUriIsRelative && !$baseUriIsAbsolute) { |
| 52 |
throw new \InvalidArgumentException(sprintf('The URL of the element is relative, so you must define its base URI passing an absolute URL to the constructor of the "%s" class ("%s" was passed).', __CLASS__, $this->currentUri)); |
| 53 |
} |
| 54 |
} |
| 55 |
|
| 56 |
/** |
| 57 |
* Gets the node associated with this link. |
| 58 |
* |
| 59 |
* @return \DOMElement |
| 60 |
*/ |
| 61 |
public function getNode() |
| 62 |
{ |
| 63 |
return $this->node; |
| 64 |
} |
| 65 |
|
| 66 |
/** |
| 67 |
* Gets the method associated with this link. |
| 68 |
* |
| 69 |
* @return string |
| 70 |
*/ |
| 71 |
public function getMethod() |
| 72 |
{ |
| 73 |
return $this->method ?? 'GET'; |
| 74 |
} |
| 75 |
|
| 76 |
/** |
| 77 |
* Gets the URI associated with this link. |
| 78 |
* |
| 79 |
* @return string |
| 80 |
*/ |
| 81 |
public function getUri() |
| 82 |
{ |
| 83 |
return UriResolver::resolve($this->getRawUri(), $this->currentUri); |
| 84 |
} |
| 85 |
|
| 86 |
/** |
| 87 |
* Returns raw URI data. |
| 88 |
* |
| 89 |
* @return string |
| 90 |
*/ |
| 91 |
abstract protected function getRawUri(); |
| 92 |
|
| 93 |
/** |
| 94 |
* Returns the canonicalized URI path (see RFC 3986, section 5.2.4). |
| 95 |
* |
| 96 |
* @param string $path URI path |
| 97 |
* |
| 98 |
* @return string |
| 99 |
*/ |
| 100 |
protected function canonicalizePath(string $path) |
| 101 |
{ |
| 102 |
if ('' === $path || '/' === $path) { |
| 103 |
return $path; |
| 104 |
} |
| 105 |
|
| 106 |
if (str_ends_with($path, '.')) { |
| 107 |
$path .= '/'; |
| 108 |
} |
| 109 |
|
| 110 |
$output = []; |
| 111 |
|
| 112 |
foreach (explode('/', $path) as $segment) { |
| 113 |
if ('..' === $segment) { |
| 114 |
array_pop($output); |
| 115 |
} elseif ('.' !== $segment) { |
| 116 |
$output[] = $segment; |
| 117 |
} |
| 118 |
} |
| 119 |
|
| 120 |
return implode('/', $output); |
| 121 |
} |
| 122 |
|
| 123 |
/** |
| 124 |
* Sets current \DOMElement instance. |
| 125 |
* |
| 126 |
* @param \DOMElement $node A \DOMElement instance |
| 127 |
* |
| 128 |
* @throws \LogicException If given node is not an anchor |
| 129 |
*/ |
| 130 |
abstract protected function setNode(\DOMElement $node); |
| 131 |
} |
| 132 |
|