Thursday, 24 March 2016

Model rules for date validation and triming the values before validation

Today I faced problem with validating date fields .

I am accepting date using CJuiDateTimepicker it is working fine, but when I gave regular expression to validate a date field. It is giving error even for the valid date.

The main cause for the above situation is the DatePicker picking up date and a space appended to the date at the end of date. However we have 'date' datatype in mysql for these fields so the dates are automatically trimmed and saved in DB perfectly.

But to validate the dates we have define the rules as below

array('heardt,fdate,secdt,judgedt,nheardt,mandsurdt,leactdt,serorddt,dispdt', 'filter', 'filter'=>'trim'),    // This will trim the values
            array('heardt,fdate,secdt,judgedt,nheardt,mandsurdt,leactdt,serorddt,dispdt','match' ,'pattern'=> '/^([0-9]{4})-([0-1]{0,1}[0-9]{1})-([0-3]{0,1}[0-9]{1})$/','allowEmpty'=>true,'message'=> 'Date Format is YYYY-MM-DD'),
/* The above one validates the format of date. This format accepts 0000-00-00 as date */

array('dispdt','match','pattern'=> '/^([0-9]{4})-([0-1]{0,1}[0-9]{1})-([0-3]{0,1}[0-9]{1})$/','allowEmpty'=>false, 'message'=>'Disposed date mandatory when case is disposed','on'=>'disposed'),

/* The above one works when $model->scenario is assaigned to disposed. */

By this we can validate the dates using model rules

Wednesday, 23 March 2016

End Date should be greater than Start Date using CJuiDatePicker

<?php 
echo $form->labelEx($model, 'start_date');
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model' => $model,
'htmlOptions' => array(
'size' => '10', // textField size
'maxlength' => '10', // textField maxlength
'class' => "input-small"
),
'options' => array(
'showAnim' => 'fold',
'dateFormat' => 'yy-mm-dd',
'changeMonth' => true,
'changeYear' => true,
'yearRange' => '2000:2099',
'onSelect' => 'js:function( selectedDate ) {
    // #end_date is the ID of end_date input text field
    $("#end_date").datepicker( "option", "minDate", selectedDate );
     }',
    ),
));

echo $form->labelEx($model, 'end_date');            
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model' => $model,
'htmlOptions' => array(
'size' => '10', // textField size
'maxlength' => '10', // textField maxlength                        
'class' => "input-small"
),
'options' => array(
'showAnim' => 'fold',
'dateFormat' => 'yy-mm-dd',
'changeMonth' => true,
'changeYear' => true,
),
));
            
?>

Saturday, 19 March 2016

Ajax Partial Rendering in YII rendering calender controls and partial views

Lets consider a senario such that certain controls to be displayed based on selection of dropdown in which it may contain calender controls (such as CJUIDateTimePicker) or a ajax calls which in turns calls another view. To achieve the above situation

In my case , While entering land details the user selects "whether regularization applied?" column to Yes/NO selection.
If Yes then we have to accept the "date of application" and again We need to know whether "Depreciation Claimed or not by the applicant" and , If yes then we have to accept the reasons and date from the user.
For this, I have main model "land" which consists fields "reg_applied varchar(1) , app_dt date, dclaimed varchar(1) , reasons varchar(300) and finally dcdate date."

First we have _createform.php (app_folder\protected\views\land\_createform.php):

<?php echo $form->dropDownList($model,'reg_applied',array('N'=>'NO','Y'=>'YES'),  
        array('prompt'=>'Select',

                    'ajax'=>array( 'type'=>'POST',   
                   'url'=>CController::createUrl('Land/areg',array('id'=>$model->id)), 
                      'update'=>'#areg', 

          ))); ?>  
        <?php echo $form->error($model,'reg_applied'); ?>

<div id="areg">   
</div>

In above dropdown we defined a ajax call to the action 'areg' . and updates the div content which is having id as 'areg'.

Now we have to define the action 'areg' in our LandController.php (app_folder\protected\controller\LandController.php)

public function actionAreg($id){ 
        if(($id==null)or($id=='')or(empty($id)))  
            $model=new Land; 
        else 
            $model=$this->loadModel($id); 
        $stat=$_POST['Land']['reg_applied'];
       $output=$this->renderPartial('_areg',array('model'=>$model,'stat'=>$stat),true,true);
        echo $output;     
}                               

Now we have to define our partial form i.e., nothing but "_areg.php" in our views folder (app_folder\protected\views\land\_areg.php)

<?php if(strtoupper($stat)=='Y'){    /* This is defined in controller and we are passing as argument  in the render partial method */  ?>
<table>
<tr>
<td><b> If Yes (applied) - </b></td>
<td><b>Date of application </b></td>
<td>
    <?php                                                                                                                         
                     $this->widget('zii.widgets.jui.CJuiDatePicker',array(                  
            'model'=>$model,
            'attribute'=>'app_dt',
            'value'=>date('Y-m-d',strtotime($model->app_dt)),
            'language'=>'',
            'options'=>array(
                'showAnim'=>'slide', //'slide','fold','slideDown','fadeIn','blind','bounce','clip','drop'
                    //    'showAnim'=>'slideDown',
                'showHour'=>false,
                'showMinute'=>false,
                'showTime'=>false,
                'changeMonth'=>true,
                'changeYear'=>true,
                'dateFormat'=>'yy-mm-dd',
                'timeFormat'=>'',
                'showButtonPanel'=>true,
            ),
            'htmlOptions'=>array(   
            'style'=>'height:20px;'
        ),
));
?>
</td>

<td><b>Depreciation Claimed</b></td>
<td>
            <?php echo CHtml::dropDownList('Land[
dclaimed]',"$model->dclaimed",
                    array('N'=>'NO','Y'=>'YES'),
                    array('ajax'=>array(
                      'type'=>'POST',
                      'url'=>CController::createUrl('Land/dclaim',array('id'=>$model->id)),
                      'update'=>'#dclaim',
                    ))
                    );?>
</td>

</tr>
<tr>
<td colspan='5'>
</td>
<div id="dclaim">
    </div>

</tr>
</table>


Here in the above partial form we are calling another ajax call for the dropdown dclaimed. Remember We have to know whether "Depreciation Claimed or not by the applicant" and , If claimed then we have to accept the reasons and date from the user.To acheive this we are calling ajax call and we have to handle the code that if claimed ie., $model->dclaimed =='Y' then we have to display the fields reasons and date

Again move to controller (our LandController.php) and define the action dclaim (app_folder\protected\controller\LandController.php)

public function actionDclaim($id){
        if(($id==null)or($id=='')or(empty($id)))
            $model=new Land;
        else
            $model=$this->loadModel($id);
        $stat=$_POST['Land']['dclaimed'];
        $output=$this->renderPartial('_dclaim',array('model'=>$model,'stat'=>$stat),true,true);
        echo $output;
    }


and here we are rendering partial view dclaim , remember the view elements which are showing are shown in the position where our div dclaim defined. So we have to customize the positions of controls according to our requirement

Now define partial view (app_folder\protected\views\land\_dclaim.php)

<?php if(strtoupper($stat)=='Y'){ ?>
<table>
<tr>
<td rowspan="2"><b> If Yes </b></td>
<td colspan="1"><b>Details</b></td>
<td colspan="3">
    <?php echo CHtml::textArea('Land[reasons]', "$model->details",array('rows'=>4,'cols'=>40,'style'=>'width:270px;height:80px;')); ?>
    </td>
    </tr><tr>
<td><b>Date of Execution </b></td>
<td>

    <?php
             $this->widget('zii.widgets.jui.CJuiDatePicker',array(
            'model'=>$model,
            'attribute'=>'dcdate',
            'value'=>date('Y-m-d',strtotime($model->dcdate)),
            'language'=>'',
            'options'=>array(
                'showAnim'=>'slide', //'slide','fold','slideDown','fadeIn','blind','bounce','clip','drop'
                    //    'showAnim'=>'slideDown',
                'showHour'=>false,
                'showMinute'=>false,
                'showTime'=>false,
                'changeMonth'=>true,
                'changeYear'=>true,
                'dateFormat'=>'yy-mm-dd',
                'timeFormat'=>'',
                'showButtonPanel'=>true,
            ),
            'htmlOptions'=>array(  
            'style'=>'height:20px;'
        ),
));
?>
</td>
</tr>
</table>

<?php } ?>

and finally don't forget to define access rules for the above two actions ie.,

public function accessRules()
    {
        return array(
            array('allow',  // allow all users to perform 'index' and 'view' actions
                'actions'=>array('index','view','areg','dclaim'),
                'users'=>array('*'),
            ),
            array('allow', // allow authenticated user to perform 'create' and 'update' actions
                'actions'=>array('admin','create','update'),
                'users'=>array('@'),
            ),
            array('allow', // allow admin user to perform 'admin' and 'delete' actions
                'actions'=>array('delete'),
                'users'=>array('admin'),
            ),
            array('deny',  // deny all users
                'users'=>array('*'),
            ),
        );
    }

Now, the requirement fulfilled up to entry level. We need to treat update screen differently, i.e., in create action simply we defined the controls to be displayed based on selection. But in update screen the selection was done already we have to show them directly on loading the screen in addition to the above actions defined. i.e., if the user selected "regularized" column as yes and given application date.

So in update form (app_folder\protected\views\land\_updateform.php), note we have same as _createform but the div 'areg' is defined here.

<?php echo $form->dropDownList($model,'reg_applied',array('N'=>'NO','Y'=>'YES'),  
        array('prompt'=>'Select',                                                                                                      

                    'ajax'=>array(                                                                                                             
                      'type'=>'POST',                                                                                                         
                      'url'=>CController::createUrl('Land/areg',array('id'=>$model->id)),           
                      'update'=>'#areg',                                                                                                     
                ))); ?>                                                                                                                                 
        <?php echo $form->error($model,'
reg_applied'); ?>                                                        
<div id="areg">  
            <?php $stat=$model->reg_applied; ?>
    <?php if(strtoupper($stat)=='Y'){ ?>
    <table>
    <tr>
    <td rowspan="4"><b> If Yes (applied) - </b></td>
    <td><b>Date of application </b></td>
    <td>
    <?php
            $this->widget('zii.widgets.jui.CJuiDatePicker',array(
            'model'=>$model,
            'attribute'=>'app_dt',
            'value'=>date('Y-m-d',strtotime($model->app_dt)),
            'language'=>'en-AU',
            'options'=>array(
                'showAnim'=>'slide', //'slide','fold','slideDown','fadeIn','blind','bounce','clip','drop'
                    //    'showAnim'=>'slideDown',
                'showHour'=>false,
                'showMinute'=>false,
                'showTime'=>false,
                'changeMonth'=>true,
                'changeYear'=>true,
                'dateFormat'=>'yy-mm-dd',
                'timeFormat'=>'',
                'showButtonPanel'=>true,
            ),
            'htmlOptions'=>array(  
            'style'=>'height:20px;'
        ),
        ));
        ?>
    </td>

<td><b>Depreciation Claimed</b></td>
<td>
            <?php echo $form->dropDownList($model,'dclaimed',
                    array('N'=>'NO','Y'=>'YES'),
                    array('ajax'=>array(
                      'type'=>'POST',
                      'url'=>CController::createUrl('Land/dclaim',array('id'=>$model->id)),
                      'update'=>'#dclaim',
                    ))
                    );?>
    </td>

</table>   
<?php } // End of condition ?>                                         
 </div> 

I have shown a example, similarly we have to do for "Depreciation Claimed" condition also. Otherwise the controls shown in ajax action only, but if in create action user have already given the date, etc., so before giving him/her provision to update we need to show them in the screen.

Hope this post is useful