Creating modules

If you have created a complex application part and want to use it with some degree of customization in your next project, most probably you need to create a module.

In this recipe we will see how to create a wiki module. For simplicity, we will not focus on the user and permissions management but will let everyone edit everything.

Getting ready

  1. Create a fresh Yii application using yiic webapp.
  2. Configure MySQL database and execute the following SQL:
    CREATE TABLE `wiki` (
      `id` varchar(255) NOT NULL,
      `text` text NOT NULL,
      PRIMARY KEY  (`id`)
    )
  3. Generate the Wiki model using Gii.
  4. Move protected/models/Wiki.php to protected/modules/wiki/models/.
  5. Add wiki to the modules section of protected/config/main.php:
    'modules'=>array(
      // uncomment the following to enable the Gii tool
      'gii'=>array(
    
        'class'=>'system.gii.GiiModule',
        'password'=>false,
      ),
      'wiki'
    ),

How to do it...

Let's do some planning first:

  • A wiki is a set of pages where one page can link to another using its name
  • Typically, wiki uses simpler human-readable markup instead of HTML
  • If a user goes to a page that doesn't yet exist, he's prompted to create one
  • To delete a page a user needs to save it with an empty body

Based on this planning we'll use markdown as the markup language. We will add a way to link to another page by name. Let's say it will be [[page name]] or [[Custom title|page name]] if you need a custom titled link.

  1. First, let's add wiki links to CMarkdownParser. Create protected/modules/wiki/components/WikiMarkdownParser.php:
    <?php
    class WikiMarkdownParser extends CMarkdownParser
    {
      public function transform($text)
      {
        $text = preg_replace_callback('~[[(.*?)(?:|(.*?))?]]~', array($this, 'processWikiLinks'), $text);
        return parent::transform($text);
      }
    
      protected function processWikiLinks($matches)
      {
        $page = $matches[1];
        $title = isset($matches[2]) ? $matches[2] : $matches[1];
        return CHtml::link(CHtml::encode($title), array(
          'view', 'id' => $page,
        ));
      }
    }
  2. Now, let's use it by adding the getHtml method to the protected/modules/wiki/models/Wiki.php model:
    public function getHtml()
    {
      $parser = new WikiMarkdownParser();
      return $parser->transform($this->text);
    }

    We're moving to customizing the protected/modules/wiki/controller/DefaultController.php controller. We'll need just two actions there: the view action and the edit action. Additionally, we'll create an index action that will just call view with id = index. Since we don't need a view for the index action, it can be deleted safely.

  3. Now, edit protected/modules/wiki/controller/DefaultController.php:
    class DefaultController extends Controller
    {
      public function actionIndex()
      {
        $this->actionView('index'),
      }
    
      public function actionView($id)
      {
        $model = Wiki::model()->findByPk($id);
        if(!$model)
        {
          $this->actionEdit($id);
          Yii::app()->end();
        }
    
        $this->render('view', array(
          'model' => $model,
        ));
      }
    
      public function actionEdit($id)
      {
        $model = Wiki::model()->findByPk($id);
        if(!$model)
        {
          $model = new Wiki();
          $model->id = $id;
        }
        if(!empty($_POST['Wiki']))
        {
          if(!empty($_POST['Wiki']['text']))
          {
            $model->text = $_POST['Wiki']['text'];
            if($model->save())
              $this->redirect(array('view', 'id' => $id));
          }
          else
          {
            Wiki::model()->deleteByPk($id);
          }
        }
    
        $this->render('edit', array(
          'model' => $model
        ));
      }
    }
  4. In addition, we will need two views. Create protected/modules/wiki/views/default/view.php:
    <h2>
      <?php echo CHtml::encode($model->id)?>
      [<?php echo CHtml::link('edit', array('edit', 'id' => $model->id))?>]
    </h2>
    <?php echo $model->html ?>
  5. Create another one, protected/modules/wiki/views/default/edit.php:
    <h2>Editing <?php echo CHtml::encode($model->id)?></h2>
    
    <?php echo CHtml::beginForm()?>
      <?php echo CHtml::activeTextArea($model, 'text', array('cols' => 100, 'rows' => 20))?>
      <br /><br />
      <?php echo CHtml::submitButton('Done')?>
    <?php echo CHtml::endForm()?>
  6. That's it. Now, run the wiki module and check it out by entering some text. Don't forget to add internal links such as [[rules]]:
    How to do it...
  7. The preceding page will look like the following screenshot when being edited:
    How to do it...
  8. Since we moved the Wiki model from application to module, the module doesn't have any dependencies on the application itself. So we can move it to an extension package such as protected/extensions/wiki/, changing the module configuration of protected/config/main.php to the following:
    'modules'=>array(
      // uncomment the following to enable the Gii tool
      'gii'=>array(
        'class'=>'system.gii.GiiModule',
        'password'=>false,
      ),
      'wiki'=>array(
        'class' => 'ext.wiki.WikiModule'
      ),
    ),

How it works...

Each module created contains a main module class such as WikiModule, where we can define configurable properties, define imports, change paths, attach controllers, and so on. By default, a module generated with Gii runs the index action of the default controller:

public function actionIndex()
{
  $this->actionView('index'),
}

In our wiki module index we are just calling the view action by passing id = index to it:

$model = Wiki::model()->findByPk($id);
if(!$model)
{
  $this->actionEdit($id);
  Yii::app()->end();
}

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

If there is a model with such an ID, we are displaying it using a view.

If there is no page with such an ID, we are, again, delegating processing to another action. This time it's edit:

$model = Wiki::model()->findByPk($id);
if(!$model)
{
  $model = new Wiki();
  $model->id = $id;
}

if(!empty($_POST['Wiki']))
{
  if(!empty($_POST['Wiki']['text']))
  {
    $model->text = $_POST['Wiki']['text'];
    if($model->save())
      $this->redirect(array('view', 'id' => $id));
  }
  else
  {
    Wiki::model()->deleteByPk($id);
  }
}

$this->render('edit', array(
  'model' => $model
));

If there is no model with an ID passed, we're creating a new one; if there is a model, we are editing it. Edit form data comes from POST and, if a text is empty, we are deleting a model. If there is a text, we are saving a model.

There's more...

There is a very flexible and configurable wiki module for Yii called Yeeki. It is still in development and is very good for learning about how to make a module really configurable and reusable:

https://github.com/samdark/Yeeki

To learn more about modules, refer to the following URLs:

See also

  • The Making extensions distribution-ready recipe
..................Content has been hidden....................

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