Blog Tutorial -- Problem With Postcontroller.actionindex()

I am following along the blog tutorial (http://www.yiiframework.com/doc/blog/1.1/en/post.display) and just got stumped.

I notice when I implement the tutorial’s customized actionIndex() function in PostController.php:




	public function actionIndex()

	{

	    $criteria=new CDbCriteria(array(

	        'condition'=>'status='.Post::STATUS_PUBLISHED,

	        'order'=>'update_time DESC',

	        'with'=>'commentCount',

	    ));

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

	        $criteria->addSearchCondition('tags',$_GET['tag']);

	 

	    $dataProvider=new CActiveDataProvider('Post', array(

	        'pagination'=>array(

	            'pageSize'=>5,

	        ),

	        'criteria'=>$criteria,

	    ));

	 

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

	        'dataProvider'=>$dataProvider,

	    ));

	}



The /index.php/post page crashes at the zii widget call:




<?php

$this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$dataProvider,

	'itemView'=>'_view',

	'template' => '{items}\n{pager}',

));

?>



However, when I put the actionIndex() back to its original generated code, the crash doesn’t happen.




	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('Post');

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

			'dataProvider'=>$dataProvider,

		));

	}



So I am a bit stumped. I copied the actionIndex() coded exactly, is there something wrong with the CDbCriteria class? Or adding the tag functionality?

The comments section didn’t seem to cover this, searches came up dry, so any help?

What do you mean it crashes? What’s the error that you’re getting? The error and the stack trace should make the problem clearer.

Full error output of page /blog/index.php/post

Notice about half way through the mention of zii.widgets





CDbException


Relation "commentCount" is not defined in active record class "Post".


/opt/lampp/yii/yii-1.1.12.b600af/framework/db/ar/CActiveFinder.php(216)


204             // named scope

205             $scopes=array();

206             if(($pos=strpos($with,':'))!==false)

207             {

208                 $scopes=explode(':',substr($with,$pos+1));

209                 $with=substr($with,0,$pos);

210             }

211 

212             if(isset($parent->children[$with]) && $parent->children[$with]->master===null)

213                 return $parent->children[$with];

214 

215             if(($relation=$parent->model->getActiveRelation($with))===null)

216                 throw new CDbException(Yii::t('yii','Relation "{name}" is not defined in active record class "{class}".',

217                     array('{class}'=>get_class($parent->model), '{name}'=>$with)));

218 

219             $relation=clone $relation;

220             $model=CActiveRecord::model($relation->className);

221 

222             if($relation instanceof CActiveRelation)

223             {

224                 $oldAlias=$model->getTableAlias(false,false);

225                 if(isset($options['alias']))

226                     $model->setTableAlias($options['alias']);

227                 else if($relation->alias===null)

228                     $model->setTableAlias($relation->name);


Stack Trace

#0 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/db/ar/CActiveFinder.php(49): CActiveFinder->buildJoinTree(CJoinElement, "commentCount")

#1 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/db/ar/CActiveRecord.php(1543): CActiveFinder->__construct(Post, "commentCount")

#2 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CActiveDataProvider.php(179): CActiveRecord->count(CDbCriteria)

#3 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CDataProvider.php(193): CActiveDataProvider->calculateTotalItemCount()

#4 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CActiveDataProvider.php(129): CDataProvider->getTotalItemCount()

#5 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CDataProvider.php(137): CActiveDataProvider->fetchData()

#6 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/zii/widgets/CBaseListView.php(108): CDataProvider->getData()

#7 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/zii/widgets/CListView.php(182): CBaseListView->init()

#8 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CBaseController.php(148): CListView->init()

#9 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CBaseController.php(173): CBaseController->createWidget("zii.widgets.CListView", array("dataProvider" => CActiveDataProvider, "itemView" => "_view", "template" => "{items}\n{pager}"))

#10 	

–

 /opt/lampp/htdocs/blog/protected/views/post/index.php(28): CBaseController->widget("zii.widgets.CListView", array("dataProvider" => CActiveDataProvider, "itemView" => "_view", "template" => "{items}\n{pager}"))


23 <?php

24 $this->widget('zii.widgets.CListView', array(

25     'dataProvider'=>$dataProvider,

26     'itemView'=>'_view',

27     'template' => '{items}\n{pager}',

28 ));

29 ?>


#11 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CBaseController.php(127): require("/opt/lampp/htdocs/blog/protected/views/post/index.php")

#12 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CBaseController.php(96): CBaseController->renderInternal("/opt/lampp/htdocs/blog/protected/views/post/index.php", array("dataProvider" => CActiveDataProvider), true)

#13 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(870): CBaseController->renderFile("/opt/lampp/htdocs/blog/protected/views/post/index.php", array("dataProvider" => CActiveDataProvider), true)

#14 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(783): CController->renderPartial("index", array("dataProvider" => CActiveDataProvider), true)

#15 	

–

 /opt/lampp/htdocs/blog/protected/controllers/PostController.php(154): CController->render("index", array("dataProvider" => CActiveDataProvider))


149             'criteria'=>$criteria,

150         ));

151      

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

153             'dataProvider'=>$dataProvider,

154         ));

155     }

156     /**/

157     /** Generated Code

158      * Lists all models.

159      *


#16 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/actions/CInlineAction.php(50): PostController->actionIndex()

#17 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(309): CInlineAction->runWithParams(array())

#18 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/filters/CFilterChain.php(134): CController->runAction(CInlineAction)

#19 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/filters/CFilter.php(41): CFilterChain->run()

#20 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(1146): CFilter->filter(CFilterChain)

#21 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/filters/CInlineFilter.php(59): CController->filterAccessControl(CFilterChain)

#22 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/filters/CFilterChain.php(131): CInlineFilter->filter(CFilterChain)

#23 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(292): CFilterChain->run()

#24 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CController.php(266): CController->runActionWithFilters(CInlineAction, array("accessControl", "postOnly + delete"))

#25 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CWebApplication.php(283): CController->run("")

#26 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/web/CWebApplication.php(142): CWebApplication->runController("post")

#27 	

+

 /opt/lampp/yii/yii-1.1.12.b600af/framework/base/CApplication.php(162): CWebApplication->processRequest()

#28 	

–

 /opt/lampp/htdocs/blog/index.php(13): CApplication->run()


08 defined('YII_DEBUG') or define('YII_DEBUG',true);

09 // specify how many levels of call stack should be shown in each log message

10 defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);

11 

12 require_once($yii);

13 Yii::createWebApplication($config)->run();


2012-09-11 09:57:58 Apache/2.2.21 (Unix) DAV/2 mod_ssl/2.2.21 OpenSSL/1.0.0c PHP/5.3.8 mod_apreq2-20090110/2.7.1 mod_perl/2.0.5 Perl/v5.10.1 Yii Framework/1.1.12




When I change actionIndex() back to its original code, this never happens.

The error is:




Relation "commentCount" is not defined in active record class "Post".



Can you post your Post model?

Ohh hmm, you’re right it isn’t defined in my model\Post.php class. I will copy/paste it here and investigation too.




<?php


/**

 * This is the model class for table "{{post}}".

 *

 * The followings are the available columns in table '{{post}}':

 * @property integer $id

 * @property string $title

 * @property string $content

 * @property string $tags

 * @property integer $status

 * @property integer $create_time

 * @property integer $update_time

 * @property integer $author_id

 *

 * The followings are the available model relations:

 * @property Comment[] $comments

 * @property User $author

 */

class Post extends CActiveRecord

{

	const STATUS_DRAFT = 1;

	const STATUS_PUBLISHED = 2;

	const STATUS_ARCHIVED = 3;

	private $_oldTags;

	

	protected function beforeSave() {

		if (parent::beforeSave()) {

			if ($this->isNewRecord) {

				$this->create_time = $this->update_time = time();

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

			} else

				$this->update_time = time();

			

			return true;

		} else

			return false;

	}

	

	protected function afterSave() {

		parent::afterSave();

		Tag::model()->updateFrequency($this->_oldTags, $this->tags);

	}

	

	protected function afterFind() {

		parent::afterFind();

		$this->_oldTags = $this->tags;

	}

	

	/**

	 * Returns the static model of the specified AR class.

	 * @param string $className active record class name.

	 * @return Post 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 '{{post}}';

	}

	

	public function rules() {

		return array (

				array ('title, content, status', 'required'),

				array ('title', 'length', 'max' => 128),

				array ('status', 'in', 'range' => array(1,2,3)),

				array ('tags', 'match', 'pattern' => '/^[\w\s,]+$/',

						'message' => 'Tags can only contain word characters.'),

				array ('tags', 'noramlizeTags'),

	

				array('title, status', 'safe', 'on' => 'search'),

	

		);

	}

	

	/** Generated rules()

	 *

	 * @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(

			array('title, content, status, author_id', 'required'),

			array('status, create_time, update_time, author_id', 'numerical', 'integerOnly'=>true),

			array('title', 'length', 'max'=>128),

			array('tags', 'safe'),

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

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

			array('id, title, content, tags, status, create_time, update_time, author_id', 'safe', 'on'=>'search'),

		);

	}

	*/

	

	/**

	 * @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(

			'comments' => array(self::HAS_MANY, 'Comment', 'post_id'),

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

		);

	}


	/**

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

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'title' => 'Title',

			'content' => 'Content',

			'tags' => 'Tags',

			'status' => 'Status',

			'create_time' => 'Create Time',

			'update_time' => 'Update Time',

			'author_id' => 'Author',

		);

	}


	/**

	 * 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('title',$this->title,true);

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

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

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

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

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

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


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

	

	public function normalizeTags($attribute, $params) {

		$this->tags = Tag::array2string(array_unique(Tag::string2array($this->tags)));

	}

	

	public function getUrl() {

		return Yii::app()->createUrl('post/view', array(

				'id' => $this-id,

				'title' =>	$this->title,

			));	

	}

}



Edit:

Uh-Oh! Totally newbie mistake! I put the relations function in the wrong model. :(

See here: http://www.yiiframework.com/doc/blog/1.1/en/post.model#customizing-x-16x-method

It works now!