vendor/symfony/src/Symfony/Component/DomCrawler/Form.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Component\DomCrawler;
       
    13 
       
    14 use Symfony\Component\DomCrawler\Field\FormField;
       
    15 
       
    16 /**
       
    17  * Form represents an HTML form.
       
    18  *
       
    19  * @author Fabien Potencier <fabien@symfony.com>
       
    20  *
       
    21  * @api
       
    22  */
       
    23 class Form extends Link implements \ArrayAccess
       
    24 {
       
    25     private $button;
       
    26     private $fields;
       
    27 
       
    28     /**
       
    29      * Constructor.
       
    30      *
       
    31      * @param \DOMNode $node       A \DOMNode instance
       
    32      * @param string   $currentUri The URI of the page where the form is embedded
       
    33      * @param string   $method     The method to use for the link (if null, it defaults to the method defined by the form)
       
    34      *
       
    35      * @throws \LogicException if the node is not a button inside a form tag
       
    36      *
       
    37      * @api
       
    38      */
       
    39     public function __construct(\DOMNode $node, $currentUri, $method = null)
       
    40     {
       
    41         parent::__construct($node, $currentUri, $method);
       
    42 
       
    43         $this->initialize();
       
    44     }
       
    45 
       
    46     /**
       
    47      * Gets the form node associated with this form.
       
    48      *
       
    49      * @return \DOMNode A \DOMNode instance
       
    50      */
       
    51     public function getFormNode()
       
    52     {
       
    53         return $this->node;
       
    54     }
       
    55 
       
    56     /**
       
    57      * Sets the value of the fields.
       
    58      *
       
    59      * @param array $values An array of field values
       
    60      *
       
    61      * @api
       
    62      */
       
    63     public function setValues(array $values)
       
    64     {
       
    65         foreach ($values as $name => $value) {
       
    66             $this[$name] = $value;
       
    67         }
       
    68 
       
    69         return $this;
       
    70     }
       
    71 
       
    72     /**
       
    73      * Gets the field values.
       
    74      *
       
    75      * The returned array does not include file fields (@see getFiles).
       
    76      *
       
    77      * @return array An array of field values.
       
    78      *
       
    79      * @api
       
    80      */
       
    81     public function getValues()
       
    82     {
       
    83         $values = array();
       
    84         foreach ($this->fields as $name => $field) {
       
    85             if ($field->isDisabled()) {
       
    86                 continue;
       
    87             }
       
    88 
       
    89             if (!$field instanceof Field\FileFormField && $field->hasValue()) {
       
    90                 $values[$name] = $field->getValue();
       
    91             }
       
    92         }
       
    93 
       
    94         return $values;
       
    95     }
       
    96 
       
    97     /**
       
    98      * Gets the file field values.
       
    99      *
       
   100      * @return array An array of file field values.
       
   101      *
       
   102      * @api
       
   103      */
       
   104     public function getFiles()
       
   105     {
       
   106         if (!in_array($this->getMethod(), array('POST', 'PUT', 'DELETE'))) {
       
   107             return array();
       
   108         }
       
   109 
       
   110         $files = array();
       
   111         foreach ($this->fields as $name => $field) {
       
   112             if ($field->isDisabled()) {
       
   113                 continue;
       
   114             }
       
   115 
       
   116             if ($field instanceof Field\FileFormField) {
       
   117                 $files[$name] = $field->getValue();
       
   118             }
       
   119         }
       
   120 
       
   121         return $files;
       
   122     }
       
   123 
       
   124     /**
       
   125      * Gets the field values as PHP.
       
   126      *
       
   127      * This method converts fields with th array notation
       
   128      * (like foo[bar] to arrays) like PHP does.
       
   129      *
       
   130      * @return array An array of field values.
       
   131      *
       
   132      * @api
       
   133      */
       
   134     public function getPhpValues()
       
   135     {
       
   136         $qs = http_build_query($this->getValues());
       
   137         parse_str($qs, $values);
       
   138 
       
   139         return $values;
       
   140     }
       
   141 
       
   142     /**
       
   143      * Gets the file field values as PHP.
       
   144      *
       
   145      * This method converts fields with th array notation
       
   146      * (like foo[bar] to arrays) like PHP does.
       
   147      *
       
   148      * @return array An array of field values.
       
   149      *
       
   150      * @api
       
   151      */
       
   152     public function getPhpFiles()
       
   153     {
       
   154         $qs = http_build_query($this->getFiles());
       
   155         parse_str($qs, $values);
       
   156 
       
   157         return $values;
       
   158     }
       
   159 
       
   160     /**
       
   161      * Gets the URI of the form.
       
   162      *
       
   163      * The returned URI is not the same as the form "action" attribute.
       
   164      * This method merges the value if the method is GET to mimics
       
   165      * browser behavior.
       
   166      *
       
   167      * @return string The URI
       
   168      *
       
   169      * @api
       
   170      */
       
   171     public function getUri()
       
   172     {
       
   173         $uri = parent::getUri();
       
   174 
       
   175         if (!in_array($this->getMethod(), array('POST', 'PUT', 'DELETE')) && $queryString = http_build_query($this->getValues(), null, '&')) {
       
   176             $sep = false === strpos($uri, '?') ? '?' : '&';
       
   177             $uri .= $sep.$queryString;
       
   178         }
       
   179 
       
   180         return $uri;
       
   181     }
       
   182 
       
   183     protected function getRawUri()
       
   184     {
       
   185         return $this->node->getAttribute('action');
       
   186     }
       
   187 
       
   188     /**
       
   189      * Gets the form method.
       
   190      *
       
   191      * If no method is defined in the form, GET is returned.
       
   192      *
       
   193      * @return string The method
       
   194      *
       
   195      * @api
       
   196      */
       
   197     public function getMethod()
       
   198     {
       
   199         if (null !== $this->method) {
       
   200             return $this->method;
       
   201         }
       
   202 
       
   203         return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET';
       
   204     }
       
   205 
       
   206     /**
       
   207      * Returns true if the named field exists.
       
   208      *
       
   209      * @param string $name The field name
       
   210      *
       
   211      * @return Boolean true if the field exists, false otherwise
       
   212      *
       
   213      * @api
       
   214      */
       
   215     public function has($name)
       
   216     {
       
   217         return isset($this->fields[$name]);
       
   218     }
       
   219 
       
   220     /**
       
   221      * Removes a field from the form.
       
   222      *
       
   223      * @param string $name The field name
       
   224      *
       
   225      * @api
       
   226      */
       
   227     public function remove($name)
       
   228     {
       
   229         unset($this->fields[$name]);
       
   230     }
       
   231 
       
   232     /**
       
   233      * Gets a named field.
       
   234      *
       
   235      * @param string $name The field name
       
   236      *
       
   237      * @return FormField The field instance
       
   238      *
       
   239      * @throws \InvalidArgumentException When field is not present in this form
       
   240      *
       
   241      * @api
       
   242      */
       
   243     public function get($name)
       
   244     {
       
   245         if (!$this->has($name)) {
       
   246             throw new \InvalidArgumentException(sprintf('The form has no "%s" field', $name));
       
   247         }
       
   248 
       
   249         return $this->fields[$name];
       
   250     }
       
   251 
       
   252     /**
       
   253      * Sets a named field.
       
   254      *
       
   255      * @param Field\FormField $field The field
       
   256      *
       
   257      * @return FormField The field instance
       
   258      *
       
   259      * @api
       
   260      */
       
   261     public function set(Field\FormField $field)
       
   262     {
       
   263         $this->fields[$field->getName()] = $field;
       
   264     }
       
   265 
       
   266     /**
       
   267      * Gets all fields.
       
   268      *
       
   269      * @return array An array of fields
       
   270      *
       
   271      * @api
       
   272      */
       
   273     public function all()
       
   274     {
       
   275         return $this->fields;
       
   276     }
       
   277 
       
   278     private function initialize()
       
   279     {
       
   280         $this->fields = array();
       
   281 
       
   282         $document = new \DOMDocument('1.0', 'UTF-8');
       
   283         $node = $document->importNode($this->node, true);
       
   284         $button = $document->importNode($this->button, true);
       
   285         $root = $document->appendChild($document->createElement('_root'));
       
   286         $root->appendChild($node);
       
   287         $root->appendChild($button);
       
   288         $xpath = new \DOMXPath($document);
       
   289 
       
   290         foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $root) as $node) {
       
   291             if (!$node->hasAttribute('name')) {
       
   292                 continue;
       
   293             }
       
   294 
       
   295             $nodeName = $node->nodeName;
       
   296 
       
   297             if ($node === $button) {
       
   298                 $this->set(new Field\InputFormField($node));
       
   299             } elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) {
       
   300                 $this->set(new Field\ChoiceFormField($node));
       
   301             } elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) {
       
   302                 if ($this->has($node->getAttribute('name'))) {
       
   303                     $this->get($node->getAttribute('name'))->addChoice($node);
       
   304                 } else {
       
   305                     $this->set(new Field\ChoiceFormField($node));
       
   306                 }
       
   307             } elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) {
       
   308                 $this->set(new Field\FileFormField($node));
       
   309             } elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) {
       
   310                 $this->set(new Field\InputFormField($node));
       
   311             } elseif ('textarea' == $nodeName) {
       
   312                 $this->set(new Field\TextareaFormField($node));
       
   313             }
       
   314         }
       
   315     }
       
   316 
       
   317     /**
       
   318      * Returns true if the named field exists.
       
   319      *
       
   320      * @param string $name The field name
       
   321      *
       
   322      * @return Boolean true if the field exists, false otherwise
       
   323      */
       
   324     public function offsetExists($name)
       
   325     {
       
   326         return $this->has($name);
       
   327     }
       
   328 
       
   329     /**
       
   330      * Gets the value of a field.
       
   331      *
       
   332      * @param string $name The field name
       
   333      *
       
   334      * @return FormField The associated Field instance
       
   335      *
       
   336      * @throws \InvalidArgumentException if the field does not exist
       
   337      */
       
   338     public function offsetGet($name)
       
   339     {
       
   340         if (!$this->has($name)) {
       
   341             throw new \InvalidArgumentException(sprintf('The form field "%s" does not exist', $name));
       
   342         }
       
   343 
       
   344         return $this->fields[$name];
       
   345     }
       
   346 
       
   347     /**
       
   348      * Sets the value of a field.
       
   349      *
       
   350      * @param string       $name  The field name
       
   351      * @param string|array $value The value of the field
       
   352      *
       
   353      * @throws \InvalidArgumentException if the field does not exist
       
   354      */
       
   355     public function offsetSet($name, $value)
       
   356     {
       
   357         if (!$this->has($name)) {
       
   358             throw new \InvalidArgumentException(sprintf('The form field "%s" does not exist', $name));
       
   359         }
       
   360 
       
   361         $this->fields[$name]->setValue($value);
       
   362     }
       
   363 
       
   364     /**
       
   365      * Removes a field from the form.
       
   366      *
       
   367      * @param string $name The field name
       
   368      */
       
   369     public function offsetUnset($name)
       
   370     {
       
   371         $this->remove($name);
       
   372     }
       
   373 
       
   374     protected function setNode(\DOMNode $node)
       
   375     {
       
   376         $this->button = $node;
       
   377         if ('button' == $node->nodeName || ('input' == $node->nodeName && in_array($node->getAttribute('type'), array('submit', 'button', 'image')))) {
       
   378             do {
       
   379                 // use the ancestor form element
       
   380                 if (null === $node = $node->parentNode) {
       
   381                     throw new \LogicException('The selected node does not have a form ancestor.');
       
   382                 }
       
   383             } while ('form' != $node->nodeName);
       
   384         } else {
       
   385             throw new \LogicException(sprintf('Unable to submit on a "%s" tag.', $node->nodeName));
       
   386         }
       
   387 
       
   388         $this->node = $node;
       
   389     }
       
   390 }