| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 | <?php/* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */namespace Symfony\Component\DomCrawler\Field;/** * ChoiceFormField represents a choice form field. * * It is constructed from a HTML select tag, or a HTML checkbox, or radio inputs. * * @author Fabien Potencier <fabien@symfony.com> */class ChoiceFormField extends FormField{    /**     * @var string     */    private $type;    /**     * @var bool     */    private $multiple;    /**     * @var array     */    private $options;    /**     * @var bool     */    private $validationDisabled = false;    /**     * Returns true if the field should be included in the submitted values.     *     * @return bool true if the field should be included in the submitted values, false otherwise     */    public function hasValue()    {        // don't send a value for unchecked checkboxes        if (\in_array($this->type, ['checkbox', 'radio']) && null === $this->value) {            return false;        }        return true;    }    /**     * Check if the current selected option is disabled.     *     * @return bool     */    public function isDisabled()    {        if (parent::isDisabled() && 'select' === $this->type) {            return true;        }        foreach ($this->options as $option) {            if ($option['value'] == $this->value && $option['disabled']) {                return true;            }        }        return false;    }    /**     * Sets the value of the field.     *     * @param string|array $value The value of the field     */    public function select($value)    {        $this->setValue($value);    }    /**     * Ticks a checkbox.     *     * @throws \LogicException When the type provided is not correct     */    public function tick()    {        if ('checkbox' !== $this->type) {            throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type));        }        $this->setValue(true);    }    /**     * Unticks a checkbox.     *     * @throws \LogicException When the type provided is not correct     */    public function untick()    {        if ('checkbox' !== $this->type) {            throw new \LogicException(sprintf('You cannot untick "%s" as it is not a checkbox (%s).', $this->name, $this->type));        }        $this->setValue(false);    }    /**     * Sets the value of the field.     *     * @param string|array|bool $value The value of the field     *     * @throws \InvalidArgumentException When value type provided is not correct     */    public function setValue($value)    {        if ('checkbox' === $this->type && false === $value) {            // uncheck            $this->value = null;        } elseif ('checkbox' === $this->type && true === $value) {            // check            $this->value = $this->options[0]['value'];        } else {            if (\is_array($value)) {                if (!$this->multiple) {                    throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name));                }                foreach ($value as $v) {                    if (!$this->containsOption($v, $this->options)) {                        throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $v, implode(', ', $this->availableOptionValues())));                    }                }            } elseif (!$this->containsOption($value, $this->options)) {                throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $value, implode(', ', $this->availableOptionValues())));            }            if ($this->multiple) {                $value = (array) $value;            }            if (\is_array($value)) {                $this->value = $value;            } else {                parent::setValue($value);            }        }    }    /**     * Adds a choice to the current ones.     *     * @throws \LogicException When choice provided is not multiple nor radio     *     * @internal     */    public function addChoice(\DOMElement $node)    {        if (!$this->multiple && 'radio' !== $this->type) {            throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name));        }        $option = $this->buildOptionValue($node);        $this->options[] = $option;        if ($node->hasAttribute('checked')) {            $this->value = $option['value'];        }    }    /**     * Returns the type of the choice field (radio, select, or checkbox).     *     * @return string The type     */    public function getType()    {        return $this->type;    }    /**     * Returns true if the field accepts multiple values.     *     * @return bool true if the field accepts multiple values, false otherwise     */    public function isMultiple()    {        return $this->multiple;    }    /**     * Initializes the form field.     *     * @throws \LogicException When node type is incorrect     */    protected function initialize()    {        if ('input' !== $this->node->nodeName && 'select' !== $this->node->nodeName) {            throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName));        }        if ('input' === $this->node->nodeName && 'checkbox' !== strtolower($this->node->getAttribute('type')) && 'radio' !== strtolower($this->node->getAttribute('type'))) {            throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is %s).', $this->node->getAttribute('type')));        }        $this->value = null;        $this->options = [];        $this->multiple = false;        if ('input' == $this->node->nodeName) {            $this->type = strtolower($this->node->getAttribute('type'));            $optionValue = $this->buildOptionValue($this->node);            $this->options[] = $optionValue;            if ($this->node->hasAttribute('checked')) {                $this->value = $optionValue['value'];            }        } else {            $this->type = 'select';            if ($this->node->hasAttribute('multiple')) {                $this->multiple = true;                $this->value = [];                $this->name = str_replace('[]', '', $this->name);            }            $found = false;            foreach ($this->xpath->query('descendant::option', $this->node) as $option) {                $optionValue = $this->buildOptionValue($option);                $this->options[] = $optionValue;                if ($option->hasAttribute('selected')) {                    $found = true;                    if ($this->multiple) {                        $this->value[] = $optionValue['value'];                    } else {                        $this->value = $optionValue['value'];                    }                }            }            // if no option is selected and if it is a simple select box, take the first option as the value            if (!$found && !$this->multiple && !empty($this->options)) {                $this->value = $this->options[0]['value'];            }        }    }    /**     * Returns option value with associated disabled flag.     *     * @return array     */    private function buildOptionValue(\DOMElement $node)    {        $option = [];        $defaultDefaultValue = 'select' === $this->node->nodeName ? '' : 'on';        $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : $defaultDefaultValue;        $option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue;        $option['disabled'] = $node->hasAttribute('disabled');        return $option;    }    /**     * Checks whether given value is in the existing options.     *     * @param string $optionValue     * @param array  $options     *     * @return bool     */    public function containsOption($optionValue, $options)    {        if ($this->validationDisabled) {            return true;        }        foreach ($options as $option) {            if ($option['value'] == $optionValue) {                return true;            }        }        return false;    }    /**     * Returns list of available field options.     *     * @return array     */    public function availableOptionValues()    {        $values = [];        foreach ($this->options as $option) {            $values[] = $option['value'];        }        return $values;    }    /**     * Disables the internal validation of the field.     *     * @return self     */    public function disableValidation()    {        $this->validationDisabled = true;        return $this;    }}
 |