2015-08-18 00:00:26 +00:00
< ? 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
2018-11-23 12:29:20 +00:00
if ( \in_array ( $this -> type , array ( 'checkbox' , 'radio' )) && null === $this -> value ) {
2015-08-18 00:00:26 +00:00
return false ;
}
return true ;
}
/**
* Check if the current selected option is disabled .
*
* @ return bool
*/
public function isDisabled ()
{
2017-02-03 00:28:38 +00:00
if ( parent :: isDisabled () && 'select' === $this -> type ) {
return true ;
}
2015-08-18 00:00:26 +00:00
foreach ( $this -> options as $option ) {
if ( $option [ 'value' ] == $this -> value && $option [ 'disabled' ]) {
return true ;
}
}
return false ;
}
/**
* Sets the value of the field .
*
2018-11-23 12:29:20 +00:00
* @ param string | array $value The value of the field
2015-08-18 00:00:26 +00:00
*/
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 );
}
/**
2018-11-23 12:29:20 +00:00
* Unticks a checkbox .
2015-08-18 00:00:26 +00:00
*
* @ throws \LogicException When the type provided is not correct
*/
public function untick ()
{
if ( 'checkbox' !== $this -> type ) {
2018-11-23 12:29:20 +00:00
throw new \LogicException ( sprintf ( 'You cannot untick "%s" as it is not a checkbox (%s).' , $this -> name , $this -> type ));
2015-08-18 00:00:26 +00:00
}
$this -> setValue ( false );
}
/**
* Sets the value of the field .
*
2018-11-23 12:29:20 +00:00
* @ param string | array $value The value of the field
2015-08-18 00:00:26 +00:00
*
* @ 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 {
2018-11-23 12:29:20 +00:00
if ( \is_array ( $value )) {
2015-08-18 00:00:26 +00:00
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 ;
}
2018-11-23 12:29:20 +00:00
if ( \is_array ( $value )) {
2015-08-18 00:00:26 +00:00
$this -> value = $value ;
} else {
parent :: setValue ( $value );
}
}
}
/**
* Adds a choice to the current ones .
*
* @ param \DOMElement $node
*
* @ throws \LogicException When choice provided is not multiple nor radio
2018-11-23 12:29:20 +00:00
*
* @ internal
2015-08-18 00:00:26 +00:00
*/
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 = array ();
$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 = array ();
$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 .
*
* @ param \DOMElement $node
*
* @ return array
*/
private function buildOptionValue ( \DOMElement $node )
{
$option = array ();
2017-02-03 00:28:38 +00:00
$defaultDefaultValue = 'select' === $this -> node -> nodeName ? '' : 'on' ;
$defaultValue = ( isset ( $node -> nodeValue ) && ! empty ( $node -> nodeValue )) ? $node -> nodeValue : $defaultDefaultValue ;
2015-08-18 00:00:26 +00:00
$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 = array ();
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 ;
}
}