[DomCrawler] fixed HTML5 form attribute handling
This commit is contained in:
parent
b219e0a9c6
commit
04e730ec2e
@ -366,46 +366,59 @@ class Form extends Link implements \ArrayAccess
|
|||||||
$this->node = $node;
|
$this->node = $node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds form elements related to this form.
|
||||||
|
*
|
||||||
|
* Creates an internal copy of the submitted 'button' element and
|
||||||
|
* the form node or the entire document depending on whether we need
|
||||||
|
* to find non-descendant elements through HTML5 'form' attribute.
|
||||||
|
*/
|
||||||
private function initialize()
|
private function initialize()
|
||||||
{
|
{
|
||||||
$this->fields = new FormFieldRegistry();
|
$this->fields = new FormFieldRegistry();
|
||||||
|
|
||||||
$document = new \DOMDocument('1.0', 'UTF-8');
|
$document = new \DOMDocument('1.0', 'UTF-8');
|
||||||
$node = $document->importNode($this->node, true);
|
|
||||||
$button = $document->importNode($this->button, true);
|
|
||||||
$root = $document->appendChild($document->createElement('_root'));
|
|
||||||
$root->appendChild($node);
|
|
||||||
$root->appendChild($button);
|
|
||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
|
$root = $document->appendChild($document->createElement('_root'));
|
||||||
|
|
||||||
// add descendant elements to the form
|
// add submitted button if it has a valid name
|
||||||
$fieldNodes = $xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root);
|
if ($this->button->hasAttribute('name') && $this->button->getAttribute('name')) {
|
||||||
foreach ($fieldNodes as $node) {
|
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
|
||||||
$this->addField($node, $button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find form elements corresponding to the current form by the HTML5 form attribute
|
// find form elements corresponding to the current form
|
||||||
if ($this->node->hasAttribute('id')) {
|
if ($this->node->hasAttribute('id')) {
|
||||||
|
// traverse through the whole document
|
||||||
|
$node = $document->importNode($this->node->ownerDocument->documentElement, true);
|
||||||
|
$root->appendChild($node);
|
||||||
|
|
||||||
|
// corresponding elements are either descendants or have a matching HTML5 form attribute
|
||||||
$formId = Crawler::xpathLiteral($this->node->getAttribute('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] | //form[@id=%s]/input[not(@form)] | //form[@id=%s]/button[not(@form)] | //form[@id=%s]/textarea[not(@form)] | //form[@id=%s]/select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $formId), $root);
|
||||||
$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) {
|
foreach ($fieldNodes as $node) {
|
||||||
$this->addField($node, $button);
|
$this->addField($node);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// parent form has no id, add descendant elements only
|
||||||
|
$node = $document->importNode($this->node, true);
|
||||||
|
$root->appendChild($node);
|
||||||
|
|
||||||
|
// descendant elements with form attribute are not part of this form
|
||||||
|
$fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $root);
|
||||||
|
foreach ($fieldNodes as $node) {
|
||||||
|
$this->addField($node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addField(\DOMNode $node, \DOMNode $button)
|
private function addField(\DOMNode $node)
|
||||||
{
|
{
|
||||||
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
|
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nodeName = $node->nodeName;
|
$nodeName = $node->nodeName;
|
||||||
|
if ('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));
|
$this->set(new Field\ChoiceFormField($node));
|
||||||
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
|
} elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
|
||||||
if ($this->has($node->getAttribute('name'))) {
|
if ($this->has($node->getAttribute('name'))) {
|
||||||
|
@ -90,21 +90,53 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
|||||||
$dom = new \DOMDocument();
|
$dom = new \DOMDocument();
|
||||||
$dom->loadHTML('
|
$dom->loadHTML('
|
||||||
<html>
|
<html>
|
||||||
<form id="bar">
|
<form id="form_1" action="" method="POST">
|
||||||
<input type="submit" form="bar" />
|
<input type="checkbox" name="apples[]" value="1" checked />
|
||||||
|
<input form="form_2" type="checkbox" name="oranges[]" value="1" checked />
|
||||||
|
<input form="form_1" type="hidden" name="form_name" value="form_1" />
|
||||||
|
<input form="form_1" type="submit" name="button_1" value="Capture fields" />
|
||||||
|
<button form="form_2" type="submit" name="button_2">Submit form_2</button>
|
||||||
|
</form>
|
||||||
|
<input form="form_1" type="checkbox" name="apples[]" value="2" checked />
|
||||||
|
<form id="form_2" action="" method="POST">
|
||||||
|
<input type="checkbox" name="oranges[]" value="2" checked />
|
||||||
|
<input type="checkbox" name="oranges[]" value="3" checked />
|
||||||
|
<input form="form_2" type="hidden" name="form_name" value="form_2" />
|
||||||
|
<input form="form_1" type="hidden" name="outer_field" value="success" />
|
||||||
|
<button form="form_1" type="submit" name="button_3">Submit from outside the form</button>
|
||||||
</form>
|
</form>
|
||||||
<input type="submit" form="bar" />
|
|
||||||
<button />
|
<button />
|
||||||
</html>
|
</html>
|
||||||
');
|
');
|
||||||
|
|
||||||
$nodes = $dom->getElementsByTagName('input');
|
$inputElements = $dom->getElementsByTagName('input');
|
||||||
|
$buttonElements = $dom->getElementsByTagName('button');
|
||||||
|
|
||||||
$form = new Form($nodes->item(0), 'http://example.com');
|
// Tests if submit buttons are correctly assigned to forms
|
||||||
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
|
$form1 = new Form($buttonElements->item(1), 'http://example.com');
|
||||||
|
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form1->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
|
||||||
|
|
||||||
|
$form1 = new Form($inputElements->item(3), 'http://example.com');
|
||||||
|
$this->assertSame($dom->getElementsByTagName('form')->item(0), $form1->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
|
||||||
|
|
||||||
|
$form2 = new Form($buttonElements->item(0), 'http://example.com');
|
||||||
|
$this->assertSame($dom->getElementsByTagName('form')->item(1), $form2->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
|
||||||
|
|
||||||
|
// Tests if form elements are correctly assigned to forms
|
||||||
|
$values1 = array(
|
||||||
|
'apples' => array('1', '2'),
|
||||||
|
'form_name' => 'form_1',
|
||||||
|
'button_1' => 'Capture fields',
|
||||||
|
'outer_field' => 'success'
|
||||||
|
);
|
||||||
|
$values2 = array(
|
||||||
|
'oranges' => array('1', '2', '3'),
|
||||||
|
'form_name' => 'form_2',
|
||||||
|
'button_2' => '',
|
||||||
|
);
|
||||||
|
$this->assertEquals($values1, $form1->getPhpValues(), 'HTML5-compliant form attribute handled incorrectly');
|
||||||
|
$this->assertEquals($values2, $form2->getPhpValues(), '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()
|
public function testMultiValuedFields()
|
||||||
|
Reference in New Issue
Block a user