8000 [DomCrawler] added support for HTML5 'form' attribute by kepten · Pull Request #7500 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DomCrawler] added support for HTML5 'form' attribute #7500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations 8000
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[DomCrawler] added support for HTML5 'form' attribute
  • Loading branch information
kepten committed Apr 1, 2013
commit f8178dd1bb53f192b8e20fd002ec507ac3711199
1 change: 1 addition & 0 deletions src/Symfony/Component/DomCrawler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
-----

* added schema relative URL support to links
* added support for HTML5 'form' attribute

2.2.0
-----
Expand Down
71 changes: 50 additions & 21 deletions src/Symfony/Component/DomCrawler/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,9 @@ public function offsetUnset($name)
}

/**
* Sets current \DOMNode instance.
* Sets the node for the form.
*
* Expects a 'submit' button \DOMNode and finds the corresponding form element.
*
* @param \DOMNode $node A \DOMNode instance
*
Expand All @@ -341,8 +343,18 @@ protected function setNode(\DOMNode $node)
{
$this->button = $node;
if ('button' == $node->nodeName || ('input' == $node->nodeName && in_array($node->getAttribute('type'), array('submit', 'button', 'image')))) {
if ($node->hasAttribute('form')) {
// if the node has the HTML5-compliant 'form' attribute, use it
$formId = $node->getAttribute('form');
$form = $node->ownerDocument->getElementById($formId);
if (null === $form) {
throw new \LogicException(sprintf('The selected node has an invalid form attribute (%s).', $formId));
}
$this->node = $form;
return;
}
// we loop until we find a form ancestor
do {
// use the ancestor form element
if (null === $node = $node->parentNode) {
throw new \LogicException('The selected node does not have a form ancestor.');
}
Expand All @@ -366,30 +378,47 @@ private function initialize()
$root->appendChild($button);
$xpath = new \DOMXPath($document);

foreach ($xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root) as $node) {
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
continue;
// add descendant elements to the form
$fieldNodes = $xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root);
foreach ($fieldNodes as $node) {
$this->addField($node, $button);
}

// find form elements corresponding to the current form by the HTML5 form attribute
if ($this->node->hasAttribute('id')) {
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
$xpath = new \DOMXPath($this->node->ownerDocument);
$fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s]', $formId, $formId, $formId, $formId));
foreach ($fieldNodes as $node) {
$this->addField($node, $button);
}
}
}

private function addField(\DOMNode $node, \DOMNode $button)
{
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
return;
}

$nodeName = $node->nodeName;
$nodeName = $node->nodeName;

if ($node === $button) {
$this->set(new Field\InputFormField($node));
} elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) {
if ($node === $button) {
$this->set(new Field\InputFormField($node));
} elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) {
$this->set(new Field\ChoiceFormField($node));
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
if ($this->has($node->getAttribute('name'))) {
$this->get($node->getAttribute('name'))->addChoice($node);
} else {
$this->set(new Field\ChoiceFormField($node));
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
if ($this->has($node->getAttribute('name'))) {
$this->get($node->getAttribute('name'))->addChoice($node);
} else {
$this->set(new Field\ChoiceFormField($node));
}
} elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) {
$this->set(new Field\FileFormField($node));
} elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) {
$this->set(new Field\InputFormField($node));
} elseif ('textarea' == $nodeName) {
$this->set(new Field\TextareaFormField($node));
}
} elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) {
$this->set(new Field\FileFormField($node));
} elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) {
$this->set(new Field\InputFormField($node));
} elseif ('textarea' == $nodeName) {
$this->set(new Field\TextareaFormField($node));
}
}
}
20 changes: 17 additions & 3 deletions src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ public function testSelectButton()
$this->assertEquals(1, $crawler->selectButton('BarValue')->count(), '->selectButton() selects buttons');
$this->assertEquals(1, $crawler->selectButton('BarName')->count(), '->selectButton() selects buttons');
$this->assertEquals(1, $crawler->selectButton('BarId')->count(), '->selectButton() selects buttons');

$this->assertEquals(1, $crawler->selectButton('FooBarValue')->count(), '->selectButton() selects buttons with form attribute too');
$this->assertEquals(1, $crawler->selectButton('FooBarName')->count(), '->selectButton() selects buttons with form attribute too');
}

public function testLink()
Expand Down Expand Up @@ -427,10 +430,17 @@ public function testLinks()

public function testForm()
{
$crawler = $this->createTestCrawler('http://example.com/bar/')->selectButton('FooValue');
$testCrawler = $this->createTestCrawler('http://example.com/bar/');
$crawler = $testCrawler->selectButton('FooValue');
$crawler2 = $testCrawler->selectButton('FooBarValue');
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler->form(), '->form() returns a Form instance');
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler2->form(), '->form() returns a Form instance');

$this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute');

$this->assertEquals(array('FooName' => 'FooBar'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument');
$this->assertEquals(array('FooName' => 'FooBar', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument');
$this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->form() takes an array of values to submit as its first argument');
$this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->form() takes an array of values to submit as its first argument');

try {
$this->createTestCrawler()->filterXPath('//ol')->form();
Expand Down Expand Up @@ -576,12 +586,16 @@ public function createTestCrawler($uri = null)

<a href="?get=param">GetLink</a>

<form action="foo">
<form action="foo" id="FooFormId">
<input type="text" value="TextValue" name="TextName" />
<input type="submit" value="FooValue" name="FooName" id="FooId" />
<input type="button" value="BarValue" name="BarName" id="BarId" />
<button value="ButtonValue" name="ButtonName" id="ButtonId" />
</form>

<input type="submit" value="FooBarValue" name="FooBarName" form="FooFormId" />
<input type="text" value="FooTextValue" name="FooTextName" form="FooFormId" />

<ul class="first">
<li class="first">One</li>
<li>Two</li>
Expand Down
45 changes: 45 additions & 0 deletions src/Symfony/Component/DomCrawler/Tests/FormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,51 @@ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
}
}

/**
* __construct() should throw \\LogicException if the form attribute is invalid
* @expectedException \LogicException
*/
public function testConstructorThrowsExceptionIfNoRelatedForm()
{
$dom = new \DOMDocument();
$dom->loadHTML('
<html>
<form id="bar">
<input type="submit" form="nonexistent" />
</form>
<input type="text" form="nonexistent" />
<button />
</html>
');

$nodes = $dom->getElementsByTagName('input');

$form = new Form($nodes->item(0), 'http://example.com');
$form = new Form($nodes->item(1), 'http://example.com');
}

public function testConstructorHandlesFormAttribute()
{
$dom = new \DOMDocument();
$dom->loadHTML('
<html>
<form id="bar">
<input type="submit" form="bar" />
</form>
<input type="submit" form="bar" />
<button />
</html>
');

$nodes = $dom->getElementsByTagName('input');

$form = new Form($nodes->item(0), 'http://example.com');
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');

$form = new Form($nodes->item(1), 'http://example.com');
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
}

public function testMultiValuedFields()
{
$form = $this->createForm('<form>
Expand Down
0