Problem submitting form

Hi all,

I’m new to Yii. Based on the examples in the book I’m trying to build a little app. I have successfully managed to connect to my table tbl_user and I can log in and log out.

Now I’m trying to update user information. I built a method actionUpdate in the controller User and a view file that loads the attached form. When clicking the submit button the page user/update gets reloaded. Values are not saved and the redirection to user/welcome does not occur. I put a “echo $model->getErrors();” right after “$this->redirect(array(‘user/welcome’));” and it returns an empty array.

It would be awesome and much appreciated if someone could help me as I’m a complete beginner. Thanks…

Here is the code:

Controller:




<?php


class UserController extends Controller

{

	/**

	 * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

	 * using two-column layout. See 'protected/views/layouts/column2.php'.

	 */

	public $layout='//layouts/column2';


	/**

	 * @return array action filters

	 */

	public function filters()

	{

		return array(

			'accessControl', // perform access control for CRUD operations

		);

	}


	/**

	 * Specifies the access control rules.

	 * This method is used by the 'accessControl' filter.

	 * @return array access control rules

	 */

	public function accessRules()

	{

		return array(

			array('allow',  // allow all users to perform 'index' and 'view' actions

				'actions'=>array('register'),

				'users'=>array('*'),

			),

			array('allow', // allow authenticated user to perform 'create' and 'update' actions

				'actions'=>array('welcome','update'),

				'users'=>array('@'),

			),

			array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('admin','delete'),

				'users'=>array('admin'),

			),

			array('deny',  // deny all users

				'users'=>array('*'),

			),

		);

	}


	/**

	 * Show welcome message after logging in

	 * @param integer $id the ID of the model to be displayed

	 */

	public function actionWelcome()

	{

                $this->render('welcome',array(

                        // get user id from application's parent class CWebUser and load all data for this record in $model->

			'model'=>$this->loadModel(Yii::app()->user->id),

			));

	}


	/**NOT IN USE

	 * Displays a particular model.

	 * @param integer $id the ID of the model to be displayed

	 */

	public function actionView($id)

        {

                $this->render('view',array(

                        'model'=>$this->loadModel($id),

                ));

        }


	 /**

	 * Creates a new model.

	 * If registration is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionRegister()

	{

		$model=new User;


		// Uncomment the following line if AJAX validation is needed

		$this->performAjaxValidation($model);


		if(isset($_POST['User']))

		{

			$model->attributes=$_POST['User'];

			if($model->save())

				// pass on registered=1 through URL for message "Thanks for registering" on login form

				// pass on email through URL for more convenient login on login form				

				$this->redirect(array('site/login','registered'=>'1','email'=>$model->email));				

		}


		$this->render('register',array(

			'model'=>$model,

		));

	}	




	 /**NOT IN USE

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate()

	{

		$model=new User;


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['User']))

		{

			$model->attributes=$_POST['User'];

			if($model->save())

				$this->redirect(array('view','id'=>$model->id));

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate()

	{

		$model=$this->loadModel(Yii::app()->user->id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['User']))

		{ 

			$model->attributes=$_POST['User'];

			if($model->save())

				$this->redirect(array('user/welcome'));

				echo $model->getErrors();

		}


		echo $model->getErrors();

		


		$this->render('update',array(

			'model'=>$this->loadModel(Yii::app()->user->id),

		));

	}


	/**NOT IN USE

	 * Deletes a particular model.

	 * If deletion is successful, the browser will be redirected to the 'index' page.

	 * @param integer $id the ID of the model to be deleted

	 */

	public function actionDelete($id)

	{

		if(Yii::app()->request->isPostRequest)

		{

			// we only allow deletion via POST request

			$this->loadModel($id)->delete();


			// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

			if(!isset($_GET['ajax']))

				$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

		}

		else

			throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

	}


	/**NOT IN USE

	 * Lists all models.

	 */

	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('User');

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

	}


	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

		$model=new User('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['User']))

			$model->attributes=$_GET['User'];


		$this->render('admin',array(

			'model'=>$model,

		));

	}


	/**

	 * Returns the data model based on the primary key given in the GET variable.

	 * If the data model is not found, an HTTP exception will be raised.

	 * @param integer the ID of the model to be loaded

	 */

	public function loadModel($id)

	{

		$model=User::model()->findByPk((int)$id);

		if($model===null)

			throw new CHttpException(404,'The requested page does not exist.');

		return $model;

	}


	/**

	 * Performs the AJAX validation.

	 * @param CModel the model to be validated

	 */

	protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}

}



Form:




<div class="form">


<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'user-form',

	'enableAjaxValidation'=>true,

)); ?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<?php echo $form->errorSummary($model); ?>


	<div class="row">

		<?php echo $form->labelEx($model,'tbl_salutation_id'); ?>

		<?php echo $form->dropDownList($model, 'tbl_salutation_id', CHtml::listData(UserSalutation::model()->findAll(), 'id', 'salutation'), array('prompt' => 'Select a salutation') ); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'first_name'); ?>

		<?php echo $form->textField($model,'first_name',array('size'=>45,'maxlength'=>45)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'last_name'); ?>

		<?php echo $form->textField($model,'last_name',array('size'=>45,'maxlength'=>45)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'address_1'); ?>

		<?php echo $form->textField($model,'address_1',array('size'=>45,'maxlength'=>45)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'address_2'); ?>

		<?php echo $form->textField($model,'address_2',array('size'=>45,'maxlength'=>45)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'city'); ?>

		<?php echo $form->textField($model,'city',array('size'=>45,'maxlength'=>45)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'postcode'); ?>

		<?php echo $form->textField($model,'postcode'); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'tbl_state_id'); ?>

		<?php echo $form->textField($model,'tbl_state_id'); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'phone'); ?>

		<?php echo $form->textField($model,'phone',array('size'=>15,'maxlength'=>15)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'email'); ?>

		<?php echo $form->textField($model,'email',array('size'=>60,'maxlength'=>100)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'password'); ?>

		<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>255)); ?>

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

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'tbl_user_interest_id'); ?>

		<?php echo $form->dropDownList($model, 'tbl_user_interest_id', CHtml::listData(UserInterest::model()->findAll(), 'id', 'interest'), array('prompt' => 'Select an interest') ); ?>

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

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

	</div>


<?php $this->endWidget(); ?>


</div><!-- form -->



Model:




<?php


/**

 * This is the model class for table "tbl_user".

 *

 * The followings are the available columns in table 'tbl_user':

 * @property integer $id

 * @property integer $tbl_salutation_id

 * @property string $first_name

 * @property string $last_name

 * @property string $address_1

 * @property string $address_2

 * @property string $city

 * @property integer $postcode

 * @property integer $tbl_state_id

 * @property string $phone

 * @property string $email

 * @property string $password

 * @property integer $tbl_user_interest_id

 * @property integer $tbl_user_role_id

 * @property string $created

 * @property string $modified

 *

 * The followings are the available model relations:

 * @property BuyerDocuments[] $buyerDocuments

 * @property UserInterest $tblUserInterest

 * @property UserRole $tblUserRole

 * @property State $tblState

 * @property UserSalutation $tblSalutation

 * @property SellerCompany[] $tblSellerCompanys

 */

class User extends CActiveRecord

{

	

	// for password repeat field, specific variable since this is no column in the table

	// for details check out Agile-Web-Application-Development-with-Yii11-and-PHP5-eBook09022011_1063898.pdf

	public $password_repeat;


	/**

	 * Returns the static model of the specified AR class.

	 * @return User the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_user';

	}

	

	// set created and modified row automatically

	public function behaviors(){

		return array(

			'CTimestampBehavior' => array(

				'class' => 'zii.behaviors.CTimestampBehavior',

				'createAttribute' => 'created',

				'updateAttribute' => 'modified',

			)

		);

	}	




	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

	

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			// password_repeat needs to be included for unknown reasons

			array('email, password, password_repeat, tbl_user_interest_id', 'required'),

			array('tbl_salutation_id, postcode, tbl_state_id, tbl_user_interest_id, tbl_user_role_id', 'numerical', 'integerOnly'=>true),

			array('first_name, last_name, address_1, address_2, city', 'length', 'max'=>45),

			array('phone', 'length', 'max'=>15),

			array('email', 'length', 'max'=>100),

			array('email', 'email'),			

			array('password', 'length', 'max'=>255),

			array('created, modified', 'safe'),

			// when registering set value to user role / permission (2 = registered user)			

			array('tbl_user_role_id','default',

			      'value'=>2,

			      'setOnEmpty'=>false,'on'=>'insert'),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('id, tbl_salutation_id, first_name, last_name, address_1, address_2, city, postcode, tbl_state_id, phone, email, password, tbl_user_interest_id, tbl_user_role_id, last_login, created, modified, $password_repeat', 'safe', 'on'=>'search'),

			// prevents fields from being set to NULL instead of empty			

			/*array('tbl_salutation_id, first_name, last_name, address_1, address_2, city, postcode, tbl_state_id, phone', 'default', 'setOnEmpty'=>true, 'value' => 'null'),*/

			// compares password with password_repeat

			// for details check out Agile-Web-Application-Development-with-Yii11-and-PHP5-eBook09022011_1063898.pdf

			array('password', 'compare'),			


		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'buyerDocuments' => array(self::HAS_MANY, 'BuyerDocuments', 'tbl_user_id'),

			'tblUserInterest' => array(self::BELONGS_TO, 'UserInterest', 'tbl_user_interest_id'),

			'tblUserRole' => array(self::BELONGS_TO, 'UserRole', 'tbl_user_role_id'),

			'tblState' => array(self::BELONGS_TO, 'State', 'tbl_state_id'),

			'tblSalutation' => array(self::BELONGS_TO, 'UserSalutation', 'tbl_salutation_id'),

			'tblSellerCompanys' => array(self::MANY_MANY, 'SellerCompany', 'tbl_user_has_tbl_seller_company(tbl_user_id, tbl_seller_company_id)'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'tbl_salutation_id' => 'Salutation',

			'first_name' => 'First Name',

			'last_name' => 'Last Name',

			'address_1' => 'Address 1',

			'address_2' => 'Address 2',

			'city' => 'City',

			'postcode' => 'Postcode',

			'tbl_state_id' => 'State',

			'phone' => 'Phone',

			'email' => 'Email',

			'password' => 'Password',

			'tbl_user_interest_id' => 'Interested in',

			'tbl_user_role_id' => 'Role',

			'created' => 'Created',

			'modified' => 'Modified',

			'last_login' => 'Last time logged in',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('tbl_salutation_id',$this->tbl_salutation_id);

		$criteria->compare('first_name',$this->first_name,true);

		$criteria->compare('last_name',$this->last_name,true);

		$criteria->compare('address_1',$this->address_1,true);

		$criteria->compare('address_2',$this->address_2,true);

		$criteria->compare('city',$this->city,true);

		$criteria->compare('postcode',$this->postcode);

		$criteria->compare('tbl_state_id',$this->tbl_state_id);

		$criteria->compare('phone',$this->phone,true);

		$criteria->compare('email',$this->email,true);

		//$criteria->compare('password',$this->password,true);

		$criteria->compare('tbl_user_interest_id',$this->tbl_user_interest_id);

		$criteria->compare('tbl_user_role_id',$this->tbl_user_role_id);

		$criteria->compare('created',$this->created,true);

		$criteria->compare('modified',$this->modified,true);


		return new CActiveDataProvider(get_class($this), array(

			'criteria'=>$criteria,

		));

	}




	/**

	* perform one-way encryption on the password before we store it in

	the database

	*/

	protected function afterValidate()

	{

		parent::afterValidate();

		$this->password = $this->encrypt($this->password);

	}

	public function encrypt($value)

	{

		return md5($value);

	}


	

}



No way I’ll read this amount of code …

My guess is that it fails because the $model->save() fails the validation, try to print_r($_POST) as see if it all pass the rules

also check the response headers of the post, if it is "200 OK" or other

Another option is that you dont have access to perform the action you are trying

Thanks Gustavo. I made things simpler and only kept one field "first_name". Here is the output of the print_r function:

Output was:


Array

(

    [User] => Array

        (

            [first_name] => Michael

        )


    [yt0] => Save

)



Can the problem be in the controller?


	public function actionUpdate()

	{

		$model=$this->loadModel(Yii::app()->user->id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['User']))

		{ 

			$model->attributes=$_POST['User'];

			if($model->save())

				$this->redirect(array('user/welcome'));

				echo $model->getErrors();

		}


		echo $model->getErrors();

		


		$this->render('update',array(

			'model'=>$this->loadModel(Yii::app()->user->id),

		));

	}



Check the documentation for redirect - http://www.yiiframew…redirect-detail

As it says for the first parameter…

and you do not have parameters… just send a string… like:


$this->redirect('user/welcome');

Edit:

but before that… instead of the redirect try to put there a die(“OK”); statement so that you confirm that the save() was successful and that the problem is in the redirect (could be the validation ;) )

Thanks for this. I implemented your suggestions. Redirect works now but only with the die(“OK”); statement. Database still doesn’t get updated.

This is the controller code:




	public function actionUpdate()

	{

		$model=$this->loadModel(Yii::app()->user->id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['User']))

		{ 

			$model->attributes=$_POST['User'];

			if($model->save())

				die("OK");				

				$this->redirect('index.php?r=user/welcome');

				//echo $model->getErrors();

		}

		


		$this->render('update',array(

			'model'=>$this->loadModel(Yii::app()->user->id),

		));

	}

What to do next? Thanks for your help, much appreciated.




                        if($model->save())

                                die("OK");                              

                                $this->redirect('index.php?r=user/welcome');

                                //echo $model->getErrors();



should be




                        if($model->save()){

                                die("OK");                              

                                $this->redirect('index.php?r=user/welcome');

                       }




and it doesnt save probably because fail validation

Thanks, I changed accordingly. The save()) command was autocreated by the CRUDE operations creator. If I implement your code I don’t get redirected, the page simply reloads. With the original code I get redirected but the form doesn’t update. Do you have any other suggestions? Thx

As pointed out by this test… (and Gustavo already told you that)… the problem seems to be in the validation…

so

you have some rules… that are not met… and that’s why your data is not saved… and page not redirected…

The problem obviously is not the redirect. It is the save() that isn’t working working. Look at the code.


if($model->save())

   die("OK");                              

   $this->redirect('index.php?r=user/welcome');

   //echo $model->getErrors();

without the {}, it’s essentially doing this


if($model->save())

{

    die("OK");                              

}

$this->redirect('index.php?r=user/welcome');

//echo $model->getErrors();

As you can see, the die only happens if your save() is successful. The redirect will happen regardless.

I did glance at the original code and this looked a little off to me, but I could be wrong:

Model:


        public function rules() 

        { 

         

                ...

                        array('password', 'compare'),                    

                ...

                ); 

        } 



‘password’ is 'compare’d to what? I don’t anything with me right now, but this rule just looks wrong. Just a thought.

Jeff

Check the documentation for CComapreValidator - http://www.yiiframew…ompareValidator

Here is the important quote:

Thanks guys. As suggested by some of you, it had to do with password_repeat. It didn’t validate because I didn’t fill out the password_repeat field. But at the same time, no error message appeared despite having listed this field as a required field.

I guess this must have to do with the password_repeat field not being a field in the database but rather a variable declared in the AR model class as described in the Agile-Web-Application-Development-with-Yii11-and-PHP5 book.

The form works when using


$form->save(false);

But I guess it would be better to make password (and hence password_repeat) not a mandatory field when users update their information. How can I make a field mandatory in one view and not mandatory in another view by using the same model?

Thanks…

Found the solution with scenarios: http://www.yiiframework.com/forum/index.php?/topic/12229-best-way-to-implement-implicit-change-of-password-solved/