Browse Source

Add support for base tag for Link and Form, Fixes #9422

Jeremy Bush 14 years ago
parent
commit
4460b49802

+ 18 - 4
src/Symfony/Component/DomCrawler/Crawler.php

@@ -23,19 +23,27 @@ class Crawler extends \SplObjectStorage
     protected $uri;
     protected $host;
     protected $path;
+    protected $base;
 
     /**
      * Constructor.
      *
      * @param mixed  $node A Node to use as the base for the crawling
      * @param string $uri  The base URI to use for absolute links or form actions
+     * @param string $base An optional base href for generating the uris for Form and Link.
+     *                     This will be autodetected if $node has a <base> tag.
      */
-    public function __construct($node = null, $uri = null)
+    public function __construct($node = null, $uri = null, $base = null)
     {
         $this->uri = $uri;
+
         list($this->host, $this->path) = $this->parseUri($this->uri);
 
         $this->add($node);
+
+        if ($base) {
+            $this->base = $base;
+        }
     }
 
     /**
@@ -103,6 +111,12 @@ class Crawler extends \SplObjectStorage
 
         @$dom->loadHTML($content);
         $this->addDocument($dom);
+
+        $base = $this->filter('base')->extract(array('href'));
+
+        if (count($base)) {
+            $this->base = current($base);
+        }
     }
 
     /**
@@ -430,7 +444,7 @@ class Crawler extends \SplObjectStorage
 
         $domxpath = new \DOMXPath($document);
 
-        return new static($domxpath->query($xpath), $this->uri);
+        return new static($domxpath->query($xpath), $this->uri, $this->base);
     }
 
     /**
@@ -503,7 +517,7 @@ class Crawler extends \SplObjectStorage
 
         $node = $this->getNode(0);
 
-        return new Link($node, $method, $this->host, $this->path);
+        return new Link($node, $method, $this->host, $this->path, $this->base);
     }
 
     /**
@@ -537,7 +551,7 @@ class Crawler extends \SplObjectStorage
             throw new \InvalidArgumentException('The current node list is empty.');
         }
 
-        $form = new Form($this->getNode(0), $method, $this->host, $this->path);
+        $form = new Form($this->getNode(0), $method, $this->host, $this->path, $this->base);
 
         if (null !== $values) {
             $form->setValues($values);

+ 8 - 3
src/Symfony/Component/DomCrawler/Form.php

@@ -27,6 +27,7 @@ class Form implements \ArrayAccess
     protected $method;
     protected $host;
     protected $path;
+    protected $base;
 
     /**
      * Constructor.
@@ -35,10 +36,11 @@ class Form implements \ArrayAccess
      * @param string   $method The method to use for the link (if null, it defaults to the method defined by the form)
      * @param string   $host   The base URI to use for absolute links (like http://localhost)
      * @param string   $path   The base path for relative links (/ by default)
+     * @param string   $base   An optional base href for generating the submit uri
      *
      * @throws \LogicException if the node is not a button inside a form tag
      */
-    public function __construct(\DOMNode $node, $method = null, $host = null, $path = '/')
+    public function __construct(\DOMNode $node, $method = null, $host = null, $path = '/', $base = null)
     {
         $this->button = $node;
         if ('button' == $node->nodeName || ('input' == $node->nodeName && in_array($node->getAttribute('type'), array('submit', 'button', 'image')))) {
@@ -55,6 +57,7 @@ class Form implements \ArrayAccess
         $this->method = $method;
         $this->host = $host;
         $this->path = empty($path) ? '/' : $path;
+        $this->base = $base;
 
         $this->initialize();
     }
@@ -185,11 +188,13 @@ class Form implements \ArrayAccess
             $path = substr($path, 0, strrpos($path, '/') + 1);
         }
 
-        if ($uri && '/' !== $uri[0] && !$urlHaveScheme) {
+        if (!$this->base && $uri && '/' !== $uri[0] && !$urlHaveScheme) {
             $uri = $path.$uri;
+        } elseif ($this->base) {
+            $uri = $this->base.$uri;
         }
 
-        if ($absolute && null !== $this->host && !$urlHaveScheme) {
+        if (!$this->base && $absolute && null !== $this->host && !$urlHaveScheme) {
             return $this->host.$uri;
         }
 

+ 9 - 3
src/Symfony/Component/DomCrawler/Link.php

@@ -22,6 +22,7 @@ class Link
     protected $method;
     protected $host;
     protected $path;
+    protected $base;
 
     /**
      * Constructor.
@@ -30,10 +31,11 @@ class Link
      * @param string   $method The method to use for the link (get by default)
      * @param string   $host   The base URI to use for absolute links (like http://localhost)
      * @param string   $path   The base path for relative links (/ by default)
+     * @param strin    $base    An optional base href for generating the uri
      *
      * @throws \LogicException if the node is not a link
      */
-    public function __construct(\DOMNode $node, $method = 'get', $host = null, $path = '/')
+    public function __construct(\DOMNode $node, $method = 'get', $host = null, $path = '/', $base = null)
     {
         if ('a' != $node->nodeName) {
             throw new \LogicException(sprintf('Unable to click on a "%s" tag.', $node->nodeName));
@@ -43,6 +45,7 @@ class Link
         $this->method = $method;
         $this->host = $host;
         $this->path = empty($path) ? '/' : $path;
+        $this->base = $base;
     }
 
     /**
@@ -72,11 +75,14 @@ class Link
             $path = substr($path, 0, strrpos($path, '/') + 1);
         }
 
-        if ($uri && '/' !== $uri[0] && !$urlHaveScheme) {
+        if (!$this->base && $uri && '/' !== $uri[0] && !$urlHaveScheme) {
             $uri = $path.$uri;
+        } elseif ($this->base) {
+            $uri = $this->base.$uri;
         }
 
-        if ($absolute && null !== $this->host && !$urlHaveScheme) {
+        if (!$this->base && $absolute && null !== $this->host && !$urlHaveScheme) {
+
             return $this->host.$uri;
         }
 

+ 10 - 0
tests/Symfony/Tests/Component/DomCrawler/FormTest.php

@@ -384,4 +384,14 @@ class FormTest extends \PHPUnit_Framework_TestCase
 
         return new Form($nodes->item($nodes->length - 1), $method, $host, $path);
     }
+
+    public function testBase()
+    {
+        $dom = new \DOMDocument();
+        $dom->loadHTML('<html><form method="post" action="foo.php"><input type="text" name="bar" value="bar" /><input type="submit" /></form></html>');
+
+        $nodes = $dom->getElementsByTagName('input');
+        $form = new Form($nodes->item($nodes->length - 1), null, 'http://www.bar.com/foobar/', '/', 'http://www.foo.com/');
+        $this->assertEquals('http://www.foo.com/foo.php', $form->getUri());
+    }
 }

+ 6 - 0
tests/Symfony/Tests/Component/DomCrawler/LinkTest.php

@@ -82,5 +82,11 @@ class LinkTest extends \PHPUnit_Framework_TestCase
 
         $link = new Link($node, 'get', 'http://www.foo.com', '/foo/bar');
         $this->assertEquals('/foo/bar?get=param', $link->getUri(false), '->getUri() returns the relative URI of the link if false is the first argument');
+
+        $dom = new \DOMDocument();
+        $dom->loadHTML('<html><a href="test.html">foo</a></html>');
+        $node = $dom->getElementsByTagName('a')->item(0);
+        $link = new Link($node, 'get', null, '/foo/bar', 'http://www.foo.com/');
+        $this->assertEquals('http://www.foo.com/test.html', $link->getUri());
     }
 }