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