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