|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* TBaseValidator class file |
|
4
|
|
|
* |
|
5
|
|
|
* @author Qiang Xue <[email protected]> |
|
6
|
|
|
* @link https://github.com/pradosoft/prado |
|
7
|
|
|
* @copyright Copyright © 2005-2016 The PRADO Group |
|
8
|
|
|
* @license https://github.com/pradosoft/prado/blob/master/LICENSE |
|
9
|
|
|
* @package Prado\Web\UI\WebControls |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace Prado\Web\UI\WebControls; |
|
13
|
|
|
|
|
14
|
|
|
use Prado\Exceptions\TConfigurationException; |
|
15
|
|
|
use Prado\Exceptions\TNotSupportedException; |
|
16
|
|
|
use Prado\TPropertyValue; |
|
17
|
|
|
use Prado\Exceptions\TInvalidDataTypeException; |
|
18
|
|
|
use Prado\Web\Javascripts\TJavaScript; |
|
19
|
|
|
use Prado\Web\UI\IValidator; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* TBaseValidator class |
|
23
|
|
|
* |
|
24
|
|
|
* TBaseValidator serves as the base class for validator controls. |
|
25
|
|
|
* |
|
26
|
|
|
* Validation is performed when a postback control, such as a TButton, a TLinkButton |
|
27
|
|
|
* or a TTextBox (under AutoPostBack mode) is submitting the page and |
|
28
|
|
|
* its <b>CausesValidation</b> property is true. |
|
29
|
|
|
* You can also manually perform validation by calling {@link TPage::validate()}. |
|
30
|
|
|
* The input control to be validated is specified by {@link setControlToValidate ControlToValidate}. |
|
31
|
|
|
* |
|
32
|
|
|
* Validator controls always validate the associated input control on the serve side. |
|
33
|
|
|
* In addition, if {@link getEnableClientScript EnableClientScript} is true, |
|
34
|
|
|
* validation will also be performed on the client-side using javascript. |
|
35
|
|
|
* Client-side validation will validate user input before it is sent to the server. |
|
36
|
|
|
* The form data will not be submitted if any error is detected. This avoids |
|
37
|
|
|
* the round-trip of information necessary for server-side validation. |
|
38
|
|
|
* |
|
39
|
|
|
* You can use multiple validator controls to validate a single input control, |
|
40
|
|
|
* each responsible for validating against a different criteria. |
|
41
|
|
|
* For example, on a user registration form, you may want to make sure the user |
|
42
|
|
|
* enters a value in the username text box, and the input must consist of only word |
|
43
|
|
|
* characters. You can use a {@link TRequiredFieldValidator} to ensure the input |
|
44
|
|
|
* of username and a {@link TRegularExpressionValidator} to ensure the proper input. |
|
45
|
|
|
* |
|
46
|
|
|
* If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage} |
|
47
|
|
|
* property is displayed in the validation control. However, if the {@link setText Text} |
|
48
|
|
|
* property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage} |
|
49
|
|
|
* and {@link setText Text} are empty, the body content of the validator will |
|
50
|
|
|
* be displayed. Error display is controlled by {@link setDisplay Display} property. |
|
51
|
|
|
* |
|
52
|
|
|
* You can also customized the client-side behaviour by adding javascript |
|
53
|
|
|
* code to the subproperties of the {@link getClientSide ClientSide} |
|
54
|
|
|
* property. See quickstart documentation for further details. |
|
55
|
|
|
* |
|
56
|
|
|
* You can also place a {@link TValidationSummary} control on a page to display error messages |
|
57
|
|
|
* from the validators together. In this case, only the {@link setErrorMessage ErrorMessage} |
|
58
|
|
|
* property of the validators will be displayed in the {@link TValidationSummary} control. |
|
59
|
|
|
* |
|
60
|
|
|
* Validators can be partitioned into validation groups by setting their |
|
61
|
|
|
* {@link setValidationGroup ValidationGroup} property. If the control causing the |
|
62
|
|
|
* validation also sets its ValidationGroup property, only those validators having |
|
63
|
|
|
* the same ValidationGroup value will do input validation. |
|
64
|
|
|
* |
|
65
|
|
|
* Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage} |
|
66
|
|
|
* instance will be automatically updated by the validation process which occurs |
|
67
|
|
|
* after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events. |
|
68
|
|
|
* Therefore, if you use the {@link TPage::getIsValid()} property in |
|
69
|
|
|
* the {@link TPage::onLoad()} method, you must first explicitly call |
|
70
|
|
|
* the {@link TPage::validate()} method. |
|
71
|
|
|
* |
|
72
|
|
|
* <b>Notes to Inheritors</b> When you inherit from TBaseValidator, you must |
|
73
|
|
|
* override the method {@link evaluateIsValid}. |
|
74
|
|
|
* |
|
75
|
|
|
* @author Qiang Xue <[email protected]> |
|
76
|
|
|
* @package Prado\Web\UI\WebControls |
|
77
|
|
|
* @since 3.0 |
|
78
|
|
|
*/ |
|
79
|
|
|
abstract class TBaseValidator extends TLabel implements IValidator |
|
80
|
|
|
{ |
|
81
|
|
|
/** |
|
82
|
|
|
* @var bool whether the validation succeeds |
|
83
|
|
|
*/ |
|
84
|
|
|
private $_isValid = true; |
|
85
|
|
|
/** |
|
86
|
|
|
* @var bool whether the validator has been registered with the page |
|
87
|
|
|
*/ |
|
88
|
|
|
private $_registered = false; |
|
89
|
|
|
/** |
|
90
|
|
|
* @var TValidatorClientSide validator client-script options. |
|
91
|
|
|
*/ |
|
92
|
|
|
private $_clientSide; |
|
93
|
|
|
/** |
|
94
|
|
|
* Controls for which the client-side validation3.js file needs to handle |
|
95
|
|
|
* them specially. |
|
96
|
|
|
* @var array list of control class names |
|
97
|
|
|
*/ |
|
98
|
|
|
private static $_clientClass = ['THtmlArea', 'THtmlArea4', 'TDatePicker', 'TListBox', 'TCheckBoxList']; |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* Constructor. |
|
102
|
|
|
* This method sets the foreground color to red. |
|
103
|
|
|
*/ |
|
104
|
|
|
public function __construct() |
|
105
|
|
|
{ |
|
106
|
|
|
parent::__construct(); |
|
107
|
|
|
$this->setForeColor('red'); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/** |
|
111
|
|
|
* Registers the validator with page. |
|
112
|
|
|
* @param mixed $param event parameter |
|
113
|
|
|
*/ |
|
114
|
|
|
public function onInit($param) |
|
115
|
|
|
{ |
|
116
|
|
|
parent::onInit($param); |
|
117
|
|
|
$this->getPage()->getValidators()->add($this); |
|
118
|
|
|
$this->_registered = true; |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
/** |
|
122
|
|
|
* Unregisters the validator from page. |
|
123
|
|
|
* @param mixed $param event parameter |
|
124
|
|
|
*/ |
|
125
|
|
|
public function onUnload($param) |
|
126
|
|
|
{ |
|
127
|
|
|
if ($this->_registered && ($page = $this->getPage()) !== null) { |
|
128
|
|
|
$page->getValidators()->remove($this); |
|
129
|
|
|
} |
|
130
|
|
|
$this->_registered = false; |
|
131
|
|
|
parent::onUnload($param); |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
/** |
|
135
|
|
|
* Adds attributes to renderer. Calls parent implementation and renders the |
|
136
|
|
|
* client control scripts. |
|
137
|
|
|
* @param THtmlWriter $writer the renderer |
|
138
|
|
|
*/ |
|
139
|
|
|
protected function addAttributesToRender($writer) |
|
140
|
|
|
{ |
|
141
|
|
|
$display = $this->getDisplay(); |
|
142
|
|
|
$visible = $this->getEnabled(true) && !$this->getIsValid(); |
|
143
|
|
View Code Duplication |
if ($display === TValidatorDisplayStyle::None || (!$visible && $display === TValidatorDisplayStyle::Dynamic)) { |
|
|
|
|
|
|
144
|
|
|
$writer->addStyleAttribute('display', 'none'); |
|
145
|
|
|
} elseif (!$visible) { |
|
146
|
|
|
$writer->addStyleAttribute('visibility', 'hidden'); |
|
147
|
|
|
} |
|
148
|
|
|
$writer->addAttribute('id', $this->getClientID()); |
|
149
|
|
|
parent::addAttributesToRender($writer); |
|
150
|
|
|
$this->renderClientControlScript($writer); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
/** |
|
154
|
|
|
* Returns an array of javascript validator options. |
|
155
|
|
|
* @return array javascript validator options. |
|
156
|
|
|
*/ |
|
157
|
|
|
protected function getClientScriptOptions() |
|
158
|
|
|
{ |
|
159
|
|
|
$control = $this->getValidationTarget(); |
|
160
|
|
|
$options['ID'] = $this->getClientID(); |
|
|
|
|
|
|
161
|
|
|
$options['FormID'] = $this->getPage()->getForm()->getClientID(); |
|
162
|
|
|
$options['Display'] = $this->getDisplay(); |
|
163
|
|
|
$options['ErrorMessage'] = $this->getErrorMessage(); |
|
164
|
|
|
if ($this->getFocusOnError()) { |
|
165
|
|
|
$options['FocusOnError'] = $this->getFocusOnError(); |
|
166
|
|
|
$options['FocusElementID'] = $this->getFocusElementID(); |
|
167
|
|
|
} |
|
168
|
|
|
$options['ValidationGroup'] = $this->getValidationGroup(); |
|
169
|
|
|
if ($control) { |
|
170
|
|
|
$options['ControlToValidate'] = $control->getClientID(); |
|
171
|
|
|
} |
|
172
|
|
|
$options['ControlCssClass'] = $this->getControlCssClass(); |
|
173
|
|
|
|
|
174
|
|
|
$options['ControlType'] = $this->getClientControlClass($control); |
|
175
|
|
|
$options['Enabled'] = $this->getEnabled(true); |
|
176
|
|
|
|
|
177
|
|
|
//get date format from date picker target control |
|
178
|
|
|
if ($control instanceof TDatePicker) { |
|
179
|
|
|
$options['DateFormat'] = $control->getDateFormat(); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
$options = array_merge($options, $this->getClientSide()->getOptions()->toArray()); |
|
183
|
|
|
|
|
184
|
|
|
return $options; |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
|
|
/** |
|
188
|
|
|
* Gets the Control type for client-side validation. If new cases exists in |
|
189
|
|
|
* TBaseValidator::$_clientClass, be sure to update the corresponding |
|
190
|
|
|
* "Javascript/validation3.js" file as well. |
|
191
|
|
|
* @param TControl $control control to validate. |
|
192
|
|
|
* @return string control type for client-side validation. |
|
193
|
|
|
*/ |
|
194
|
|
|
private function getClientControlClass($control) |
|
195
|
|
|
{ |
|
196
|
|
|
foreach (self::$_clientClass as $type) { |
|
197
|
|
|
if ($control instanceof $type) { |
|
198
|
|
|
return $type; |
|
199
|
|
|
} |
|
200
|
|
|
} |
|
201
|
|
|
$reflectionClass = new \ReflectionClass($control); |
|
202
|
|
|
return $reflectionClass->getShortName(); |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* Gets the TValidatorClientSide that allows modification of the client- |
|
207
|
|
|
* side validator events. |
|
208
|
|
|
* |
|
209
|
|
|
* The client-side validator supports the following events. |
|
210
|
|
|
* # <tt>OnValidate</tt> -- raised before client-side validation is |
|
211
|
|
|
* executed. |
|
212
|
|
|
* # <tt>OnValidationSuccess</tt> -- raised after client-side validation is completed |
|
213
|
|
|
* and is successfull, overrides default validator error messages updates. |
|
214
|
|
|
* # <tt>OnValidationError</tt> -- raised after client-side validation is completed |
|
215
|
|
|
* and failed, overrides default validator error message updates. |
|
216
|
|
|
* |
|
217
|
|
|
* You can attach custom javascript code to each of these events |
|
218
|
|
|
* |
|
219
|
|
|
* @return TValidatorClientSide javascript validator event options. |
|
220
|
|
|
*/ |
|
221
|
|
|
public function getClientSide() |
|
222
|
|
|
{ |
|
223
|
|
|
if ($this->_clientSide === null) { |
|
224
|
|
|
$this->_clientSide = $this->createClientSide(); |
|
225
|
|
|
} |
|
226
|
|
|
return $this->_clientSide; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* @return TValidatorClientSide javascript validator event options. |
|
231
|
|
|
*/ |
|
232
|
|
|
protected function createClientSide() |
|
233
|
|
|
{ |
|
234
|
|
|
return new TValidatorClientSide; |
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
|
/** |
|
238
|
|
|
* Renders the javascript code to the end script. |
|
239
|
|
|
* If you override this method, be sure to call the parent implementation |
|
240
|
|
|
* so that the event handlers can be invoked. |
|
241
|
|
|
* @param THtmlWriter $writer the renderer |
|
242
|
|
|
*/ |
|
243
|
|
|
public function renderClientControlScript($writer) |
|
244
|
|
|
{ |
|
245
|
|
|
$scripts = $this->getPage()->getClientScript(); |
|
246
|
|
|
if ($this->getEnableClientScript()) { |
|
247
|
|
|
$scripts->registerPradoScript('validator'); |
|
248
|
|
|
} |
|
249
|
|
|
$formID = $this->getPage()->getForm()->getClientID(); |
|
250
|
|
|
$scriptKey = "TBaseValidator:$formID"; |
|
251
|
|
View Code Duplication |
if ($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey)) { |
|
|
|
|
|
|
252
|
|
|
$manager['FormID'] = $formID; |
|
|
|
|
|
|
253
|
|
|
$options = TJavaScript::encode($manager); |
|
254
|
|
|
$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});"); |
|
255
|
|
|
} |
|
256
|
|
|
if ($this->getEnableClientScript()) { |
|
257
|
|
|
$this->registerClientScriptValidator(); |
|
258
|
|
|
} |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
/** |
|
262
|
|
|
* Override parent implementation to update the control CSS Class before |
|
263
|
|
|
* the validated control is rendered |
|
264
|
|
|
* @param mixed $param |
|
265
|
|
|
*/ |
|
266
|
|
|
public function onPreRender($param) |
|
267
|
|
|
{ |
|
268
|
|
|
parent::onPreRender($param); |
|
269
|
|
|
$this->updateControlCssClass(); |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
/** |
|
273
|
|
|
* Update the ControlToValidate component's css class depending |
|
274
|
|
|
* if the ControlCssClass property is set, and whether this is valid. |
|
275
|
|
|
* @return bool true if change, false otherwise. |
|
276
|
|
|
*/ |
|
277
|
|
|
protected function updateControlCssClass() |
|
278
|
|
|
{ |
|
279
|
|
|
if (($cssClass = $this->getControlCssClass()) !== '') { |
|
280
|
|
|
$control = $this->getValidationTarget(); |
|
281
|
|
|
if ($control instanceof TWebControl) { |
|
282
|
|
|
$class = preg_replace('/ ' . preg_quote($cssClass) . '/', '', $control->getCssClass()); |
|
283
|
|
|
if (!$this->getIsValid()) { |
|
284
|
|
|
$class .= ' ' . $cssClass; |
|
285
|
|
|
$control->setCssClass($class); |
|
286
|
|
|
} elseif ($control->getIsValid()) { |
|
287
|
|
|
$control->setCssClass($class); |
|
288
|
|
|
} |
|
289
|
|
|
} |
|
290
|
|
|
} |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
/** |
|
294
|
|
|
* Registers the individual validator client-side javascript code. |
|
295
|
|
|
*/ |
|
296
|
|
|
protected function registerClientScriptValidator() |
|
297
|
|
|
{ |
|
298
|
|
|
$key = 'prado:' . $this->getClientID(); |
|
299
|
|
|
if (!$this->getPage()->getClientScript()->isEndScriptRegistered($key)) { |
|
300
|
|
|
$options = TJavaScript::encode($this->getClientScriptOptions()); |
|
301
|
|
|
$script = 'new ' . $this->getClientClassName() . '(' . $options . ');'; |
|
302
|
|
|
$this->getPage()->getClientScript()->registerEndScript($key, $script); |
|
303
|
|
|
} |
|
304
|
|
|
} |
|
305
|
|
|
|
|
306
|
|
|
/** |
|
307
|
|
|
* Gets the name of the javascript class responsible for performing validation for this control. |
|
308
|
|
|
* This method overrides the parent implementation. |
|
309
|
|
|
* @return string the javascript class name |
|
310
|
|
|
*/ |
|
311
|
|
|
abstract protected function getClientClassName(); |
|
312
|
|
|
|
|
313
|
|
|
/** |
|
314
|
|
|
* This method overrides the parent implementation to forbid setting ForControl. |
|
315
|
|
|
* @param string $value the associated control ID |
|
316
|
|
|
* @throws TNotSupportedException whenever this method is called |
|
317
|
|
|
*/ |
|
318
|
|
|
public function setForControl($value) |
|
319
|
|
|
{ |
|
320
|
|
|
throw new TNotSupportedException('basevalidator_forcontrol_unsupported', get_class($this)); |
|
321
|
|
|
} |
|
322
|
|
|
|
|
323
|
|
|
/** |
|
324
|
|
|
* This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled. |
|
325
|
|
|
* @param bool $value whether the validator is enabled. |
|
326
|
|
|
*/ |
|
327
|
|
|
public function setEnabled($value) |
|
328
|
|
|
{ |
|
329
|
|
|
$value = TPropertyValue::ensureBoolean($value); |
|
330
|
|
|
parent::setEnabled($value); |
|
331
|
|
|
if (!$value) { |
|
332
|
|
|
$this->_isValid = true; |
|
333
|
|
|
} |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed. |
|
338
|
|
|
*/ |
|
339
|
|
|
public function getDisplay() |
|
340
|
|
|
{ |
|
341
|
|
|
return $this->getViewState('Display', TValidatorDisplayStyle::Fixed); |
|
342
|
|
|
} |
|
343
|
|
|
|
|
344
|
|
|
/** |
|
345
|
|
|
* @param TValidatorDisplayStyle $value the style of displaying the error message |
|
346
|
|
|
*/ |
|
347
|
|
|
public function setDisplay($value) |
|
348
|
|
|
{ |
|
349
|
|
|
$this->setViewState('Display', TPropertyValue::ensureEnum($value, 'Prado\\Web\\UI\\WebControls\\TValidatorDisplayStyle'), TValidatorDisplayStyle::Fixed); |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/** |
|
353
|
|
|
* @return bool whether client-side validation is enabled. |
|
354
|
|
|
*/ |
|
355
|
|
|
public function getEnableClientScript() |
|
356
|
|
|
{ |
|
357
|
|
|
return $this->getViewState('EnableClientScript', true); |
|
358
|
|
|
} |
|
359
|
|
|
|
|
360
|
|
|
/** |
|
361
|
|
|
* @param bool $value whether client-side validation is enabled. |
|
362
|
|
|
*/ |
|
363
|
|
|
public function setEnableClientScript($value) |
|
364
|
|
|
{ |
|
365
|
|
|
$this->setViewState('EnableClientScript', TPropertyValue::ensureBoolean($value), true); |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
/** |
|
369
|
|
|
* @return string the text for the error message. |
|
370
|
|
|
*/ |
|
371
|
|
|
public function getErrorMessage() |
|
372
|
|
|
{ |
|
373
|
|
|
return $this->getViewState('ErrorMessage', ''); |
|
374
|
|
|
} |
|
375
|
|
|
|
|
376
|
|
|
/** |
|
377
|
|
|
* Sets the text for the error message. |
|
378
|
|
|
* @param string $value the error message |
|
379
|
|
|
*/ |
|
380
|
|
|
public function setErrorMessage($value) |
|
381
|
|
|
{ |
|
382
|
|
|
$this->setViewState('ErrorMessage', $value, ''); |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
|
|
/** |
|
386
|
|
|
* @return string the ID path of the input control to validate |
|
387
|
|
|
*/ |
|
388
|
|
|
public function getControlToValidate() |
|
389
|
|
|
{ |
|
390
|
|
|
return $this->getViewState('ControlToValidate', ''); |
|
391
|
|
|
} |
|
392
|
|
|
|
|
393
|
|
|
/** |
|
394
|
|
|
* Sets the ID path of the input control to validate. |
|
395
|
|
|
* The ID path is the dot-connected IDs of the controls reaching from |
|
396
|
|
|
* the validator's naming container to the target control. |
|
397
|
|
|
* @param string $value the ID path |
|
398
|
|
|
*/ |
|
399
|
|
|
public function setControlToValidate($value) |
|
400
|
|
|
{ |
|
401
|
|
|
$this->setViewState('ControlToValidate', $value, ''); |
|
402
|
|
|
} |
|
403
|
|
|
|
|
404
|
|
|
/** |
|
405
|
|
|
* @return bool whether to set focus at the validating place if the validation fails. Defaults to false. |
|
406
|
|
|
*/ |
|
407
|
|
|
public function getFocusOnError() |
|
408
|
|
|
{ |
|
409
|
|
|
return $this->getViewState('FocusOnError', false); |
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
/** |
|
413
|
|
|
* @param bool $value whether to set focus at the validating place if the validation fails |
|
414
|
|
|
*/ |
|
415
|
|
|
public function setFocusOnError($value) |
|
416
|
|
|
{ |
|
417
|
|
|
$this->setViewState('FocusOnError', TPropertyValue::ensureBoolean($value), false); |
|
418
|
|
|
} |
|
419
|
|
|
|
|
420
|
|
|
/** |
|
421
|
|
|
* Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. |
|
422
|
|
|
* Defaults to the client ID of the {@link getControlToValidate ControlToValidate}. |
|
423
|
|
|
* @return string the ID of the HTML element to receive focus |
|
424
|
|
|
*/ |
|
425
|
|
|
public function getFocusElementID() |
|
426
|
|
|
{ |
|
427
|
|
|
if (($id = $this->getViewState('FocusElementID', '')) === '') { |
|
428
|
|
|
$target = $this->getValidationTarget(); |
|
429
|
|
|
/* Workaround: TCheckBoxList and TRadioButtonList nests the actual |
|
430
|
|
|
* inputs inside a table; we ensure the first input gets focused |
|
431
|
|
|
*/ |
|
432
|
|
|
if ($target instanceof TCheckBoxList && $target->getItemCount() > 0) { |
|
433
|
|
|
$id = $target->getClientID() . '_c0'; |
|
434
|
|
|
} else { |
|
435
|
|
|
$id = $target->getClientID(); |
|
436
|
|
|
} |
|
437
|
|
|
} |
|
438
|
|
|
return $id; |
|
439
|
|
|
} |
|
440
|
|
|
|
|
441
|
|
|
/** |
|
442
|
|
|
* Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. |
|
443
|
|
|
* @param string $value the ID of the HTML element to receive focus |
|
444
|
|
|
*/ |
|
445
|
|
|
public function setFocusElementID($value) |
|
446
|
|
|
{ |
|
447
|
|
|
$this->setViewState('FocusElementID', $value, ''); |
|
448
|
|
|
} |
|
449
|
|
|
|
|
450
|
|
|
/** |
|
451
|
|
|
* @return string the group which this validator belongs to |
|
452
|
|
|
*/ |
|
453
|
|
|
public function getValidationGroup() |
|
454
|
|
|
{ |
|
455
|
|
|
return $this->getViewState('ValidationGroup', ''); |
|
456
|
|
|
} |
|
457
|
|
|
|
|
458
|
|
|
/** |
|
459
|
|
|
* @param string $value the group which this validator belongs to |
|
460
|
|
|
*/ |
|
461
|
|
|
public function setValidationGroup($value) |
|
462
|
|
|
{ |
|
463
|
|
|
$this->setViewState('ValidationGroup', $value, ''); |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
/** |
|
467
|
|
|
* @return bool whether the validation succeeds |
|
468
|
|
|
*/ |
|
469
|
|
|
public function getIsValid() |
|
470
|
|
|
{ |
|
471
|
|
|
return $this->_isValid; |
|
472
|
|
|
} |
|
473
|
|
|
|
|
474
|
|
|
/** |
|
475
|
|
|
* Sets the value indicating whether the validation succeeds |
|
476
|
|
|
* @param bool $value whether the validation succeeds |
|
477
|
|
|
*/ |
|
478
|
|
|
public function setIsValid($value) |
|
479
|
|
|
{ |
|
480
|
|
|
$this->_isValid = TPropertyValue::ensureBoolean($value); |
|
481
|
|
|
} |
|
482
|
|
|
|
|
483
|
|
|
/** |
|
484
|
|
|
* @throws TConfigurationException if {@link getControlToValidate |
|
485
|
|
|
* ControlToValidate} is empty or does not point to a valid control |
|
486
|
|
|
* @return TControl control to be validated. Null if no control is found. |
|
487
|
|
|
*/ |
|
488
|
|
|
public function getValidationTarget() |
|
489
|
|
|
{ |
|
490
|
|
|
if (($id = $this->getControlToValidate()) !== '' && ($control = $this->findControl($id)) !== null) { |
|
491
|
|
|
return $control; |
|
492
|
|
|
} else { |
|
493
|
|
|
throw new TConfigurationException('basevalidator_controltovalidate_invalid', get_class($this)); |
|
494
|
|
|
} |
|
495
|
|
|
} |
|
496
|
|
|
|
|
497
|
|
|
/** |
|
498
|
|
|
* Retrieves the property value of the control being validated. |
|
499
|
|
|
* @param TControl $control control being validated |
|
500
|
|
|
* @throws TInvalidDataTypeException if the control to be validated does not implement {@link \Prado\Web\UI\IValidatable}. |
|
501
|
|
|
* @return string property value to be validated |
|
502
|
|
|
*/ |
|
503
|
|
|
protected function getValidationValue($control) |
|
504
|
|
|
{ |
|
505
|
|
|
if ($control instanceof \Prado\Web\UI\IValidatable) { |
|
506
|
|
|
return $control->getValidationPropertyValue(); |
|
507
|
|
|
} else { |
|
508
|
|
|
throw new TInvalidDataTypeException('basevalidator_validatable_required', get_class($this)); |
|
509
|
|
|
} |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
/** |
|
513
|
|
|
* Validates the specified control. |
|
514
|
|
|
* Do not override this method. Override {@link evaluateIsValid} instead. |
|
515
|
|
|
* @return bool whether the validation succeeds |
|
516
|
|
|
*/ |
|
517
|
|
|
public function validate() |
|
518
|
|
|
{ |
|
519
|
|
|
$this->onValidate(); |
|
520
|
|
|
if ($this->getVisible(true) && $this->getEnabled(true)) { |
|
521
|
|
|
$target = $this->getValidationTarget(); |
|
522
|
|
|
// if the target is not a disabled web control |
|
523
|
|
|
if ($target === null || |
|
524
|
|
|
($target !== null && |
|
525
|
|
|
!($target instanceof TWebControl && !$target->getEnabled(true)))) { |
|
526
|
|
|
if ($this->evaluateIsValid()) { |
|
527
|
|
|
$this->setIsValid(true); |
|
528
|
|
|
$this->onValidationSuccess(); |
|
529
|
|
|
} else { |
|
530
|
|
|
if ($target) { |
|
531
|
|
|
$target->setIsValid(false); |
|
532
|
|
|
} |
|
533
|
|
|
$this->setIsValid(false); |
|
534
|
|
|
$this->onValidationError(); |
|
535
|
|
|
} |
|
536
|
|
|
} else { |
|
537
|
|
|
$this->evaluateIsValid(); |
|
538
|
|
|
$this->setIsValid(true); |
|
539
|
|
|
$this->onValidationSuccess(); |
|
540
|
|
|
} |
|
541
|
|
|
} else { |
|
542
|
|
|
$this->setIsValid(true); |
|
543
|
|
|
} |
|
544
|
|
|
return $this->getIsValid(); |
|
545
|
|
|
} |
|
546
|
|
|
|
|
547
|
|
|
/** |
|
548
|
|
|
* @return string the css class that is applied to the control being validated in case the validation fails |
|
549
|
|
|
*/ |
|
550
|
|
|
public function getControlCssClass() |
|
551
|
|
|
{ |
|
552
|
|
|
return $this->getViewState('ControlCssClass', ''); |
|
553
|
|
|
} |
|
554
|
|
|
|
|
555
|
|
|
/** |
|
556
|
|
|
* @param string $value the css class that is applied to the control being validated in case the validation fails |
|
557
|
|
|
*/ |
|
558
|
|
|
public function setControlCssClass($value) |
|
559
|
|
|
{ |
|
560
|
|
|
$this->setViewState('ControlCssClass', $value, ''); |
|
561
|
|
|
} |
|
562
|
|
|
|
|
563
|
|
|
/** |
|
564
|
|
|
* This is the major method for validation. |
|
565
|
|
|
* Derived classes should implement this method to provide customized validation. |
|
566
|
|
|
* @return bool whether the validation succeeds |
|
567
|
|
|
*/ |
|
568
|
|
|
abstract protected function evaluateIsValid(); |
|
569
|
|
|
|
|
570
|
|
|
/** |
|
571
|
|
|
* This event is raised when the validator succeeds in validation. |
|
572
|
|
|
*/ |
|
573
|
|
|
public function onValidationSuccess() |
|
574
|
|
|
{ |
|
575
|
|
|
$this->raiseEvent('OnValidationSuccess', $this, null); |
|
576
|
|
|
} |
|
577
|
|
|
|
|
578
|
|
|
/** |
|
579
|
|
|
* This event is raised when the validator fails in validation. |
|
580
|
|
|
*/ |
|
581
|
|
|
public function onValidationError() |
|
582
|
|
|
{ |
|
583
|
|
|
$this->raiseEvent('OnValidationError', $this, null); |
|
584
|
|
|
} |
|
585
|
|
|
|
|
586
|
|
|
/** |
|
587
|
|
|
* This event is raised right before the validator starts to perform validation. |
|
588
|
|
|
* You may use this event to change the behavior of validation. |
|
589
|
|
|
* For example, you may disable the validator if certain condition is satisfied. |
|
590
|
|
|
* Note, the event will NOT be raised if the validator is invisible. |
|
591
|
|
|
*/ |
|
592
|
|
|
public function onValidate() |
|
593
|
|
|
{ |
|
594
|
|
|
$this->raiseEvent('OnValidate', $this, null); |
|
595
|
|
|
} |
|
596
|
|
|
|
|
597
|
|
|
/** |
|
598
|
|
|
* Renders the validator control. |
|
599
|
|
|
* @param THtmlWriter $writer writer for the rendering purpose |
|
600
|
|
|
*/ |
|
601
|
|
View Code Duplication |
public function renderContents($writer) |
|
|
|
|
|
|
602
|
|
|
{ |
|
603
|
|
|
if (($text = $this->getText()) !== '') { |
|
604
|
|
|
$writer->write($text); |
|
605
|
|
|
} elseif (($text = $this->getErrorMessage()) !== '') { |
|
606
|
|
|
$writer->write($text); |
|
607
|
|
|
} else { |
|
608
|
|
|
parent::renderContents($writer); |
|
609
|
|
|
} |
|
610
|
|
|
} |
|
611
|
|
|
} |
|
612
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.