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