1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
6: */
7:
8: namespace Nette\Forms\Controls;
9:
10: use Nette;
11:
12:
13: /**
14: * Select box control that allows single item selection.
15: *
16: * @author David Grudl
17: *
18: * @property-read mixed $rawValue
19: * @property bool $prompt
20: * @property array $items
21: * @property-read string $selectedItem
22: */
23: class SelectBox extends BaseControl
24: {
25: /** @var array */
26: private $items = array();
27:
28: /** @var array */
29: protected $allowed = array();
30:
31: /** @var mixed */
32: private $prompt = FALSE;
33:
34: /** @var bool */
35: private $useKeys = TRUE;
36:
37:
38: /**
39: * @param string label
40: * @param array items from which to choose
41: * @param int number of rows that should be visible
42: */
43: public function __construct($label = NULL, array $items = NULL, $size = NULL)
44: {
45: parent::__construct($label);
46: $this->control->setName('select');
47: $this->control->size = $size > 1 ? (int) $size : NULL;
48: if ($items !== NULL) {
49: $this->setItems($items);
50: }
51: }
52:
53:
54: /**
55: * Returns selected item key.
56: * @return mixed
57: */
58: public function getValue()
59: {
60: return is_scalar($this->value) && isset($this->allowed[$this->value]) ? $this->value : NULL;
61: }
62:
63:
64: /**
65: * Returns selected item key (not checked).
66: * @return mixed
67: */
68: public function getRawValue()
69: {
70: return is_scalar($this->value) ? $this->value : NULL;
71: }
72:
73:
74: /**
75: * Has been any item selected?
76: * @return bool
77: */
78: public function isFilled()
79: {
80: $value = $this->getValue();
81: return is_array($value) ? count($value) > 0 : $value !== NULL;
82: }
83:
84:
85: /**
86: * Sets first prompt item in select box.
87: * @param string
88: * @return self
89: */
90: public function setPrompt($prompt)
91: {
92: if ($prompt === TRUE) { // back compatibility
93: $prompt = reset($this->items);
94: unset($this->allowed[key($this->items)], $this->items[key($this->items)]);
95: }
96: $this->prompt = $prompt;
97: return $this;
98: }
99:
100:
101: /** @deprecated */
102: function skipFirst($v = NULL)
103: {
104: trigger_error(__METHOD__ . '() is deprecated; use setPrompt() instead.', E_USER_WARNING);
105: return $this->setPrompt($v);
106: }
107:
108:
109: /**
110: * Returns first prompt item?
111: * @return mixed
112: */
113: public function getPrompt()
114: {
115: return $this->prompt;
116: }
117:
118:
119: /**
120: * Are the keys used?
121: * @return bool
122: */
123: public function areKeysUsed()
124: {
125: return $this->useKeys;
126: }
127:
128:
129: /**
130: * Sets items from which to choose.
131: * @param array
132: * @param bool
133: * @return self
134: */
135: public function setItems(array $items, $useKeys = TRUE)
136: {
137: $allowed = array();
138: foreach ($items as $k => $v) {
139: foreach ((is_array($v) ? $v : array($k => $v)) as $key => $value) {
140: if (!$useKeys) {
141: if (!is_scalar($value)) {
142: throw new Nette\InvalidArgumentException("All items must be scalar.");
143: }
144: $key = $value;
145: }
146:
147: if (isset($allowed[$key])) {
148: throw new Nette\InvalidArgumentException("Items contain duplication for key '$key'.");
149: }
150:
151: $allowed[$key] = $value;
152: }
153: }
154:
155: $this->items = $items;
156: $this->allowed = $allowed;
157: $this->useKeys = (bool) $useKeys;
158: return $this;
159: }
160:
161:
162: /**
163: * Returns items from which to choose.
164: * @return array
165: */
166: public function getItems()
167: {
168: return $this->items;
169: }
170:
171:
172: /**
173: * Returns selected value.
174: * @return string
175: */
176: public function getSelectedItem()
177: {
178: $value = $this->getValue();
179: return ($this->useKeys && $value !== NULL) ? $this->allowed[$value] : $value;
180: }
181:
182:
183: /**
184: * Generates control's HTML element.
185: * @return Nette\Utils\Html
186: */
187: public function getControl()
188: {
189: $selected = $this->getValue();
190: $selected = is_array($selected) ? array_flip($selected) : array($selected => TRUE);
191: $control = parent::getControl();
192: $option = Nette\Utils\Html::el('option');
193:
194: if ($this->prompt !== FALSE) {
195: $control->add($this->prompt instanceof Nette\Utils\Html
196: ? $this->prompt->value('')
197: : (string) $option->value('')->setText($this->translate((string) $this->prompt))
198: );
199: }
200:
201: foreach ($this->items as $key => $value) {
202: if (!is_array($value)) {
203: $value = array($key => $value);
204: $dest = $control;
205: } else {
206: $dest = $control->create('optgroup')->label($this->translate($key));
207: }
208:
209: foreach ($value as $key2 => $value2) {
210: if ($value2 instanceof Nette\Utils\Html) {
211: $dest->add((string) $value2->value($key2)
212: ->selected(isset($selected[$key2])));
213:
214: } else {
215: $key2 = $this->useKeys ? $key2 : $value2;
216: $dest->add((string) $option->value($key2)
217: ->selected(isset($selected[$key2]))
218: ->setText($this->translate((string) $value2)));
219: }
220: }
221: }
222: return $control;
223: }
224:
225: }
226: