@@ -367,46 +367,59 @@ protected function setNode(\DOMNode $node)
367
367
$ this ->node = $ node ;
368
368
}
369
369
370
+ /**
371
+ * Adds form elements related to this form.
372
+ *
373
+ * Creates an internal copy of the submitted 'button' element and
374
+ * the form node or the entire document depending on whether we need
375
+ * to find non-descendant elements through HTML5 'form' attribute.
376
+ */
370
377
private function initialize ()
371
378
{
372
379
$ this ->fields = new FormFieldRegistry ();
373
380
374
381
$ document = new \DOMDocument ('1.0 ' , 'UTF-8 ' );
375
- $ node = $ document ->importNode ($ this ->node , true );
376
- $ button = $ document ->importNode ($ this ->button , true );
377
- $ root = $ document ->appendChild ($ document ->createElement ('_root ' ));
378
- $ root ->appendChild ($ node );
379
- $ root ->appendChild ($ button );
380
382
$ xpath = new \DOMXPath ($ document );
383
+ $ root = $ document ->appendChild ($ document ->createElement ('_root ' ));
381
384
382
- // add descendant elements to the form
383
- $ fieldNodes = $ xpath ->query ('descendant::input | descendant::button | descendant::textarea | descendant::select ' , $ root );
384
- foreach ($ fieldNodes as $ node ) {
385
- $ this ->addField ($ node , $ button );
385
+ // add submitted button if it has a valid name
386
+ if ($ this ->button ->hasAttribute ('name ' ) && $ this ->button ->getAttribute ('name ' )) {
387
+ $ this ->set (new Field \InputFormField ($ document ->importNode ($ this ->button , true )));
386
388
}
387
389
388
- // find form elements corresponding to the current form by the HTML5 form attribute
390
+ // find form elements corresponding to the current form
389
391
if ($ this ->node ->hasAttribute ('id ' )) {
392
+ // traverse through the whole document
393
+ $ node = $ document ->importNode ($ this ->node ->ownerDocument ->documentElement , true );
394
+ $ root ->appendChild ($ node );
395
+
396
+ // corresponding elements are either descendants or have a matching HTML5 form attribute
390
397
$ formId = Crawler::xpathLiteral ($ this ->node ->getAttribute ('id ' ));
391
- $ xpath = new \DOMXPath ($ this ->node ->ownerDocument );
392
- $ fieldNodes = $ xpath ->query (sprintf ('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] ' , $ formId , $ formId , $ formId , $ formId ));
398
+ $ 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 );
393
399
foreach ($ fieldNodes as $ node ) {
394
- $ this ->addField ($ node , $ button );
400
+ $ this ->addField ($ node );
401
+ }
402
+ } else {
403
+ // parent form has no id, add descendant elements only
404
+ $ node = $ document ->importNode ($ this ->node , true );
405
+ $ root ->appendChild ($ node );
406
+
407
+ // descendant elements with form attribute are not part of this form
408
+ $ fieldNodes = $ xpath ->query ('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] ' , $ root );
409
+ foreach ($ fieldNodes as $ node ) {
410
+ $ this ->addField ($ node );
395
411
}
396
412
}
397
413
}
398
414
399
- private function addField (\DOMNode $ node, \ DOMNode $ button )
415
+ private function addField (\DOMNode $ node )
400
416
{
401
417
if (!$ node ->hasAttribute ('name ' ) || !$ node ->getAttribute ('name ' )) {
402
418
return ;
403
419
}
404
420
405
421
$ nodeName = $ node ->nodeName ;
406
-
407
- if ($ node === $ button ) {
408
- $ this ->set (new Field \InputFormField ($ node ));
409
- } elseif ('select ' == $ nodeName || 'input ' == $ nodeName && 'checkbox ' == $ node ->getAttribute ('type ' )) {
422
+ if ('select ' == $ nodeName || 'input ' == $ nodeName && 'checkbox ' == $ node ->getAttribute ('type ' )) {
410
423
$ this ->set (new Field \ChoiceFormField ($ node ));
411
424
} elseif ('input ' == $ nodeName && 'radio ' == $ node ->getAttribute ('type ' )) {
412
425
if ($ this ->has ($ node ->getAttribute ('name ' ))) {
0 commit comments