Recent Blog Posts

Making your own portal widget with Yii

By Ronald van Belzen | April 30, 2013

As an example of how to make your own portlet let me show how I made a "recent comments" portlet for this blog.

The Blog tutorial shows a couple of excellent examples of how to make your own portlets, including how to make a recent comments portlet, but this one will be different. It will not just select to show the recent comments of the specified blog (multiple blogs can be defined, see the database schema in a previous post for reference). It will actually show the recently commented blog posts instead of the recent comments.

This is the code that I placed in "/protected/component":


class RecentComments extends CPortlet { 
  public $title='Recent Comments'; 
  public $blogId=0; 
  public $maxComments=10; 

  protected function renderContent() { 
    $criteria = new CDbCriteria; 
    $criteria->select = 'post_id, max( as id'; 
    $criteria->group = 'post_id'; 
    $criteria->condition = 'blog_id = ' . $this->blogId; 
    $criteria->order = 'MAX( DESC'; 
    $criteria->limit = $this->maxComments; 
    $models = Blogcomment::model()

    foreach($models as $model) { 
      $comment = BlogComment::model()->with('commentUser')->findByPk($model->id); 
      $post = BlogPost::model()->findByPk($model->post_id)->title; 
      $username = ($comment->commentUser)?$comment->commentUser->username:$comment->username;
      $link=CHtml::link(CHtml::encode($username) . ' ÔÇó ' . CHtml::encode($post), array('/blog/blogPost/view','id'=>$model->post_id,'#'=>'bottom')); 
      echo CHtml::tag('div', array('class'=>'recent',), $link) . PHP_EOL; 

The default value for $blogId will result in an empty portlet and portlets have the advantage of not being shown when they have no content.

The real work is contained in the criteria. Translated into a SQL statement it would read:

Syntax Highlighting in Yii

By Ronald van Belzen | April 29, 2013

Syntaxhighlighting is not difficult in Yii, but I was unable to find any examples on the web. CTextHighlighter is well documented, but a working example is sometimes helpful.

On my website I use the CKEditor with the help of the editMe extension to edit text. In the editor I enter the <pre> tag with the attribute "lang" to enclose code. For viewing the text I use the following jQuery script to change the displayed code:

function setSyntax(id) { 
  var content = $('#'+id).html(); 
  var lang = $('#'+id).attr('lang'); 
    url: url, 
    type: "POST", 
    dataType: "json", 
    data: {
      "id" : id, 
      "lang" : lang, 
      "content" : content 
    success: function(data){
    error: function(error){
      console.log("Error:"); console.log(error); 

  $('pre').each(function(n) { = 'code_'+n; 

The script reads all code enclosed inside <pre> tags and sends it to the server with Ajax calls. The returned content is used to replace the <pre> tags together with their content.

On the server side the controller action handles the request:

public function actionSyntax() { 
  $json = array(); 
  $json['id'] = $_POST['id']; 
  $language = $_POST['lang']; 
  $content = $_POST['content']; 
  $content = str_replace('<br>', '', $content); 
  $content = str_replace('<p>', '', $content); 
  $content = str_replace('&lt;', '<', $content); 
  $content = str_replace('&gt;', '>', $content); 
  $highlighter = new CTextHighlighter; 
  $highlighter->showLineNumbers = true; 
  $highlighter->language = $language; 
  $content = $highlighter->highlight($content); 
  $json['content'] = $content; 
  echo json_encode($json); 

After some cleaning up of the content it is CTextHighlighter that does the actual highlighting with "$highlighter->highlight($content)".

Automatic view counting in Yii

By Ronald van Belzen | April 28, 2013

A simple method to automatically count the number of times that an item has been viewed in Yii is with the aid of scenario's.

In the controller that accesses the model the scenario is set:

$model = BlogPost::model();
$model->scenario = 'view';

While in the model the afterFind() function is overwritten:

protected function afterFind() {
  if(self::model()->scenario == 'view') {
  return parent::afterFind();

Of course, model events that trigger upon saving need to take into account that in the scenario "view" the afterFind event performs a save.