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