Highlighting code with Yii

If you are posting code, be it a company's internal wiki or a public developer's blog, it is always better to have the syntax highlighted, so users who read the code will feel comfortable. Yii has PEAR's Text_Highlighter code-highlighting class bundled. It is used to highlight Yii definitive guide examples, and we can use it to do the same for our application.

In this recipe, we will create a simple application that will allow for adding, editing, and viewing code snippets.

Getting ready

  1. Create a new application by using yiic webapp as described in the official guide at the following URL:

    http://www.yiiframework.com/doc/guide/en/quickstart.first-app

  2. Set up a database connection and create a table named snippet as follows:
    CREATE TABLE `snippet` (
      `id` int(11) unsigned NOT NULL auto_increment,
      `title` varchar(255) NOT NULL,
      `code` text NOT NULL,
      `html` text NOT NULL,
      `language` varchar(20) NOT NULL,
      PRIMARY KEY  (`id`)
    );
  3. Generate a Snippet model by using Gii.

How to do it...

  1. First, we will tweak the protected/models/Snippet.php model code. Change the rules method to the following:
    public function rules()
    {
       return array(
          array('title, code, language', 'required'),
          array('title', 'length', 'max'=>255),
          array('language', 'length', 'max' => 20),
       );
    }
  2. Add methods to the same Snippet model:
    protected function afterValidate()
    {
       $highlighter = new CTextHighlighter();
       $highlighter->language = $this->language;
       $this->html = $highlighter->highlight($this->code);
    
       return parent::afterValidate();
    }
    
    public function getSupportedLanguages()
    {
       return array(
          'php' => 'PHP',
          'css' => 'CSS',
          'html' => 'HTML',
          'javascript' => 'JavaScript',
       );
    }
  3. The model is ready. Now, we will create a controller. Therefore, create protected/controllers/SnippetController.php as follows:
    <?php
    class SnippetController extends CController
    {
       public function actionIndex()
       {
          $criteria = new CDbCriteria();
          $criteria->order = 'id DESC';
          $models = Snippet::model()->findAll($criteria);
          $this->render('index', array(
             'models' => $models,
          ));
       }
    
       public function actionView($id)
       {
          $model = Snippet::model()->findByPk($id);
          if(!$model)
             throw new CException(404);
    
          $this->render('view', array(
             'model' => $model,
          ));
       }
    
       public function actionAdd()
       {
          $model = new Snippet();
          $data = Yii::app()->request->getPost('Snippet'),
          if($data)
          {
             $model->setAttributes($data);
             if($model->save())
                $this->redirect(array('view', 'id' => $model->id));
          }
          $this->render('add', array(
             'model' => $model,
          ));
       }
    
       public function actionEdit($id){
          $model = Snippet::model()->findByPk($id);
          if(!$model)
             throw new CHttpException(404);
    
          $data = Yii::app()->request->getPost('Snippet'),
          if($data)
          {
             $model->setAttributes($data);
             if($model->save())
                $this->redirect(array('view', 'id' => $model->id));
          }
          $this->render('edit', array(
             'model' => $model,
          ));
       }
    }
  4. Now views; create protected/views/snippet/index.php as follows:
    <h2>Snippets</h2>
    <?php echo CHtml::link('Add snippet', array('add'))?>
    <ol>
    <?php foreach($models as $model):?>
       <li>
          <?php echo CHtml::link(
             CHtml::encode($model->title),
             array('view', 'id' => $model->id)
          )?>
       </li>
    <?php endforeach?>
    </ol>
  5. Create protected/views/snippet/view.php as follows:
    <h2><?php echo CHtml::link('Snippets', array('index'))?> → <?php 
         echo CHtml::encode($model->title)?>
    </h2>
    <?php echo CHtml::link('Edit', array
         ('edit', 'id' => $model->id))?>
    <div>
       <?php echo $model->html?>
    </div>
  6. Create protected/views/snippet/add.php as follows:
    <h2><?php echo CHtml::link('Snippets', array('index'))?> → Add 
       snippet
    </h2>
    <?php $this->renderPartial('_form', array('model' => $model))?>
  7. Create protected/views/snippet/edit.php as follows:
    <h2><?php echo CHtml::link('Snippets', array('index'))?> → Edit 
       snippet
    </h2>
    <?php $this->renderPartial('_form', array('model' => $model))?>
  8. Create protected/views/snippet/_form.php as follows:
    <?php echo CHtml::beginForm()?>
    <ul>
       <li>
          <?php echo CHtml::activeLabel($model, 'title')?>
          <?php echo CHtml::activeTextField($model, 'title')?>
       </li>
       <li>
          <?php echo CHtml::activeLabel($model, 'code')?>
          <?php echo CHtml::activeTextArea($model, 'code')?>
       </li>
       <li>
          <?php echo CHtml::activeLabel($model, 'language')?>
          <?php echo CHtml::activeDropDownList($model, 'language', $model->getSupportedLanguages())?>
       </li>
       <li>
          <?php echo CHtml::submitButton('Save')?>
       </li>
    </ul>
    <?php echo CHtml::endForm()?>
  9. That is it. Now, run the snippet controller and try creating code snippets, as shown in the following screenshot:
    How to do it...
  10. When it is viewed, it will look similar to the following screenshot:
    How to do it...

How it works...

The snippet model's function is used to store the code and snippet title. Additionally, we have added the html and language fields. The first one (html) is used to store HTML representing the highlighted code, while the language field is used for the snippet language (PHP, HTML, CSS, JavaScript, and so on). We need to store these, as we need them when we edit the snippet.

As we remove the safe rule from the Snippet model, we make title, code, and language as the required fields. There is no rule for html, which means that it cannot be set through the form directly.

The afterValidate method, as its name states, is executed after the validation gives us no errors. In this method we transform the code that is stored in the code field to HTML, representing the highlighted code in the html field by using the Yii's CTextHighlighter class and passing the language value to it.

Note

Note that you need to define CSS with php-hl-* classes defined to get highlighting. You can get the default style from framework/vendors/TextHighlighter/highlight.css.

The getSupportedLanguages function returns languages we want to support in the value-label array. We use this method in the snippet form.

There's more...

In order to learn more about code highlighting, you can use the following resources:

More code highlighters

If Text_Highlighter bundled with Yii does not fit your needs, there are many code highlighters available on the Internet. A few good examples are found at the following links:

See also

  • The Processing model fields with AR event-like methods recipe
  • The Applying markdown and HTML recipe
  • The Setting up an author automatically recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.34.87