Generating an HTML single select element is similar to the process of generating radio buttons. The tags are structured differently, however, in that both a SELECT tag and a series of OPTION tags need to be generated.
Application\Form\Element\Select class that extends Application\Form\Generic.Generic rather than Radio is because the structuring of the element is entirely different:namespace Application\Form\Element;
use Application\Form\Generic;
class Select extends Generic
{
// code
}Application\Form\Generic. Unlike radio buttons or checkboxes, there is no need to account for spacers or the placement of the selected text:const DEFAULT_OPTION_KEY = 0; const DEFAULT_OPTION_VALUE = 'Choose'; protected $options; protected $selectedKey = DEFAULT_OPTION_KEY;
$selectedKey property could be either a string or an array. Accordingly, we do not add a type hint for this property. It is important, however, that we identify whether or not the multiple attribute has been set. This can be obtained from a $this->attributes property via inheritance from the parent class.multiple attribute has been set, it's important to formulate the name attribute as an array. Accordingly, we would append [] to the name if this were the case:public function setOptions(array $options, $selectedKey = self::DEFAULT_OPTION_KEY)
{
$this->options = $options;
$this->selectedKey = $selectedKey;
if (isset($this->attributes['multiple'])) {
$this->name .= '[]';
}
}getInputOnly() method, we need to define a method to generate the select tag. We then return the final HTML using sprintf(), using $pattern, $name, and the return value of getAttribs() as arguments.$pattern with <select name="%s" %s>. We then loop through the attributes, adding them as key-value pairs with spaces in between:protected function getSelect()
{
$this->pattern = '<select name="%s" %s> ' . PHP_EOL;
return sprintf($this->pattern, $this->name,
$this->getAttribs());
}option tags that will be associated with the select tag.$this->options array represents the return value, whereas the value part of the array represents the text that will appear on screen. If $this->selectedKey is in array form, we check to see if the value is in the array. Otherwise, we assume $this-> selectedKey is a string and we simply determine if it is equal to the key. If the selected key matches, we add the selected attribute:protected function getOptions()
{
$output = '';
foreach ($this->options as $key => $value) {
if (is_array($this->selectedKey)) {
$selected = (in_array($key, $this->selectedKey))
? ' selected' : '';
} else {
$selected = ($key == $this->selectedKey)
? ' selected' : '';
}
$output .= '<option value="' . $key . '"'
. $selected . '>'
. $value
. '</option>';
}
return $output;
}getInputOnly() method.getSelect() and getOptions() methods described in the preceding code. We also need to add the closing </select> tag:public function getInputOnly()
{
$output = $this->getSelect();
$output .= $this->getOptions();
$output .= '</' . $this->getType() . '>';
return $output;
}Copy the code described above into a new Select.php file in the Application/Form/Element folder. Then define a chap_06_form_element_select.php calling script that sets up autoloading and anchors the new class:
<?php require __DIR__ . '/../Application/Autoload/Loader.php'; Application\Autoload\Loader::init(__DIR__ . '/..'); use Application\Form\Generic; use Application\Form\Element\Select;
Next, define the wrappers using the array $wrappers defined in the first recipe. You can also use the $statusList array defined in the Creating an HTML radio element generator recipe. You can then create instances of SELECT elements. The first instance is single select, and the second is multiple:
$status1 = new Select('status1',
Generic::TYPE_SELECT,
'Status 1',
$wrappers,
['id' => 'status1']);
$status2 = new Select('status2',
Generic::TYPE_SELECT,
'Status 2',
$wrappers,
['id' => 'status2',
'multiple' => '',
'size' => '4']);See if there is any status input from $_GET and set the options. Any input will become the selected key. Otherwise, the selected key is the default. As you will recall, the second instance is multiple select, so the value obtained from $_GET and the default setting should both be in the form of an array:
$checked1 = $_GET['status1'] ?? 'U'; $checked2 = $_GET['status2'] ?? ['U']; $status1->setOptions($statusList, $checked1); $status2->setOptions($statusList, $checked2);
Lastly, be sure to define a submit button (as shown in the Creating a generic form element generator recipe of this chapter).
The actual display logic is identical to the radio button recipe, except that we need to render two separate HTML select instances:
<form name="status" method="get">
<table id="status" class="display" cellspacing="0" width="100%">
<tr><?= $status1->render(); ?></tr>
<tr><?= $status2->render(); ?></tr>
<tr><?= $submit->render(); ?></tr>
<tr>
<td colspan=2>
<br>
<pre>
<?php var_dump($_GET); ?>
</pre>
</td>
</tr>
</table>
</form>Here is the actual output:

Also, you can see how the elements appear in the view source page:
