8000 merged branch kepten/ticket_7486 (PR #7500) · symfony/symfony@3a3ff28 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3a3ff28

Browse files
committed
merged branch kepten/ticket_7486 (PR #7500)
This PR was merged into the master branch. Discussion ---------- [DomCrawler] added support for HTML5 'form' attribute | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #7486 | License | MIT | Doc PR | Commits ------- f8178dd [DomCrawler] added support for HTML5 'form' attribute
2 parents 98f5983 + f8178dd commit 3a3ff28

File tree

4 files changed

+113
-24
lines changed

4 files changed

+113
-24
lines changed

src/Symfony/Component/DomCrawler/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* added schema relative URL support to links
8+
* added support for HTML5 'form' attribute
89

910
2.2.0
1011
-----

src/Symfony/Component/DomCrawler/Form.php

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ public function offsetUnset($name)
331331
}
332332

333333
/**
334-
* Sets current \DOMNode instance.
334+
* Sets the node for the form.
335+
*
336+
* Expects a 'submit' button \DOMNode and finds the corresponding form element.
335337
*
336338
* @param \DOMNode $node A \DOMNode instance
337339
*
@@ -341,8 +343,18 @@ protected function setNode(\DOMNode $node)
341343
{
342344
$this->button = $node;
343345
if ('button' == $node->nodeName || ('input' == $node->nodeName && in_array($node->getAttribute('type'), array('submit', 'button', 'image')))) {
346+
if ($node->hasAttribute('form')) {
347+
// if the node has the HTML5-compliant 'form' attribute, use it
348+
$formId = $node->getAttribute('form');
349+
$form = $node->ownerDocument->getElementById($formId);
350+
if (null === $form) {
351+
throw new \LogicException(sprintf('The selected node has an invalid form attribute (%s).', $formId));
352+
}
353+
$this->node = $form;
354+
return;
355+
}
356+
// we loop until we find a form ancestor
344357
do {
345-
// use the ancestor form element
346358
if (null === $node = $node->parentNode) {
347359
throw new \LogicException('The selected node does not have a form ancestor.');
348360
}
@@ -366,30 +378,47 @@ private function initialize()
366378
$root->appendChild($button);
367379
$xpath = new \DOMXPath($document);
368380

369-
foreach ($xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root) as $node) {
370-
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
371-
continue;
381+
// add descendant elements to the form
382+
$fieldNodes = $xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root);
383+
foreach ($fieldNodes as $node) {
384+
$this->addField($node, $button);
385+
}
386+
387+
// find form elements corresponding to the current form by the HTML5 form attribute
388+
if ($this->node->hasAttribute('id')) {
389+
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
390+
$xpath = new \DOMXPath($this->node->ownerDocument);
391+
$fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s]', $formId, $formId, $formId, $formId));
392+
foreach ($fieldNodes as $node) {
393+
$this->addField($node, $button);
372394
}
395+
}
396+
}
397+
398+
private function addField(\DOMNode $node, \DOMNode $button)
399+
{
400+
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
401+
return;
402+
}
373403

374-
$nodeName = $node->nodeName;
404+
$nodeName = $node->nodeName;
375405

376-
if ($node === $button) {
377-
$this->set(new Field\InputFormField($node));
378-
} elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) {
406+
if ($node === $button) {
407+
$this->set(new Field\InputFormField($node));
408+
} elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) {
409+
$this->set(new Field\ChoiceFormField($node));
410+
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
411+
if ($this->has($node->getAttribute('name'))) {
412+
$this->get($node->getAttribute('name'))->addChoice($node);
413+
} else {
379414
$this->set(new Field\ChoiceFormField($node));
380-
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
381-
if ($this->has($node->getAttribute('name'))) {
382-
$this->get($node->getAttribute('name'))->addChoice($node);
383-
} else {
384-
$this->set(new Field\ChoiceFormField($node));
385-
}
386-
} elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) {
387-
$this->set(new Field\FileFormField($node));
388-
} elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) {
389-
$this->set(new Field\InputFormField($node));
390-
} elseif ('textarea' == $nodeName) {
391-
$this->set(new Field\TextareaFormField($node));
392415
}
416+
} elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) {
417+
$this->set(new Field\FileFormField($node));
418+
} elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) {
419+
$this->set(new Field\InputFormField($node));
420+
} elseif ('textarea' == $nodeName) {
421+
$this->set(new Field\TextareaFormField($node));
393422
}
394423
}
395424
}

src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ public function testSelectButton()
393393
$this->assertEquals(1, $crawler->selectButton('BarValue')->count(), '->selectButton() selects buttons');
394394
$this->assertEquals(1, $crawler->selectButton('BarName')->count(), '->selectButton() selects buttons');
395395
$this->assertEquals(1, $crawler->selectButton('BarId')->count(), '->selectButton() selects buttons');
396+
397+
$this->assertEquals(1, $crawler->selectButton('FooBarValue')->count(), '->selectButton() selects buttons with form attribute too');
398+
$this->assertEquals(1, $crawler->selectButton('FooBarName')->count(), '->selectButton() selects buttons with form attribute too');
396399
}
397400

398401
public function testLink()
@@ -427,10 +430,17 @@ public function testLinks()
427430

428431
public function testForm()
429432
{
430-
$crawler = $this->createTestCrawler('http://example.com/bar/')->selectButton('FooValue');
433+
$testCrawler = $this->createTestCrawler('http://example.com/bar/');
434+
$crawler = $testCrawler->selectButton('FooValue');
435+
$crawler2 = $testCrawler->selectButton('FooBarValue');
431436
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler->form(), '->form() returns a Form instance');
437+
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler2->form(), '->form() returns a Form instance');
438+
439+
$this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute');
432440

433-
$this->assertEquals(array('FooName' => 'FooBar'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument');
441+
$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');
442+
$this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->form() takes an array of values to submit as its first argument');
443+
$this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->form() takes an array of values to submit as its first argument');
434444

435445
try {
436446
$this->createTestCrawler()->filterXPath('//ol')->form();
@@ -576,12 +586,16 @@ public function createTestCrawler($uri = null)
576586
577587
<a href="?get=param">GetLink</a>
578588
579-
<form action="foo">
589+
<form action="foo" id="FooFormId">
590+
<input type="text" value="TextValue" name="TextName" />
580591
<input type="submit" value="FooValue" name="FooName" id="FooId" />
581592
<input type="button" value="BarValue" name="BarName" id="BarId" />
582593
<button value="ButtonValue" name="ButtonName" id="ButtonId" />
583594
</form>
584595
596+
<input type="submit" value="FooBarValue" name="FooBarName" form="FooFormId" />
597+
<input type="text" value="FooTextValue" name="FooTextName" form="FooFormId" />
598+
585599
<ul class="first">
586600
<li class="first">One</li>
587601
<li>Two</li>

src/Symfony/Component/DomCrawler/Tests/FormTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,51 @@ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
6262
}
6363
}
6464

65+
/**
66+
* __construct() should throw \\LogicException if the form attribute is invalid
67+
* @expectedException \LogicException
68+
*/
69+
public function testConstructorThrowsExceptionIfNoRelatedForm()
70+
{
71+
$dom = new \DOMDocument();
72+
$dom->loadHTML('
73+
<html>
74+
<form id="bar">
75+
<input type="submit" form="nonexistent" />
76+
</form>
77+
<input type="text" form="nonexistent" />
78+
<button />
79+
</html>
80+
');
81+
82+
$nodes = $dom->getElementsByTagName('input');
83+
84+
$form = new Form($nodes->item(0), 'http://example.com');
85+
$form = new Form($nodes->item(1), 'http://example.com');
86+
}
87+
88+
public function testConstructorHandlesFormAttribute()
89+
{
90+
$dom = new \DOMDocument();
91+
$dom->loadHTML('
92+
<html>
93+
<form id="bar">
94+
<input type="submit" form="bar" />
95+
</form>
96+
<input type="submit" form="bar" />
97+
<button />
98+
</html>
99+
');
100+
101+
$nodes = $dom->getElementsByTagName('input');
102+
103+
$form = new Form($nodes->item(0), 'http://example.com');
104+
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
105+
106+
$form = new Form($nodes->item(1), 'http://example.com');
107+
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
108+
}
109+
65110
public function testMultiValuedFields()
66111
{
67112
$form = $this->createForm('<form>

0 commit comments

Comments
 (0)
0