Strange session termination

I use testdrive application with the following modifications

  1. I have all tables in InnoDB

  2. I added a number of models and controllers and views using crud command

  3. I've changed UserIdentity to the following:

<?php





/**


 * UserIdentity represents the data needed to identity a user.


 * It contains the authentication method that checks if the provided


 * data can identity the user.


 */


class UserIdentity extends CUserIdentity


{


	protected $_id;


	/**


	 * Validates the username and password.


	 * This method should check the validity of the provided username


	 * and password in some way. In case of any authentication failure,


	 * set errorCode and errorMessage with appropriate values and return false.


	 * @param string username


	 * @param string password


	 * @return boolean whether the username and password are valid


	 */


	public function authenticate()


    {


        $record=User::model()->findByAttributes(array('username'=>$this->username));


        if($record === null)


            $this->errorCode=self::ERROR_USERNAME_INVALID;


        else if($record->password !== md5($this->password))


            $this->errorCode=self::ERROR_PASSWORD_INVALID;


        else


        {


            $this->_id = $record->userID;


        	$this->errorCode=self::ERROR_NONE;


        }


        return !$this->errorCode;


    }


    


    public function getId()


    {


    	if (empty($this->_id)) return $this->username;


    	return $this->_id;


    }


    


    public function setId($id)


    {


    	$this->_id = $id;


    }


}

(I want Yii::app()->user->getId() method to return primary key, not username)

Now I log in, then go to the index.php?r=category (category controller used fur crud operations on Category table (see below))

Then go to category/create

it brings me the form with name, clicks number and gender.

I can't put anything to the gender field, but that's not  problem, I know how to fix this.

So, I out category name, number of cliks and press "create", but instead of creating record, it takes me to the login page!

Whe I log in, everything is the same - when clicking "create" it takes me to the login page and terminates the session.

Why???

At the same time, if I do THE SAME for shop or tag controllers - everything goes well!

Here is code (sorry for posting so much):

  1. CategoryController
<?php





class CategoryController extends CController


{


	/**


	 * @var string specifies the default action to be 'list'.


	 */


	public $defaultAction='list';





	/**


	 * Specifies the action filters.


	 * This method overrides the parent implementation.


	 * @return array action filters


	 */


	public function filters()


	{


		return array(


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


		);


	}





	/**


	 * Specifies the access control rules.


	 * This method overrides the parent implementation.


	 * It is only effective when 'accessControl' filter is enabled.


	 * @return array access control rules


	 */


	public function accessRules()


	{


		return array(


			array('deny',  // deny access to CUD for guest users


				'actions'=>array('create','update','delete'),


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


			),


		);


	}





	/**


	 * Lists all categorys.


	 */


	public function actionList()


	{


		$pages=$this->paginate(Category::model()->count());


		$categoryList=Category::model()->findAll($this->getListCriteria($pages));





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


			'categoryList'=>$categoryList,


			'pages'=>$pages));


	}





	/**


	 * Shows a particular category.


	 */


	public function actionShow()


	{


		$this->render('show',array('category'=>$this->loadCategory()));


	}





	/**


	 * Creates a new category.


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


	 */


	public function actionCreate()


	{


		$category=new Category;


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


		{


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


				$category->setAttributes($_POST['Category']);


			if($category->save())


				$this->redirect(array('show','id'=>$category->categoryID));


		}


		$this->render('create',array('category'=>$category));


	}





	/**


	 * Updates a particular category.


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


	 */


	public function actionUpdate()


	{


		$category=$this->loadCategory();


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


		{


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


				$category->setAttributes($_POST['Category']);


			if($category->save())


				$this->redirect(array('show','id'=>$category->categoryID));


		}


		$this->render('update',array('category'=>$category));


	}





	/**


	 * Deletes a particular category.


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


	 */


	public function actionDelete()


	{


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


		{


			// we only allow deletion via POST request


			$this->loadCategory()->delete();


			$this->redirect(array('list'));


		}


		else


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


	}





	/**


	 * Loads 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.


	 */


	protected function loadCategory()


	{


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


			$category=Category::model()->findbyPk($_GET['id']);


		if(isset($category))


			return $category;


		else


			throw new CHttpException(500,'The requested category does not exist.');


	}





	/**


	 * @param CPagination the pagination information


	 * @return CDbCriteria the query criteria for Category list.


	 * It includes the ORDER BY and LIMIT/OFFSET information.


	 */


	protected function getListCriteria($pages)


	{


		$criteria=Yii::createComponent('system.db.schema.CDbCriteria');


		$columns=Category::model()->tableSchema->columns;


		if(isset($_GET['sort']) && isset($columns[$_GET['sort']]))


		{


			$criteria->order=$columns[$_GET['sort']]->rawName;


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


				$criteria->order.=' DESC';


		}


		$criteria->limit=$pages->pageSize;


		$criteria->offset=$pages->currentPage*$pages->pageSize;


		return $criteria;


	}





	/**


	 * Generates the header cell for the specified column.


	 * This method will generate a hyperlink for the column.


	 * Clicking on the link will cause the data to be sorted according to the column.


	 * @param string the column name


	 * @return string the generated header cell content


	 */


	protected function generateColumnHeader($column)


	{


		$params=$_GET;


		if(isset($params['sort']) && $params['sort']===$column)


		{


			if(isset($params['desc']))


				unset($params['desc']);


			else


				$params['desc']=1;


		}


		else


		{


			$params['sort']=$column;


			unset($params['desc']);


		}


		$url=$this->createUrl('list',$params);


		return CHtml::link(Category::model()->getAttributeLabel($column),$url);


	}


}


  1. Category model
<?php





class Category extends CActiveRecord


{


	/**


	 * Returns the static model of the specified AR class.


	 * This method is required by all child classes of CActiveRecord.


	 * @return CActiveRecord 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 'Category';


	}





	/**


	 * @return array validation rules for model attributes.


	 */


	public function rules()


	{


		return array(


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


			array('name, clicksNum, gender', 'required'),


			array('clicksNum', 'numerical', 'integerOnly'=>true),


		);


	}








	// -----------------------------------------------------------


	// Uncomment the following methods to override them if needed


	


	public function relations()


	{


		return array(


			'sizes'=>array(self::MANY_MANY, 'SizeCategory', 'CategorySizeCategory(categoryID, sizeCategoryID)', 'order' => 'sizeCategory'),


			'products'=>array(self::HAS_MANY , 'Product', 'categoryID', 'order' => 'name'),


			'tags'=>array(self::HAS_MANY , 'CategoryTag', 'categoryID', 'order' => '??.clicksNum', 'limit' => Yii::app()->params['maxCategoryTags']),


			'productsNum'=>array(self::HAS_MANY , 'Product', 'categoryID', 'select' => 'count(??.productID)'),


		);


	}





	/*public function attributeLabels()


	{


		return array(


			'authorID'=>'Author',


		);


	}





	public function protectedAttributes()


	{


		return array();


	}


	*/


}
  1. SHOW CREATE TABLE Category:
CREATE TABLE `Category` (


 `categoryID` int(5) NOT NULL AUTO_INCREMENT,


 `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,


 `clicksNum` int(11) NOT NULL DEFAULT '0',


 `gender` enum('male','female','boys','girls') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'female',


 PRIMARY KEY (`categoryID`)


) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
  1. TagController
<?php





class TagController extends CController


{


	/**


	 * @var string specifies the default action to be 'list'.


	 */


	public $defaultAction='list';





	/**


	 * Specifies the action filters.


	 * This method overrides the parent implementation.


	 * @return array action filters


	 */


	public function filters()


	{


		return array(


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


		);


	}





	/**


	 * Specifies the access control rules.


	 * This method overrides the parent implementation.


	 * It is only effective when 'accessControl' filter is enabled.


	 * @return array access control rules


	 */


	public function accessRules()


	{


		return array(


			array('deny',  // deny access to CUD for guest users


				'actions'=>array('create','update','delete'),


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


			),


		);


	}





	/**


	 * Lists all tags.


	 */


	public function actionList()


	{


		$pages=$this->paginate(Tag::model()->count());


		$tagList=Tag::model()->findAll($this->getListCriteria($pages));





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


			'tagList'=>$tagList,


			'pages'=>$pages));


	}





	/**


	 * Shows a particular tag.


	 */


	public function actionShow()


	{


		$this->render('show',array('tag'=>$this->loadTag()));


	}





	/**


	 * Creates a new tag.


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


	 */


	public function actionCreate()


	{


		$tag=new Tag;


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


		{


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


			{


				$tag->setAttributes($_POST['Tag']);


				$tag->dtAdded = date('Y-m-d H:i:s');


				$tag->userID = Yii::app()->user->getId();


			}


			if($tag->save())


				$this->redirect(array('show','id'=>$tag->tagID));


		}


		$this->render('create',array('tag'=>$tag));


	}





	/**


	 * Updates a particular tag.


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


	 */


	public function actionUpdate()


	{


		$tag=$this->loadTag();


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


		{


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


				$tag->setAttributes($_POST['Tag']);


			if($tag->save())


				$this->redirect(array('show','id'=>$tag->tagID));


		}


		$this->render('update',array('tag'=>$tag));


	}





	/**


	 * Deletes a particular tag.


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


	 */


	public function actionDelete()


	{


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


		{


			// we only allow deletion via POST request


			$this->loadTag()->delete();


			$this->redirect(array('list'));


		}


		else


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


	}





	/**


	 * Loads 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.


	 */


	protected function loadTag()


	{


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


			$tag=Tag::model()->findbyPk($_GET['id']);


		if(isset($tag))


			return $tag;


		else


			throw new CHttpException(500,'The requested tag does not exist.');


	}





	/**


	 * @param CPagination the pagination information


	 * @return CDbCriteria the query criteria for Tag list.


	 * It includes the ORDER BY and LIMIT/OFFSET information.


	 */


	protected function getListCriteria($pages)


	{


		$criteria=Yii::createComponent('system.db.schema.CDbCriteria');


		$columns=Tag::model()->tableSchema->columns;


		if(isset($_GET['sort']) && isset($columns[$_GET['sort']]))


		{


			$criteria->order=$columns[$_GET['sort']]->rawName;


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


				$criteria->order.=' DESC';


		}


		$criteria->limit=$pages->pageSize;


		$criteria->offset=$pages->currentPage*$pages->pageSize;


		return $criteria;


	}





	/**


	 * Generates the header cell for the specified column.


	 * This method will generate a hyperlink for the column.


	 * Clicking on the link will cause the data to be sorted according to the column.


	 * @param string the column name


	 * @return string the generated header cell content


	 */


	protected function generateColumnHeader($column)


	{


		$params=$_GET;


		if(isset($params['sort']) && $params['sort']===$column)


		{


			if(isset($params['desc']))


				unset($params['desc']);


			else


				$params['desc']=1;


		}


		else


		{


			$params['sort']=$column;


			unset($params['desc']);


		}


		$url=$this->createUrl('list',$params);


		return CHtml::link(Tag::model()->getAttributeLabel($column),$url);


	}


}


  1. Tag model
<?php





class Tag extends CActiveRecord


{


	/**


	 * Returns the static model of the specified AR class.


	 * This method is required by all child classes of CActiveRecord.


	 * @return CActiveRecord 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 'Tag';


	}





	/**


	 * @return array validation rules for model attributes.


	 */


	public function rules()


	{


		return array(


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


			array('text, dtAdded, userID, clicksNum, isCategory', 'required'),


			array('userID, clicksNum, isCategory', 'numerical', 'integerOnly'=>true),


		);


	}








	// -----------------------------------------------------------


	// Uncomment the following methods to override them if needed


	/*


	public function relations()


	{


		return array(


			'author'=>array(self::BELONGS_TO, 'User', 'author_id'),


			'comments'=>array(self::HAS_MANY, 'Comment', 'post_id', 'with'=>'author', 'order'=>'create_time DESC'),


			'tags'=>array(self::MANY_MANY, 'Tag', 'post_tag(post_id, tag_id)', 'order'=>'name'),


		);


	}





	public function attributeLabels()


	{


		return array(


			'authorID'=>'Author',


		);


	}





	public function protectedAttributes()


	{


		return array();


	}


	*/


}
  1. SHOW CREATE TABLE Tag:
 	CREATE TABLE `Tag` (


 `tagID` int(11) NOT NULL AUTO_INCREMENT,


 `text` varchar(100) COLLATE utf8_unicode_ci NOT NULL,


 `dtAdded` datetime NOT NULL,


 `userID` int(11) NOT NULL,


 `clicksNum` int(11) NOT NULL DEFAULT '0',


 `isCategory` tinyint(4) NOT NULL DEFAULT '0',


 PRIMARY KEY (`tagID`),


 KEY `fk_Tag_User` (`userID`),


 CONSTRAINT `fk_Tag_User` FOREIGN KEY (`userID`) REFERENCES `User` (`userID`) ON DELETE NO ACTION ON UPDATE NO ACTION


) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Please help with this!

OK, I found the problem - that's relations!

If I comment out relations, CRUD works well…

But the questions remain:

  1. Why relations cause session termination??? If it's DB-related issue, there should be CDbException, but not session termination…

  2. How to avoid this? I need both good session control and relations…

No, using relation shouldn't cause session termination, because the relation code has nothing to do with session.

Could you first make sure the save() call works without problem (insert some die() statement before and after its call)?

Yes, but this may be causing some DB error and this leads to the session termination.

Anyway, I've updated "create" action for the CategoryTag controller:

public function actionCreate()


	{


		$categorytag=new CategoryTag;


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


		{


			echo 'POSTed';


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


			{


				echo 'setting attributes... ';


				$categorytag->setAttributes($_POST['CategoryTag']);


				echo 'done';


			}


			echo 'going to save... ';


			if($categorytag->save())


			{


				echo 'saved. Going to redirect... ';


				$this->redirect(array('show','id'=>$categorytag->categoryTagID));


				echo 'redirected';


			}


		}


		$this->render('create',array('categorytag'=>$categorytag));


	}

Here is what I have in the output:

POSTed

setting attributes… done

going to save…

And then it shows me PHP error:

Cannot modify header information - headers already sent by (output started at /usr/home/konstantin/TVSMedia/EveryStyle/testdrive/protected/controllers/CategoryTagController.php:68)

That's because my output prevented redirection with header tag.

So we have problem with save() method. It doesn't work with this record…

Any ideas how can I see what it's going to insert to the table? I only have the following in the log:

Quote

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "log" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "urlManager" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "request" application component

2008/12/05 13:32:18 [trace] [system.web.filters.CFilterChain] Running filter CategoryTagController.filteraccessControl()

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "user" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "session" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "db" application component

2008/12/05 13:32:18 [trace] [system.db.CDbCommand] query with SQL: SHOW COLUMNS FROM CategoryTag

2008/12/05 13:32:18 [trace] [system.db.CDbCommand] query with SQL: SHOW CREATE TABLE CategoryTag

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "coreMessages" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "clientScript" application component

2008/12/05 13:32:18 [trace] [system.base.CApplication] Loading "errorHandler" application component

By the way, session is not terminated, when I go to the categoryTag/create (manually typing in browser) - it still shows I'm logged in.

Here is model for the CategoryTag:

<?php





class CategoryTag extends CActiveRecord


{


	/**


	 * Returns the static model of the specified AR class.


	 * This method is required by all child classes of CActiveRecord.


	 * @return CActiveRecord 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 'CategoryTag';


	}





	/**


	 * @return array validation rules for model attributes.


	 */


	public function rules()


	{


		return array(


			array('text','length','max'=>55),


			array('categoryID, type, text, clicksNum, popularity', 'required'),


			array('categoryID', 'numerical', 'integerOnly'=>true),


			array('clicksNum, popularity', 'numerical'),


		);


	}








	// -----------------------------------------------------------


	// Uncomment the following methods to override them if needed


	


	public function relations()


	{


		return array(


			'products'=>array(self::MANY_MANY, 'Product', 'ProductCategoryTag(productID, categoryTagID)', 'order'=>'name'),


			'categories'=>array(self::BELONGS_TO , 'Category', 'categoryID', 'order'=>'name'),


		);


	}





	/*public function attributeLabels()


	{


		return array(


			'authorID'=>'Author',


		);


	}





	public function protectedAttributes()


	{


		return array();


	}


	*/


}

and DB scheme:

g  	CREATE TABLE `CategoryTag` (


 `categoryTagID` int(11) NOT NULL AUTO_INCREMENT,


 `categoryID` int(5) NOT NULL,


 `type` enum('fabric','style') COLLATE utf8_unicode_ci NOT NULL,


 `text` varchar(55) COLLATE utf8_unicode_ci NOT NULL,


 `clicksNum` bigint(20) NOT NULL,


 `popularity` float(2,1) NOT NULL,


 PRIMARY KEY (`categoryTagID`),


 KEY `fk_CategoryTag_Category` (`categoryID`),


 CONSTRAINT `fk_CategoryTag_Category` FOREIGN KEY (`categoryID`) REFERENCES `Category` (`categoryID`) ON DELETE NO ACTION ON UPDATE NO ACTION


) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Is this line executed: 'saved. Going to redirect… '

The header problem is because you are using "echo". You may use Yii::trace() to log those messages.

What is your log filter/category config? Complete logs should contain SQL statements executed.

No, that is not excecuted. Some error occurs in save() method and it makes Yii to redirect. Is that possible?

I know why header problem appears, I did that to prevent redirecting :)

I rewrote the method with tracing:

public function actionCreate()


	{


		$categorytag=new CategoryTag;


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


		{


			Yii::trace('POSTed', 'application.controllers.CategoryTagController');


//			echo 'POSTed';


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


			{


				Yii::trace('Setting attributes', 'application.controllers.CategoryTagController');


//				echo 'setting attributes... ';


				$categorytag->setAttributes($_POST['CategoryTag']);


//				echo 'done';


				Yii::trace('done', 'application.controllers.CategoryTagController');


			}


//			echo 'going to save... ';


			Yii::trace('going to save...', 'application.controllers.CategoryTagController');


			if($categorytag->save())


			{


//				echo 'saved. Going to redirect... ';


				Yii::trace('saved. going to redirect...', 'application.controllers.CategoryTagController');


				$this->redirect(array('show','id'=>$categorytag->categoryTagID));


//				echo 'redirected';


				Yii::trace('redirected', 'application.controllers.CategoryTagController');


			}


			else 


			{


				Yii::trace('saving error', 'application.controllers.CategoryTagController');


			}


		}


		$this->render('create',array('categorytag'=>$categorytag));


	}

This gives the following tracing:

Quote

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "log" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "urlManager" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "request" application component

2008/12/05 20:14:56 [trace] [system.web.filters.CFilterChain] Running filter CategoryTagController.filteraccessControl()

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "user" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "session" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "db" application component

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SHOW COLUMNS FROM CategoryTag

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SHOW CREATE TABLE CategoryTag

2008/12/05 20:14:56 [trace] [application.controllers.CategoryTagController] POSTed

2008/12/05 20:14:56 [trace] [application.controllers.CategoryTagController] Setting attributes

2008/12/05 20:14:56 [trace] [application.controllers.CategoryTagController] done

2008/12/05 20:14:56 [trace] [application.controllers.CategoryTagController] going to save…

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "coreMessages" application component

2008/12/05 20:14:56 [trace] [application.controllers.CategoryTagController] saving error

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "clientScript" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "log" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "urlManager" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "request" application component

2008/12/05 20:14:56 [trace] [system.web.filters.CFilterChain] Running filter CategoryTagController.filteraccessControl()

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "user" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "session" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "log" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "urlManager" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "request" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "coreMessages" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "clientScript" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "user" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "session" application component

2008/12/05 20:14:56 [trace] [system.base.CApplication] Loading "db" application component

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SHOW COLUMNS FROM Shop

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SHOW CREATE TABLE Shop

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SELECT COUNT(*) FROM Shop

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SELECT * FROM Shop ORDER BY viewsNum DESC

2008/12/05 20:14:56 [trace] [system.db.CDbCommand] query with SQL: SELECT tagID, text, clicksNum FROM Tag ORDER BY text LIMIT 0,50

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "log" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "urlManager" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "request" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "coreMessages" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "clientScript" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "user" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "session" application component

2008/12/05 20:14:57 [trace] [system.base.CApplication] Loading "db" application component

2008/12/05 20:14:57 [trace] [system.db.CDbCommand] query with SQL: SHOW COLUMNS FROM Shop

2008/12/05 20:14:57 [trace] [system.db.CDbCommand] query with SQL: SHOW CREATE TABLE Shop

2008/12/05 20:14:57 [trace] [system.db.CDbCommand] query with SQL: SELECT COUNT(*) FROM Shop

2008/12/05 20:14:57 [trace] [system.db.CDbCommand] query with SQL: SELECT * FROM Shop ORDER BY viewsNum DESC

2008/12/05 20:14:57 [trace] [system.db.CDbCommand] query with SQL: SELECT tagID, text, clicksNum FROM Tag ORDER BY text LIMIT 0,50

It logged me out and brought to the login page.

Seems there is an error happens in save() method, that  causes session temination. Or some error occurs, it refreshes page without preserving session and it is terminated… Not sure about that, I didn’t get onto Yii so deep :(

Since save() returns false (because you logged "saving error"), the redirection seems to be caused by render('create'). You may insert some die() statements in the view to see where it stops.  Could you show your 'create' view?

In case of an error/exception, Yii will call the error handler to display the error. It won't do redirection.

Here is the view, it is auto-generated one. Should be OK then…

<h2>New CategoryTag</h2>





<div class="actionBar">


[<?php echo CHtml::link('CategoryTag List',array('list')); ?>]


</div>





<div class="yiiForm">


<?php echo CHtml::form(); ?>





<?php echo CHtml::errorSummary($categorytag); ?>





<div class="simple">


<?php echo CHtml::activeLabel($categorytag,'categoryID'); ?>


<?php echo CHtml::activeTextField($categorytag,'categoryID'); ?>


</div>


<div class="simple">


<?php echo CHtml::activeLabel($categorytag,'type'); ?>


<?php echo CHtml::activeTextField($categorytag,'type',array('size'=>0,'maxlength'=>0)); ?>


</div>


<div class="simple">


<?php echo CHtml::activeLabel($categorytag,'text'); ?>


<?php echo CHtml::activeTextField($categorytag,'text',array('size'=>55,'maxlength'=>55)); ?>


</div>


<div class="simple">


<?php echo CHtml::activeLabel($categorytag,'clicksNum'); ?>


<?php echo CHtml::activeTextField($categorytag,'clicksNum'); ?>


</div>


<div class="simple">


<?php echo CHtml::activeLabel($categorytag,'popularity'); ?>


<?php echo CHtml::activeTextField($categorytag,'popularity'); ?>


</div>





<div class="action">


<?php echo CHtml::submitButton('Create'); ?>


</div>





</form>


</div><!-- yiiForm -->

Yes, I saw this behaviour before (about CDbException), so was very surprised with this. I looked into the save() code, but didn’t find any redirection :)

How this may be caused by standard view?

I've added tracing before and after rendering. It shows trace message before, butthen page is reloaded. You're right, it is caused by rendering view, but how?

What about the layout? Yes, it not very likely that a view will cause redirection.

As a matter of fact, inside Yii core code, only when you call Yii::app()->user->loginRequired(), a redirection will be triggered. Nothing else will cause the redirection unless you explicitly request so.

You've pushed me to the right direction!

When I removed XLoginPortlet from the layout, it goes well…

Strange, what may cause session errors in this portlet?

I've changed it a bit:

protected function renderContent()


	{


		$user=new XLoginForm($this->identityClass);


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


		{


			if (isset($_POST['XLoginForm']['login']))


			{


				$user->attributes=$_POST['XLoginForm'];


				if($user->validate() && $this->login($user))


					$this->controller->refresh();


			}


			elseif (isset($_POST['XLoginForm']['logout']))


			{


				$this->logout();


				$this->controller->refresh();


			}


		}


		if (Yii::app()->user->isGuest)


			$this->render('loginPortlet',array('user'=>$user));


		else 


		{


			$data = Yii::app()->cache->get('userData');


			if ($data === false)


			{


				$r = User::model()->findByPk(Yii::app()->user->getId());


//				$r = User::model()->findByAttributes(array('username' => Yii::app()->user->getId()));


				if ($r !== null)


					$data = $r->getAttributes();


				else 


					$data = array();


			}


			$this->render('loginPortletLogged', array('userData' => $data, 'user' => $user));


		}


	}

View with form:

<?php


echo CHtml::form('', 'post', array('id' => 'login')); 


echo CHtml::activeHiddenField($user, 'login', array('value' => 1)); 


?>


	<fieldset>


		<legend><strong>login <a href="#loginEnd" title="skip login form">[skip]</a></strong></legend>


		<div class="inputBox">


			<span class="boxTop"></span>


			<span class="boxBottom usrn">


				<?php echo CHtml::activeTextField($user, 'username', array(


					'class' => 'text',


					'onfocus' => "this.style.backgroundPosition='-200px'",


					'onblur' => "if(this.value==''){this.style.backgroundPosition='center left'}",


				));?>


			</span>


		</div>


		<div class="inputBox">


			<span class="boxTop"></span>


			<span class="boxBottom pswd">


				<?php echo CHtml::activePasswordField($user, 'password', array(


					'class' => 'text',


					'onfocus' => "this.style.backgroundPosition='-200px'",


					'onblur' => "if(this.value==''){this.style.backgroundPosition='center left'}",


				));?>


			</span>


		</div>


		<input type="submit" class="submit" value="Login" />


		<p><small><a href="">forgotten password</a> | <a href="">register now</a></small></p>


	</fieldset>


</form>


<span id="loginEnd"></span>

View for the logged panel:

<?php


echo $userData['username'];


echo CHtml::form();


echo CHtml::activeHiddenField($user, 'logout', array('value' => 1));


echo CHtml::submitButton('Logout');


?>

Any ideas what I'm doing wrong?

There are two refresh() calls inside the portlet. Check if any one of them is called.

Place some die() statements to see where causes the redirection.

Yeah, I did that and figured out, that clicking "create" button also submits the logout form! Logout form is processed by widget on any page, so it doesn't matter where I click "submit".

Why it happens from time to time? because render() is only called when save() method fails (blank field, for example)

So everything is clear now except one simple question - how Yii submits 2 forms at once and how to prevent this?

Check your page HTML source and make sure the form tags are well separated. Yii doesn't have the capability to submit two forms. You need to make sure each submit button is well enclosed in its own form.

Also, try to print_r($_POST) and see what are submitted.

Ah!!!

Shame on me! I'm developing web apps for 5 years and now I'm having trouble because I forgot to close <form> tag!

Thanks a lot for your help!

Glad to know the problem is solved.  ;)