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.
yiic webapp
.CREATE TABLE `wiki` ( `id` varchar(255) NOT NULL, `text` text NOT NULL, PRIMARY KEY (`id`) )
Wiki
model using Gii.protected/models/Wiki.php
to protected/modules/wiki/models/
.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' ),
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.
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, )); } }
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.
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 )); } }
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 ?>
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()?>
wiki
module and check it out by entering some text. Don't forget to add internal links such as [[rules]]: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' ), ),
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 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:
3.15.219.217