PluginProbe
Packeta / 2.1
Packeta v2.1
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / forms / src / Forms / Controls / BaseControl.php

BaseControl.php in Packeta 2.1, at deps/nette/forms/src/Forms/Controls/BaseControl.php

476 lines 13.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace Packetery\Nette\Forms\Controls;
9
10 use Packetery\Nette;
11 use Packetery\Nette\Forms\Control;
12 use Packetery\Nette\Forms\Form;
13 use Packetery\Nette\Forms\Rules;
14 use Packetery\Nette\Utils\Html;
15 /**
16 * Base class that implements the basic functionality common to form controls.
17 *
18 * @property-read Form $form
19 * @property-read string $htmlName
20 * @property mixed $htmlId
21 * @property mixed $value
22 * @property string|object $caption
23 * @property bool $disabled
24 * @property bool $omitted
25 * @property-read Html $control
26 * @property-read Html $label
27 * @property-read Html $controlPrototype
28 * @property-read Html $labelPrototype
29 * @property bool $required
30 * @property-read bool $filled
31 * @property-read array $errors
32 * @property-read array $options
33 * @property-read string $error
34 */
35 abstract class BaseControl extends \Packetery\Nette\ComponentModel\Component implements Control
36 {
37 /** @var string */
38 public static $idMask = 'frm-%s';
39 /** @var mixed current control value */
40 protected $value;
41 /** @var Html control element template */
42 protected $control;
43 /** @var Html label element template */
44 protected $label;
45 /** @var bool|bool[] */
46 protected $disabled = \false;
47 /** @var callable[][] extension methods */
48 private static $extMethods = [];
49 /** @var string|object textual caption or label */
50 private $caption;
51 /** @var array */
52 private $errors = [];
53 /** @var bool|null */
54 private $omitted;
55 /** @var Rules */
56 private $rules;
57 /** @var \Packetery\Nette\Localization\Translator|bool|null */
58 private $translator = \true;
59 // means autodetect
60 /** @var array user options */
61 private $options = [];
62 /**
63 * @param string|object $caption
64 */
65 public function __construct($caption = null)
66 {
67 $this->control = Html::el('input', ['type' => null, 'name' => null]);
68 $this->label = Html::el('label');
69 $this->caption = $caption;
70 $this->rules = new Rules($this);
71 $this->setValue(null);
72 $this->monitor(Form::class, function (Form $form) : void {
73 if (!$this->isDisabled() && $form->isAnchored() && $form->isSubmitted()) {
74 $this->loadHttpData();
75 }
76 });
77 }
78 /**
79 * Sets textual caption or label.
80 * @param object|string $caption
81 * @return static
82 */
83 public function setCaption($caption)
84 {
85 $this->caption = $caption;
86 return $this;
87 }
88 /** @return object|string */
89 public function getCaption()
90 {
91 return $this->caption;
92 }
93 /**
94 * Returns form.
95 */
96 public function getForm(bool $throw = \true) : ?Form
97 {
98 return $this->lookup(Form::class, $throw);
99 }
100 /**
101 * Loads HTTP data.
102 */
103 public function loadHttpData() : void
104 {
105 $this->setValue($this->getHttpData(Form::DATA_TEXT));
106 }
107 /**
108 * Loads HTTP data.
109 * @return mixed
110 */
111 protected function getHttpData($type, string $htmlTail = null)
112 {
113 return $this->getForm()->getHttpData($type, $this->getHtmlName() . $htmlTail);
114 }
115 /**
116 * Returns HTML name of control.
117 */
118 public function getHtmlName() : string
119 {
120 return $this->control->name ?? \Packetery\Nette\Forms\Helpers::generateHtmlName($this->lookupPath(Form::class));
121 }
122 /********************* interface Control ****************d*g**/
123 /**
124 * Sets control's value.
125 * @return static
126 * @internal
127 */
128 public function setValue($value)
129 {
130 $this->value = $value;
131 return $this;
132 }
133 /**
134 * Returns control's value.
135 * @return mixed
136 */
137 public function getValue()
138 {
139 return $this->value;
140 }
141 /**
142 * Is control filled?
143 */
144 public function isFilled() : bool
145 {
146 $value = $this->getValue();
147 return $value !== null && $value !== [] && $value !== '';
148 }
149 /**
150 * Sets control's default value.
151 * @return static
152 */
153 public function setDefaultValue($value)
154 {
155 $form = $this->getForm(\false);
156 if ($this->isDisabled() || !$form || !$form->isAnchored() || !$form->isSubmitted()) {
157 $this->setValue($value);
158 }
159 return $this;
160 }
161 /**
162 * Disables or enables control.
163 * @param bool $value
164 * @return static
165 */
166 public function setDisabled($value = \true)
167 {
168 if ($this->disabled = (bool) $value) {
169 $this->setValue(null);
170 } elseif (($form = $this->getForm(\false)) && $form->isAnchored() && $form->isSubmitted()) {
171 $this->loadHttpData();
172 }
173 return $this;
174 }
175 /**
176 * Is control disabled?
177 */
178 public function isDisabled() : bool
179 {
180 return $this->disabled === \true;
181 }
182 /**
183 * Sets whether control value is excluded from $form->getValues() result.
184 * @return static
185 */
186 public function setOmitted(bool $value = \true)
187 {
188 $this->omitted = $value;
189 return $this;
190 }
191 /**
192 * Is control value excluded from $form->getValues() result?
193 */
194 public function isOmitted() : bool
195 {
196 return $this->omitted || $this->isDisabled() && $this->omitted === null;
197 }
198 /********************* rendering ****************d*g**/
199 /**
200 * Generates control's HTML element.
201 * @return Html|string
202 */
203 public function getControl()
204 {
205 $this->setOption('rendered', \true);
206 $el = clone $this->control;
207 return $el->addAttributes(['name' => $this->getHtmlName(), 'id' => $this->getHtmlId(), 'required' => $this->isRequired(), 'disabled' => $this->isDisabled(), 'data-nette-rules' => \Packetery\Nette\Forms\Helpers::exportRules($this->rules) ?: null]);
208 }
209 /**
210 * Generates label's HTML element.
211 * @param string|object $caption
212 * @return Html|string|null
213 */
214 public function getLabel($caption = null)
215 {
216 $label = clone $this->label;
217 $label->for = $this->getHtmlId();
218 $caption = $caption ?? $this->caption;
219 $translator = $this->getForm()->getTranslator();
220 $label->setText($translator && !$caption instanceof \Packetery\Nette\HtmlStringable ? $translator->translate($caption) : $caption);
221 return $label;
222 }
223 public function getControlPart() : ?Html
224 {
225 return $this->getControl();
226 }
227 public function getLabelPart() : ?Html
228 {
229 return $this->getLabel();
230 }
231 /**
232 * Returns control's HTML element template.
233 */
234 public function getControlPrototype() : Html
235 {
236 return $this->control;
237 }
238 /**
239 * Returns label's HTML element template.
240 */
241 public function getLabelPrototype() : Html
242 {
243 return $this->label;
244 }
245 /**
246 * Changes control's HTML id.
247 * @param string|bool|null $id
248 * @return static
249 */
250 public function setHtmlId($id)
251 {
252 $this->control->id = $id;
253 return $this;
254 }
255 /**
256 * Returns control's HTML id.
257 * @return mixed
258 */
259 public function getHtmlId()
260 {
261 if (!isset($this->control->id)) {
262 $form = $this->getForm();
263 $prefix = $form instanceof \Packetery\Nette\Application\UI\Form || $form->getName() === null ? '' : $form->getName() . '-';
264 $this->control->id = \sprintf(self::$idMask, $prefix . $this->lookupPath());
265 }
266 return $this->control->id;
267 }
268 /**
269 * Changes control's HTML attribute.
270 * @return static
271 */
272 public function setHtmlAttribute(string $name, $value = \true)
273 {
274 $this->control->{$name} = $value;
275 if ($name === 'name' && ($form = $this->getForm(\false)) && !$this->isDisabled() && $form->isAnchored() && $form->isSubmitted()) {
276 $this->loadHttpData();
277 }
278 return $this;
279 }
280 /**
281 * @deprecated use setHtmlAttribute()
282 * @return static
283 */
284 public function setAttribute(string $name, $value = \true)
285 {
286 return $this->setHtmlAttribute($name, $value);
287 }
288 /********************* translator ****************d*g**/
289 /**
290 * Sets translate adapter.
291 * @return static
292 */
293 public function setTranslator(?Nette\Localization\Translator $translator)
294 {
295 $this->translator = $translator;
296 return $this;
297 }
298 /**
299 * Returns translate adapter.
300 */
301 public function getTranslator() : ?Nette\Localization\Translator
302 {
303 if ($this->translator === \true) {
304 return $this->getForm(\false) ? $this->getForm()->getTranslator() : null;
305 }
306 return $this->translator;
307 }
308 /**
309 * Returns translated string.
310 * @return mixed
311 */
312 public function translate($value, ...$parameters)
313 {
314 if ($translator = $this->getTranslator()) {
315 $tmp = \is_array($value) ? [&$value] : [[&$value]];
316 foreach ($tmp[0] as &$v) {
317 if ($v != null && !$v instanceof \Packetery\Nette\HtmlStringable) {
318 // intentionally ==
319 $v = $translator->translate($v, ...$parameters);
320 }
321 }
322 }
323 return $value;
324 }
325 /********************* rules ****************d*g**/
326 /**
327 * Adds a validation rule.
328 * @param callable|string $validator
329 * @param string|object $errorMessage
330 * @return static
331 */
332 public function addRule($validator, $errorMessage = null, $arg = null)
333 {
334 $this->rules->addRule($validator, $errorMessage, $arg);
335 return $this;
336 }
337 /**
338 * Adds a validation condition a returns new branch.
339 */
340 public function addCondition($validator, $value = null) : Rules
341 {
342 return $this->rules->addCondition($validator, $value);
343 }
344 /**
345 * Adds a validation condition based on another control a returns new branch.
346 */
347 public function addConditionOn(Control $control, $validator, $value = null) : Rules
348 {
349 return $this->rules->addConditionOn($control, $validator, $value);
350 }
351 /**
352 * Adds a input filter callback.
353 * @return static
354 */
355 public function addFilter(callable $filter)
356 {
357 $this->getRules()->addFilter($filter);
358 return $this;
359 }
360 public function getRules() : Rules
361 {
362 return $this->rules;
363 }
364 /**
365 * Makes control mandatory.
366 * @param bool|string|object $value
367 * @return static
368 */
369 public function setRequired($value = \true)
370 {
371 $this->rules->setRequired($value);
372 return $this;
373 }
374 /**
375 * Is control mandatory?
376 */
377 public function isRequired() : bool
378 {
379 return $this->rules->isRequired();
380 }
381 /**
382 * Performs the server side validation.
383 */
384 public function validate() : void
385 {
386 if ($this->isDisabled()) {
387 return;
388 }
389 $this->cleanErrors();
390 $this->rules->validate();
391 }
392 /**
393 * Adds error message to the list.
394 * @param string|object $message
395 */
396 public function addError($message, bool $translate = \true) : void
397 {
398 $this->errors[] = $translate ? $this->translate($message) : $message;
399 }
400 /**
401 * Returns errors corresponding to control.
402 */
403 public function getError() : ?string
404 {
405 return $this->errors ? \implode(' ', \array_unique($this->errors)) : null;
406 }
407 /**
408 * Returns errors corresponding to control.
409 */
410 public function getErrors() : array
411 {
412 return \array_unique($this->errors);
413 }
414 public function hasErrors() : bool
415 {
416 return (bool) $this->errors;
417 }
418 public function cleanErrors() : void
419 {
420 $this->errors = [];
421 }
422 /********************* user data ****************d*g**/
423 /**
424 * Sets user-specific option.
425 * @return static
426 */
427 public function setOption($key, $value)
428 {
429 if ($value === null) {
430 unset($this->options[$key]);
431 } else {
432 $this->options[$key] = $value;
433 }
434 return $this;
435 }
436 /**
437 * Returns user-specific option.
438 * @return mixed
439 */
440 public function getOption($key, $default = null)
441 {
442 return $this->options[$key] ?? $default;
443 }
444 /**
445 * Returns user-specific options.
446 */
447 public function getOptions() : array
448 {
449 return $this->options;
450 }
451 /********************* extension methods ****************d*g**/
452 public function __call(string $name, array $args)
453 {
454 $class = static::class;
455 do {
456 if (isset(self::$extMethods[$name][$class])) {
457 return self::$extMethods[$name][$class]($this, ...$args);
458 }
459 $class = \get_parent_class($class);
460 } while ($class);
461 return parent::__call($name, $args);
462 }
463 public static function extensionMethod(
464 string $name,
465 /*callable*/
466 $callback
467 ) : void
468 {
469 if (\strpos($name, '::') !== \false) {
470 // back compatibility
471 [, $name] = \explode('::', $name);
472 }
473 self::$extMethods[$name][static::class] = $callback;
474 }
475 }
476