1: <?php
2: /**
3: * CActiveForm class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CActiveForm provides a set of methods that can help to simplify the creation
13: * of complex and interactive HTML forms that are associated with data models.
14: *
15: * The 'beginWidget' and 'endWidget' call of CActiveForm widget will render
16: * the open and close form tags. Most other methods of CActiveForm are wrappers
17: * of the corresponding 'active' methods in {@link CHtml}. Calling them in between
18: * the 'beginWidget' and 'endWidget' calls will render text labels, input fields,
19: * etc. For example, calling {@link CActiveForm::textField}
20: * would generate an input field for a specified model attribute.
21: *
22: * What makes CActiveForm extremely useful is its support for data validation.
23: * CActiveForm supports data validation at three levels:
24: * <ul>
25: * <li>server-side validation: the validation is performed at server side after
26: * the whole page containing the form is submitted. If there is any validation error,
27: * CActiveForm will render the error in the page back to user.</li>
28: * <li>AJAX-based validation: when the user enters data into an input field,
29: * an AJAX request is triggered which requires server-side validation. The validation
30: * result is sent back in AJAX response and the input field changes its appearance
31: * accordingly.</li>
32: * <li>client-side validation (available since version 1.1.7):
33: * when the user enters data into an input field,
34: * validation is performed on the client side using JavaScript. No server contact
35: * will be made, which reduces the workload on the server.</li>
36: * </ul>
37: *
38: * All these validations share the same set of validation rules declared in
39: * the associated model class. CActiveForm is designed in such a way that
40: * all these validations will lead to the same user interface changes and error
41: * message content.
42: *
43: * To ensure data validity, server-side validation is always performed.
44: * By setting {@link enableAjaxValidation} to true, one can enable AJAX-based validation;
45: * and by setting {@link enableClientValidation} to true, one can enable client-side validation.
46: * Note that in order to make the latter two validations work, the user's browser
47: * must has its JavaScript enabled. If not, only the server-side validation will
48: * be performed.
49: *
50: * The AJAX-based validation and client-side validation may be used together
51: * or separately. For example, in a user registration form, one may use AJAX-based
52: * validation to check if the user has picked a unique username, and use client-side
53: * validation to ensure all required fields are entered with data.
54: * Because the AJAX-based validation may bring extra workload on the server,
55: * if possible, one should mainly use client-side validation.
56: *
57: * The AJAX-based validation has a few limitations. First, it does not work
58: * with file upload fields. Second, it should not be used to perform validations that
59: * may cause server-side state changes. Third, it is not designed
60: * to work with tabular data input for the moment.
61: *
62: * Support for client-side validation varies for different validators. A validator
63: * will support client-side validation only if it implements {@link CValidator::clientValidateAttribute}
64: * and has its {@link CValidator::enableClientValidation} property set true.
65: * At this moment, the following core validators support client-side validation:
66: * <ul>
67: * <li>{@link CBooleanValidator}</li>
68: * <li>{@link CCaptchaValidator}</li>
69: * <li>{@link CCompareValidator}</li>
70: * <li>{@link CEmailValidator}</li>
71: * <li>{@link CNumberValidator}</li>
72: * <li>{@link CRangeValidator}</li>
73: * <li>{@link CRegularExpressionValidator}</li>
74: * <li>{@link CRequiredValidator}</li>
75: * <li>{@link CStringValidator}</li>
76: * <li>{@link CUrlValidator}</li>
77: * </ul>
78: *
79: * CActiveForm relies on CSS to customize the appearance of input fields
80: * which are in different validation states. In particular, each input field
81: * may be one of the four states: initial (not validated),
82: * validating, error and success. To differentiate these states, CActiveForm
83: * automatically assigns different CSS classes for the last three states
84: * to the HTML element containing the input field.
85: * By default, these CSS classes are named as 'validating', 'error' and 'success',
86: * respectively. We may customize these CSS classes by configuring the
87: * {@link clientOptions} property or specifying in the {@link error} method.
88: *
89: * The following is a piece of sample view code showing how to use CActiveForm:
90: *
91: * <pre>
92: * <?php $form = $this->beginWidget('CActiveForm', array(
93: * 'id'=>'user-form',
94: * 'enableAjaxValidation'=>true,
95: * 'enableClientValidation'=>true,
96: * 'focus'=>array($model,'firstName'),
97: * )); ?>
98: *
99: * <?php echo $form->errorSummary($model); ?>
100: *
101: * <div class="row">
102: * <?php echo $form->labelEx($model,'firstName'); ?>
103: * <?php echo $form->textField($model,'firstName'); ?>
104: * <?php echo $form->error($model,'firstName'); ?>
105: * </div>
106: * <div class="row">
107: * <?php echo $form->labelEx($model,'lastName'); ?>
108: * <?php echo $form->textField($model,'lastName'); ?>
109: * <?php echo $form->error($model,'lastName'); ?>
110: * </div>
111: *
112: * <?php $this->endWidget(); ?>
113: * </pre>
114: *
115: * To respond to the AJAX validation requests, we need the following class code:
116: * <pre>
117: * public function actionCreate()
118: * {
119: * $model=new User;
120: * $this->performAjaxValidation($model);
121: * if(isset($_POST['User']))
122: * {
123: * $model->attributes=$_POST['User'];
124: * if($model->save())
125: * $this->redirect('index');
126: * }
127: * $this->render('create',array('model'=>$model));
128: * }
129: *
130: * protected function performAjaxValidation($model)
131: * {
132: * if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
133: * {
134: * echo CActiveForm::validate($model);
135: * Yii::app()->end();
136: * }
137: * }
138: * </pre>
139: *
140: * In the above code, if we do not enable the AJAX-based validation, we can remove
141: * the <code>performAjaxValidation</code> method and its invocation.
142: *
143: * @author Qiang Xue <qiang.xue@gmail.com>
144: * @package system.web.widgets
145: * @since 1.1.1
146: */
147: class CActiveForm extends CWidget
148: {
149: /**
150: * @var mixed the form action URL (see {@link CHtml::normalizeUrl} for details about this parameter).
151: * If not set, the current page URL is used.
152: */
153: public $action='';
154: /**
155: * @var string the form submission method. This should be either 'post' or 'get'.
156: * Defaults to 'post'.
157: */
158: public $method='post';
159: /**
160: * @var boolean whether to generate a stateful form (See {@link CHtml::statefulForm}). Defaults to false.
161: */
162: public $stateful=false;
163: /**
164: * @var string the CSS class name for error messages.
165: * Since 1.1.14 this defaults to 'errorMessage' defined in {@link CHtml::$errorMessageCss}.
166: * Individual {@link error} call may override this value by specifying the 'class' HTML option.
167: */
168: public $errorMessageCssClass;
169: /**
170: * @var array additional HTML attributes that should be rendered for the form tag.
171: */
172: public $htmlOptions=array();
173: /**
174: * @var array the options to be passed to the javascript validation plugin.
175: * The following options are supported:
176: * <ul>
177: * <li>ajaxVar: string, the name of the parameter indicating the request is an AJAX request.
178: * When the AJAX validation is triggered, a parameter named as this property will be sent
179: * together with the other form data to the server. The parameter value is the form ID.
180: * The server side can then detect who triggers the AJAX validation and react accordingly.
181: * Defaults to 'ajax'.</li>
182: * <li>validationUrl: string, the URL that performs the AJAX validations.
183: * If not set, it will take the value of {@link action}.</li>
184: * <li>validationDelay: integer, the number of milliseconds that an AJAX validation should be
185: * delayed after an input is changed. A value 0 means the validation will be triggered immediately
186: * when an input is changed. A value greater than 0 means changing several inputs may only
187: * trigger a single validation if they happen fast enough, which may help reduce the server load.
188: * Defaults to 200 (0.2 second).</li>
189: * <li>validateOnSubmit: boolean, whether to perform AJAX validation when the form is being submitted.
190: * If there are any validation errors, the form submission will be stopped.
191: * Defaults to false.</li>
192: * <li>validateOnChange: boolean, whether to trigger an AJAX validation
193: * each time when an input's value is changed. You may want to turn this off
194: * if it causes too much performance impact, because each AJAX validation request
195: * will submit the data of the whole form. Defaults to true.</li>
196: * <li>validateOnType: boolean, whether to trigger an AJAX validation each time when the user
197: * presses a key. When setting this property to be true, you should tune up the 'validationDelay'
198: * option to avoid triggering too many AJAX validations. Defaults to false.</li>
199: * <li>hideErrorMessage: boolean, whether to hide the error message even if there is an error.
200: * Defaults to false, which means the error message will show up whenever the input has an error.</li>
201: * <li>inputContainer: string, the jQuery selector for the HTML element containing the input field.
202: * During the validation process, CActiveForm will set different CSS class for the container element
203: * to indicate the state change. If not set, it means the closest 'div' element that contains the input field.</li>
204: * <li>errorCssClass: string, the CSS class to be assigned to the container whose associated input
205: * has AJAX validation error. Defaults to 'error'.</li>
206: * <li>successCssClass: string, the CSS class to be assigned to the container whose associated input
207: * passes AJAX validation without any error. Defaults to 'success'.</li>
208: * <li>validatingCssClass: string, the CSS class to be assigned to the container whose associated input
209: * is currently being validated via AJAX. Defaults to 'validating'.</li>
210: * <li>errorMessageCssClass: string, the CSS class assigned to the error messages returned
211: * by AJAX validations. Defaults to 'errorMessage'.</li>
212: * <li>beforeValidate: function, the function that will be invoked before performing ajax-based validation
213: * triggered by form submission action (available only when validateOnSubmit is set true).
214: * The expected function signature should be <code>beforeValidate(form) {...}</code>, where 'form' is
215: * the jquery representation of the form object. If the return value of this function is NOT true, the validation
216: * will be cancelled.
217: *
218: * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpression} to prevent it
219: * from being encoded as a string. This option has been available since version 1.1.3.</li>
220: * <li>afterValidate: function, the function that will be invoked after performing ajax-based validation
221: * triggered by form submission action (available only when validateOnSubmit is set true).
222: * The expected function signature should be <code>afterValidate(form, data, hasError) {...}</code>, where 'form' is
223: * the jquery representation of the form object; 'data' is the JSON response from the server-side validation; 'hasError'
224: * is a boolean value indicating whether there is any validation error. If the return value of this function is NOT true,
225: * the normal form submission will be cancelled.
226: *
227: * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpression} to prevent it
228: * from being encoded as a string. This option has been available since version 1.1.3.</li>
229: * <li>beforeValidateAttribute: function, the function that will be invoked before performing ajax-based validation
230: * triggered by a single attribute input change. The expected function signature should be
231: * <code>beforeValidateAttribute(form, attribute) {...}</code>, where 'form' is the jquery representation of the form object
232: * and 'attribute' refers to the js options for the triggering attribute (see {@link error}).
233: * If the return value of this function is NOT true, the validation will be cancelled.
234: *
235: * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpression} to prevent it
236: * from being encoded as a string. This option has been available since version 1.1.3.</li>
237: * <li>afterValidateAttribute: function, the function that will be invoked after performing ajax-based validation
238: * triggered by a single attribute input change. The expected function signature should be
239: * <code>afterValidateAttribute(form, attribute, data, hasError) {...}</code>, where 'form' is the jquery
240: * representation of the form object; 'attribute' refers to the js options for the triggering attribute (see {@link error});
241: * 'data' is the JSON response from the server-side validation; 'hasError' is a boolean value indicating whether
242: * there is any validation error.
243: *
244: * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpression} to prevent it
245: * from being encoded as a string. This option has been available since version 1.1.3.</li>
246: * </ul>
247: *
248: * Some of the above options may be overridden in individual calls of {@link error()}.
249: * They include: validationDelay, validateOnChange, validateOnType, hideErrorMessage,
250: * inputContainer, errorCssClass, successCssClass, validatingCssClass, beforeValidateAttribute, afterValidateAttribute.
251: */
252: public $clientOptions=array();
253: /**
254: * @var boolean whether to enable data validation via AJAX. Defaults to false.
255: * When this property is set true, you should respond to the AJAX validation request on the server side as shown below:
256: * <pre>
257: * public function actionCreate()
258: * {
259: * $model=new User;
260: * if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
261: * {
262: * echo CActiveForm::validate($model);
263: * Yii::app()->end();
264: * }
265: * ......
266: * }
267: * </pre>
268: */
269: public $enableAjaxValidation=false;
270: /**
271: * @var boolean whether to enable client-side data validation. Defaults to false.
272: *
273: * When this property is set true, client-side validation will be performed by validators
274: * that support it (see {@link CValidator::enableClientValidation} and {@link CValidator::clientValidateAttribute}).
275: *
276: * @see error
277: * @since 1.1.7
278: */
279: public $enableClientValidation=false;
280:
281: /**
282: * @var mixed form element to get initial input focus on page load.
283: *
284: * Defaults to null meaning no input field has a focus.
285: * If set as array, first element should be model and second element should be the attribute.
286: * If set as string any jQuery selector can be used
287: *
288: * Example - set input focus on page load to:
289: * <ul>
290: * <li>'focus'=>array($model,'username') - $model->username input filed</li>
291: * <li>'focus'=>'#'.CHtml::activeId($model,'username') - $model->username input field</li>
292: * <li>'focus'=>'#LoginForm_username' - input field with ID LoginForm_username</li>
293: * <li>'focus'=>'input[type="text"]:first' - first input element of type text</li>
294: * <li>'focus'=>'input:visible:enabled:first' - first visible and enabled input element</li>
295: * <li>'focus'=>'input:text[value=""]:first' - first empty input</li>
296: * </ul>
297: *
298: * @since 1.1.4
299: */
300: public $focus;
301: /**
302: * @var array the javascript options for model attributes (input ID => options)
303: * @see error
304: * @since 1.1.7
305: */
306: protected $attributes=array();
307: /**
308: * @var string the ID of the container element for error summary
309: * @see errorSummary
310: * @since 1.1.7
311: */
312: protected $summaryID;
313: /**
314: * @var string[] attribute IDs to be used to display error summary.
315: * @since 1.1.14
316: */
317: private $_summaryAttributes=array();
318:
319: /**
320: * Initializes the widget.
321: * This renders the form open tag.
322: */
323: public function init()
324: {
325: if(!isset($this->htmlOptions['id']))
326: $this->htmlOptions['id']=$this->id;
327: else
328: $this->id=$this->htmlOptions['id'];
329:
330: if($this->stateful)
331: echo CHtml::statefulForm($this->action, $this->method, $this->htmlOptions);
332: else
333: echo CHtml::beginForm($this->action, $this->method, $this->htmlOptions);
334:
335: if($this->errorMessageCssClass===null)
336: $this->errorMessageCssClass=CHtml::$errorMessageCss;
337: }
338:
339: /**
340: * Runs the widget.
341: * This registers the necessary javascript code and renders the form close tag.
342: */
343: public function run()
344: {
345: if(is_array($this->focus))
346: $this->focus="#".CHtml::activeId($this->focus[0],$this->focus[1]);
347:
348: echo CHtml::endForm();
349: $cs=Yii::app()->clientScript;
350: if(!$this->enableAjaxValidation && !$this->enableClientValidation || empty($this->attributes))
351: {
352: if($this->focus!==null)
353: {
354: $cs->registerCoreScript('jquery');
355: $cs->registerScript('CActiveForm#focus',"
356: if(!window.location.hash)
357: jQuery('".$this->focus."').focus();
358: ");
359: }
360: return;
361: }
362:
363: $options=$this->clientOptions;
364: if(isset($this->clientOptions['validationUrl']) && is_array($this->clientOptions['validationUrl']))
365: $options['validationUrl']=CHtml::normalizeUrl($this->clientOptions['validationUrl']);
366:
367: foreach($this->_summaryAttributes as $attribute)
368: $this->attributes[$attribute]['summary']=true;
369: $options['attributes']=array_values($this->attributes);
370:
371: if($this->summaryID!==null)
372: $options['summaryID']=$this->summaryID;
373:
374: if($this->focus!==null)
375: $options['focus']=$this->focus;
376:
377: if(!empty(CHtml::$errorCss))
378: $options['errorCss']=CHtml::$errorCss;
379:
380: $options=CJavaScript::encode($options);
381: $cs->registerCoreScript('yiiactiveform');
382: $id=$this->id;
383: $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiactiveform($options);");
384: }
385:
386: /**
387: * Displays the first validation error for a model attribute.
388: * This is similar to {@link CHtml::error} except that it registers the model attribute
389: * so that if its value is changed by users, an AJAX validation may be triggered.
390: * @param CModel $model the data model
391: * @param string $attribute the attribute name
392: * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
393: * Besides all those options available in {@link CHtml::error}, the following options are recognized in addition:
394: * <ul>
395: * <li>validationDelay</li>
396: * <li>validateOnChange</li>
397: * <li>validateOnType</li>
398: * <li>hideErrorMessage</li>
399: * <li>inputContainer</li>
400: * <li>errorCssClass</li>
401: * <li>successCssClass</li>
402: * <li>validatingCssClass</li>
403: * <li>beforeValidateAttribute</li>
404: * <li>afterValidateAttribute</li>
405: * </ul>
406: * These options override the corresponding options as declared in {@link options} for this
407: * particular model attribute. For more details about these options, please refer to {@link clientOptions}.
408: * Note that these options are only used when {@link enableAjaxValidation} or {@link enableClientValidation}
409: * is set true.
410: * <ul>
411: * <li>inputID</li>
412: * </ul>
413: * When an CActiveForm input field uses a custom ID, for ajax/client validation to work properly
414: * inputID should be set to the same ID
415: *
416: * Example:
417: * <pre>
418: * <div class="form-element">
419: * <?php echo $form->labelEx($model,'attribute'); ?>
420: * <?php echo $form->textField($model,'attribute', array('id'=>'custom-id')); ?>
421: * <?php echo $form->error($model,'attribute',array('inputID'=>'custom-id')); ?>
422: * </div>
423: * </pre>
424: *
425: * When client-side validation is enabled, an option named "clientValidation" is also recognized.
426: * This option should take a piece of JavaScript code to perform client-side validation. In the code,
427: * the variables are predefined:
428: * <ul>
429: * <li>value: the current input value associated with this attribute.</li>
430: * <li>messages: an array that may be appended with new error messages for the attribute.</li>
431: * <li>attribute: a data structure keeping all client-side options for the attribute</li>
432: * </ul>
433: * This should NOT be a function but just the code, Yii will enclose the code you provide inside the
434: * actual JS function.
435: * @param boolean $enableAjaxValidation whether to enable AJAX validation for the specified attribute.
436: * Note that in order to enable AJAX validation, both {@link enableAjaxValidation} and this parameter
437: * must be true.
438: * @param boolean $enableClientValidation whether to enable client-side validation for the specified attribute.
439: * Note that in order to enable client-side validation, both {@link enableClientValidation} and this parameter
440: * must be true. This parameter has been available since version 1.1.7.
441: * @return string the validation result (error display or success message).
442: * @see CHtml::error
443: */
444: public function error($model,$attribute,$htmlOptions=array(),$enableAjaxValidation=true,$enableClientValidation=true)
445: {
446: if(!$this->enableAjaxValidation)
447: $enableAjaxValidation=false;
448: if(!$this->enableClientValidation)
449: $enableClientValidation=false;
450:
451: if(!isset($htmlOptions['class']))
452: $htmlOptions['class']=$this->errorMessageCssClass;
453:
454: if(!$enableAjaxValidation && !$enableClientValidation)
455: return CHtml::error($model,$attribute,$htmlOptions);
456:
457: $id=CHtml::activeId($model,$attribute);
458: $inputID=isset($htmlOptions['inputID']) ? $htmlOptions['inputID'] : $id;
459: unset($htmlOptions['inputID']);
460: if(!isset($htmlOptions['id']))
461: $htmlOptions['id']=$inputID.'_em_';
462:
463: $option=array(
464: 'id'=>$id,
465: 'inputID'=>$inputID,
466: 'errorID'=>$htmlOptions['id'],
467: 'model'=>get_class($model),
468: 'name'=>$attribute,
469: 'enableAjaxValidation'=>$enableAjaxValidation,
470: );
471:
472: $optionNames=array(
473: 'validationDelay',
474: 'validateOnChange',
475: 'validateOnType',
476: 'hideErrorMessage',
477: 'inputContainer',
478: 'errorCssClass',
479: 'successCssClass',
480: 'validatingCssClass',
481: 'beforeValidateAttribute',
482: 'afterValidateAttribute',
483: );
484: foreach($optionNames as $name)
485: {
486: if(isset($htmlOptions[$name]))
487: {
488: $option[$name]=$htmlOptions[$name];
489: unset($htmlOptions[$name]);
490: }
491: }
492: if($model instanceof CActiveRecord && !$model->isNewRecord)
493: $option['status']=1;
494:
495: if($enableClientValidation)
496: {
497: $validators=isset($htmlOptions['clientValidation']) ? array($htmlOptions['clientValidation']) : array();
498: unset($htmlOptions['clientValidation']);
499:
500: $attributeName = $attribute;
501: if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1) // e.g. [a]name
502: {
503: $attributeName=substr($attribute,$pos+1);
504: }
505:
506: foreach($model->getValidators($attributeName) as $validator)
507: {
508: if($validator->enableClientValidation)
509: {
510: if(($js=$validator->clientValidateAttribute($model,$attributeName))!='')
511: $validators[]=$js;
512: }
513: }
514: if($validators!==array())
515: $option['clientValidation']=new CJavaScriptExpression("function(value, messages, attribute) {\n".implode("\n",$validators)."\n}");
516: }
517:
518: if(empty($option['hideErrorMessage']) && empty($this->clientOptions['hideErrorMessage']))
519: $html=CHtml::error($model,$attribute,$htmlOptions);
520: else
521: $html='';
522: if($html==='')
523: {
524: if(isset($htmlOptions['style']))
525: $htmlOptions['style']=rtrim($htmlOptions['style'],';').';display:none';
526: else
527: $htmlOptions['style']='display:none';
528: $html=CHtml::tag(CHtml::$errorContainerTag,$htmlOptions,'');
529: }
530:
531: $this->attributes[$inputID]=$option;
532: return $html;
533: }
534:
535: /**
536: * Displays a summary of validation errors for one or several models.
537: * This method is very similar to {@link CHtml::errorSummary} except that it also works
538: * when AJAX validation is performed.
539: * @param mixed $models the models whose input errors are to be displayed. This can be either
540: * a single model or an array of models.
541: * @param string $header a piece of HTML code that appears in front of the errors
542: * @param string $footer a piece of HTML code that appears at the end of the errors
543: * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
544: * @return string the error summary. Empty if no errors are found.
545: * @see CHtml::errorSummary
546: */
547: public function errorSummary($models,$header=null,$footer=null,$htmlOptions=array())
548: {
549: if(!$this->enableAjaxValidation && !$this->enableClientValidation)
550: return CHtml::errorSummary($models,$header,$footer,$htmlOptions);
551:
552: if(!isset($htmlOptions['id']))
553: $htmlOptions['id']=$this->id.'_es_';
554: $html=CHtml::errorSummary($models,$header,$footer,$htmlOptions);
555: if($html==='')
556: {
557: if($header===null)
558: $header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
559: if(!isset($htmlOptions['class']))
560: $htmlOptions['class']=CHtml::$errorSummaryCss;
561: $htmlOptions['style']=isset($htmlOptions['style']) ? rtrim($htmlOptions['style'],';').';display:none' : 'display:none';
562: $html=CHtml::tag('div',$htmlOptions,$header."\n<ul><li>dummy</li></ul>".$footer);
563: }
564:
565: $this->summaryID=$htmlOptions['id'];
566: foreach(is_array($models) ? $models : array($models) as $model)
567: foreach($model->getSafeAttributeNames() as $attribute)
568: $this->_summaryAttributes[]=CHtml::activeId($model,$attribute);
569:
570: return $html;
571: }
572:
573: /**
574: * Renders an HTML label for a model attribute.
575: * This method is a wrapper of {@link CHtml::activeLabel}.
576: * Please check {@link CHtml::activeLabel} for detailed information
577: * about the parameters for this method.
578: * @param CModel $model the data model
579: * @param string $attribute the attribute
580: * @param array $htmlOptions additional HTML attributes.
581: * @return string the generated label tag
582: */
583: public function label($model,$attribute,$htmlOptions=array())
584: {
585: return CHtml::activeLabel($model,$attribute,$htmlOptions);
586: }
587:
588: /**
589: * Renders an HTML label for a model attribute.
590: * This method is a wrapper of {@link CHtml::activeLabelEx}.
591: * Please check {@link CHtml::activeLabelEx} for detailed information
592: * about the parameters for this method.
593: * @param CModel $model the data model
594: * @param string $attribute the attribute
595: * @param array $htmlOptions additional HTML attributes.
596: * @return string the generated label tag
597: */
598: public function labelEx($model,$attribute,$htmlOptions=array())
599: {
600: return CHtml::activeLabelEx($model,$attribute,$htmlOptions);
601: }
602:
603: /**
604: * Renders a url field for a model attribute.
605: * This method is a wrapper of {@link CHtml::activeUrlField}.
606: * Please check {@link CHtml::activeUrlField} for detailed information
607: * about the parameters for this method.
608: * @param CModel $model the data model
609: * @param string $attribute the attribute
610: * @param array $htmlOptions additional HTML attributes.
611: * @return string the generated input field
612: * @since 1.1.11
613: */
614: public function urlField($model,$attribute,$htmlOptions=array())
615: {
616: return CHtml::activeUrlField($model,$attribute,$htmlOptions);
617: }
618:
619: /**
620: * Renders an email field for a model attribute.
621: * This method is a wrapper of {@link CHtml::activeEmailField}.
622: * Please check {@link CHtml::activeEmailField} for detailed information
623: * about the parameters for this method.
624: * @param CModel $model the data model
625: * @param string $attribute the attribute
626: * @param array $htmlOptions additional HTML attributes.
627: * @return string the generated input field
628: * @since 1.1.11
629: */
630: public function emailField($model,$attribute,$htmlOptions=array())
631: {
632: return CHtml::activeEmailField($model,$attribute,$htmlOptions);
633: }
634:
635: /**
636: * Renders a number field for a model attribute.
637: * This method is a wrapper of {@link CHtml::activeNumberField}.
638: * Please check {@link CHtml::activeNumberField} for detailed information
639: * about the parameters for this method.
640: * @param CModel $model the data model
641: * @param string $attribute the attribute
642: * @param array $htmlOptions additional HTML attributes.
643: * @return string the generated input field
644: * @since 1.1.11
645: */
646: public function numberField($model,$attribute,$htmlOptions=array())
647: {
648: return CHtml::activeNumberField($model,$attribute,$htmlOptions);
649: }
650:
651: /**
652: * Generates a range field for a model attribute.
653: * This method is a wrapper of {@link CHtml::activeRangeField}.
654: * Please check {@link CHtml::activeRangeField} for detailed information
655: * about the parameters for this method.
656: * @param CModel $model the data model
657: * @param string $attribute the attribute
658: * @param array $htmlOptions additional HTML attributes.
659: * @return string the generated input field
660: * @since 1.1.11
661: */
662: public function rangeField($model,$attribute,$htmlOptions=array())
663: {
664: return CHtml::activeRangeField($model,$attribute,$htmlOptions);
665: }
666:
667: /**
668: * Renders a date field for a model attribute.
669: * This method is a wrapper of {@link CHtml::activeDateField}.
670: * Please check {@link CHtml::activeDateField} for detailed information
671: * about the parameters for this method.
672: * @param CModel $model the data model
673: * @param string $attribute the attribute
674: * @param array $htmlOptions additional HTML attributes.
675: * @return string the generated input field
676: * @since 1.1.11
677: */
678: public function dateField($model,$attribute,$htmlOptions=array())
679: {
680: return CHtml::activeDateField($model,$attribute,$htmlOptions);
681: }
682:
683:
684: /**
685: * Renders a time field for a model attribute.
686: * This method is a wrapper of {@link CHtml::activeTimeField}.
687: * Please check {@link CHtml::activeTimeField} for detailed information
688: * about the parameters for this method.
689: * @param CModel $model the data model
690: * @param string $attribute the attribute
691: * @param array $htmlOptions additional HTML attributes.
692: * @return string the generated input field
693: * @since 1.1.14
694: */
695: public function timeField($model,$attribute,$htmlOptions=array())
696: {
697: return CHtml::activeTimeField($model,$attribute,$htmlOptions);
698: }
699:
700: /**
701: * Renders a datetime field for a model attribute.
702: * This method is a wrapper of {@link CHtml::activeDateTimeField}.
703: * Please check {@link CHtml::activeDateTimeField} for detailed information
704: * about the parameters for this method.
705: * @param CModel $model the data model
706: * @param string $attribute the attribute
707: * @param array $htmlOptions additional HTML attributes.
708: * @return string the generated input field
709: * @since 1.1.16
710: */
711: public function dateTimeField($model,$attribute,$htmlOptions=array())
712: {
713: return CHtml::activeDateTimeField($model,$attribute,$htmlOptions);
714: }
715:
716: /**
717: * Renders a local datetime field for a model attribute.
718: * This method is a wrapper of {@link CHtml::activeDateTimeLocalField}.
719: * Please check {@link CHtml::activeDateTimeLocalField} for detailed information
720: * about the parameters for this method.
721: * @param CModel $model the data model
722: * @param string $attribute the attribute
723: * @param array $htmlOptions additional HTML attributes.
724: * @return string the generated input field
725: * @since 1.1.16
726: */
727: public function dateTimeLocalField($model,$attribute,$htmlOptions=array())
728: {
729: return CHtml::activeDateTimeLocalField($model,$attribute,$htmlOptions);
730: }
731:
732: /**
733: * Renders a week field for a model attribute.
734: * This method is a wrapper of {@link CHtml::activeWeekField}.
735: * Please check {@link CHtml::activeWeekField} for detailed information
736: * about the parameters for this method.
737: * @param CModel $model the data model
738: * @param string $attribute the attribute
739: * @param array $htmlOptions additional HTML attributes.
740: * @return string the generated input field
741: * @since 1.1.16
742: */
743: public function weekField($model,$attribute,$htmlOptions=array())
744: {
745: return CHtml::activeWeekField($model,$attribute,$htmlOptions);
746: }
747:
748: /**
749: * Renders a color picker field for a model attribute.
750: * This method is a wrapper of {@link CHtml::activeColorField}.
751: * Please check {@link CHtml::activeColorField} for detailed information
752: * about the parameters for this method.
753: * @param CModel $model the data model
754: * @param string $attribute the attribute
755: * @param array $htmlOptions additional HTML attributes.
756: * @return string the generated input field
757: * @since 1.1.16
758: */
759: public function colorField($model,$attribute,$htmlOptions=array())
760: {
761: return CHtml::activeColorField($model,$attribute,$htmlOptions);
762: }
763:
764: /**
765: * Renders a tel field for a model attribute.
766: * This method is a wrapper of {@link CHtml::activeTelField}.
767: * Please check {@link CHtml::activeTelField} for detailed information
768: * about the parameters for this method.
769: * @param CModel $model the data model
770: * @param string $attribute the attribute
771: * @param array $htmlOptions additional HTML attributes.
772: * @return string the generated input field
773: * @since 1.1.14
774: */
775: public function telField($model,$attribute,$htmlOptions=array())
776: {
777: return CHtml::activeTelField($model,$attribute,$htmlOptions);
778: }
779:
780: /**
781: * Renders a text field for a model attribute.
782: * This method is a wrapper of {@link CHtml::activeTextField}.
783: * Please check {@link CHtml::activeTextField} for detailed information
784: * about the parameters for this method.
785: * @param CModel $model the data model
786: * @param string $attribute the attribute
787: * @param array $htmlOptions additional HTML attributes.
788: * @return string the generated input field
789: */
790: public function textField($model,$attribute,$htmlOptions=array())
791: {
792: return CHtml::activeTextField($model,$attribute,$htmlOptions);
793: }
794:
795: /**
796: * Renders a search field for a model attribute.
797: * This method is a wrapper of {@link CHtml::activeSearchField}.
798: * Please check {@link CHtml::activeSearchField} for detailed information
799: * about the parameters for this method.
800: * @param CModel $model the data model
801: * @param string $attribute the attribute
802: * @param array $htmlOptions additional HTML attributes.
803: * @return string the generated input field
804: * @since 1.1.14
805: */
806: public function searchField($model,$attribute,$htmlOptions=array())
807: {
808: return CHtml::activeSearchField($model,$attribute,$htmlOptions);
809: }
810:
811: /**
812: * Renders a hidden field for a model attribute.
813: * This method is a wrapper of {@link CHtml::activeHiddenField}.
814: * Please check {@link CHtml::activeHiddenField} for detailed information
815: * about the parameters for this method.
816: * @param CModel $model the data model
817: * @param string $attribute the attribute
818: * @param array $htmlOptions additional HTML attributes.
819: * @return string the generated input field
820: */
821: public function ($model,$attribute,$htmlOptions=array())
822: {
823: return CHtml::activeHiddenField($model,$attribute,$htmlOptions);
824: }
825:
826: /**
827: * Renders a password field for a model attribute.
828: * This method is a wrapper of {@link CHtml::activePasswordField}.
829: * Please check {@link CHtml::activePasswordField} for detailed information
830: * about the parameters for this method.
831: * @param CModel $model the data model
832: * @param string $attribute the attribute
833: * @param array $htmlOptions additional HTML attributes.
834: * @return string the generated input field
835: */
836: public function passwordField($model,$attribute,$htmlOptions=array())
837: {
838: return CHtml::activePasswordField($model,$attribute,$htmlOptions);
839: }
840:
841: /**
842: * Renders a text area for a model attribute.
843: * This method is a wrapper of {@link CHtml::activeTextArea}.
844: * Please check {@link CHtml::activeTextArea} for detailed information
845: * about the parameters for this method.
846: * @param CModel $model the data model
847: * @param string $attribute the attribute
848: * @param array $htmlOptions additional HTML attributes.
849: * @return string the generated text area
850: */
851: public function textArea($model,$attribute,$htmlOptions=array())
852: {
853: return CHtml::activeTextArea($model,$attribute,$htmlOptions);
854: }
855:
856: /**
857: * Renders a file field for a model attribute.
858: * This method is a wrapper of {@link CHtml::activeFileField}.
859: * Please check {@link CHtml::activeFileField} for detailed information
860: * about the parameters for this method.
861: * @param CModel $model the data model
862: * @param string $attribute the attribute
863: * @param array $htmlOptions additional HTML attributes
864: * @return string the generated input field
865: */
866: public function fileField($model,$attribute,$htmlOptions=array())
867: {
868: return CHtml::activeFileField($model,$attribute,$htmlOptions);
869: }
870:
871: /**
872: * Renders a radio button for a model attribute.
873: * This method is a wrapper of {@link CHtml::activeRadioButton}.
874: * Please check {@link CHtml::activeRadioButton} for detailed information
875: * about the parameters for this method.
876: * @param CModel $model the data model
877: * @param string $attribute the attribute
878: * @param array $htmlOptions additional HTML attributes.
879: * @return string the generated radio button
880: */
881: public function radioButton($model,$attribute,$htmlOptions=array())
882: {
883: return CHtml::activeRadioButton($model,$attribute,$htmlOptions);
884: }
885:
886: /**
887: * Renders a checkbox for a model attribute.
888: * This method is a wrapper of {@link CHtml::activeCheckBox}.
889: * Please check {@link CHtml::activeCheckBox} for detailed information
890: * about the parameters for this method.
891: * @param CModel $model the data model
892: * @param string $attribute the attribute
893: * @param array $htmlOptions additional HTML attributes.
894: * @return string the generated check box
895: */
896: public function checkBox($model,$attribute,$htmlOptions=array())
897: {
898: return CHtml::activeCheckBox($model,$attribute,$htmlOptions);
899: }
900:
901: /**
902: * Renders a dropdown list for a model attribute.
903: * This method is a wrapper of {@link CHtml::activeDropDownList}.
904: * Please check {@link CHtml::activeDropDownList} for detailed information
905: * about the parameters for this method.
906: * @param CModel $model the data model
907: * @param string $attribute the attribute
908: * @param array $data data for generating the list options (value=>display)
909: * @param array $htmlOptions additional HTML attributes.
910: * @return string the generated drop down list
911: */
912: public function dropDownList($model,$attribute,$data,$htmlOptions=array())
913: {
914: return CHtml::activeDropDownList($model,$attribute,$data,$htmlOptions);
915: }
916:
917: /**
918: * Renders a list box for a model attribute.
919: * This method is a wrapper of {@link CHtml::activeListBox}.
920: * Please check {@link CHtml::activeListBox} for detailed information
921: * about the parameters for this method.
922: * @param CModel $model the data model
923: * @param string $attribute the attribute
924: * @param array $data data for generating the list options (value=>display)
925: * @param array $htmlOptions additional HTML attributes.
926: * @return string the generated list box
927: */
928: public function listBox($model,$attribute,$data,$htmlOptions=array())
929: {
930: return CHtml::activeListBox($model,$attribute,$data,$htmlOptions);
931: }
932:
933: /**
934: * Renders a checkbox list for a model attribute.
935: * This method is a wrapper of {@link CHtml::activeCheckBoxList}.
936: * Please check {@link CHtml::activeCheckBoxList} for detailed information
937: * about the parameters for this method.
938: * @param CModel $model the data model
939: * @param string $attribute the attribute
940: * @param array $data value-label pairs used to generate the check box list.
941: * @param array $htmlOptions addtional HTML options.
942: * @return string the generated check box list
943: */
944: public function checkBoxList($model,$attribute,$data,$htmlOptions=array())
945: {
946: return CHtml::activeCheckBoxList($model,$attribute,$data,$htmlOptions);
947: }
948:
949: /**
950: * Renders a radio button list for a model attribute.
951: * This method is a wrapper of {@link CHtml::activeRadioButtonList}.
952: * Please check {@link CHtml::activeRadioButtonList} for detailed information
953: * about the parameters for this method.
954: * @param CModel $model the data model
955: * @param string $attribute the attribute
956: * @param array $data value-label pairs used to generate the radio button list.
957: * @param array $htmlOptions addtional HTML options.
958: * @return string the generated radio button list
959: */
960: public function radioButtonList($model,$attribute,$data,$htmlOptions=array())
961: {
962: return CHtml::activeRadioButtonList($model,$attribute,$data,$htmlOptions);
963: }
964:
965: /**
966: * Validates one or several models and returns the results in JSON format.
967: * This is a helper method that simplifies the way of writing AJAX validation code.
968: * @param mixed $models a single model instance or an array of models.
969: * @param array $attributes list of attributes that should be validated. Defaults to null,
970: * meaning any attribute listed in the applicable validation rules of the models should be
971: * validated. If this parameter is given as a list of attributes, only
972: * the listed attributes will be validated.
973: * @param boolean $loadInput whether to load the data from $_POST array in this method.
974: * If this is true, the model will be populated from <code>$_POST[ModelClass]</code>.
975: * @return string the JSON representation of the validation error messages.
976: */
977: public static function validate($models, $attributes=null, $loadInput=true)
978: {
979: $result=array();
980: if(!is_array($models))
981: $models=array($models);
982: foreach($models as $model)
983: {
984: $modelName=CHtml::modelName($model);
985: if($loadInput && isset($_POST[$modelName]))
986: $model->attributes=$_POST[$modelName];
987: $model->validate($attributes);
988: foreach($model->getErrors() as $attribute=>$errors)
989: $result[CHtml::activeId($model,$attribute)]=$errors;
990: }
991: return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);
992: }
993:
994: /**
995: * Validates an array of model instances and returns the results in JSON format.
996: * This is a helper method that simplifies the way of writing AJAX validation code for tabular input.
997: * @param mixed $models an array of model instances.
998: * @param array $attributes list of attributes that should be validated. Defaults to null,
999: * meaning any attribute listed in the applicable validation rules of the models should be
1000: * validated. If this parameter is given as a list of attributes, only
1001: * the listed attributes will be validated.
1002: * @param boolean $loadInput whether to load the data from $_POST array in this method.
1003: * If this is true, the model will be populated from <code>$_POST[ModelClass][$i]</code>.
1004: * @return string the JSON representation of the validation error messages.
1005: */
1006: public static function validateTabular($models, $attributes=null, $loadInput=true)
1007: {
1008: $result=array();
1009: if(!is_array($models))
1010: $models=array($models);
1011: foreach($models as $i=>$model)
1012: {
1013: $modelName=CHtml::modelName($model);
1014: if($loadInput && isset($_POST[$modelName][$i]))
1015: $model->attributes=$_POST[$modelName][$i];
1016: $model->validate($attributes);
1017: foreach($model->getErrors() as $attribute=>$errors)
1018: $result[CHtml::activeId($model,'['.$i.']'.$attribute)]=$errors;
1019: }
1020: return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);
1021: }
1022: }
1023: