Kohana 3.1 Wiki Tutorial

Posted on May 9, 2011

In this tutorial you will learn how to create a simple wiki using the PHP framework Kohana version 3.1. Several years ago Siddharta Govindaraj created a screencast demonstrating how to create a wiki using Django, this is essentially the Kohana version of that. It covers using Kohana’s Routing, ORM and MVC systems. Full source code of the application is available on github.

The wiki application has 3 different pages:

  • /wiki/somepage/save – handles the saving of the page
  • /wiki/somepage/edit – displays a form that allows the user to edit the page
  • /wiki/somepage – displays the page

Configuration

We will be using the ORM module to query the database for our wiki pages so we must load it in the application/bootstrap.php file (Line ~99).

Kohana::modules(array(

	'database'   => MODPATH.'database',   // Database access
	'orm'        => MODPATH.'orm',        // Object Relationship Mapping

	));

We also need to specify our database configuration settings. This is done in application/config/database.php.

<?php

return array
  (
  	'default' => array
  	(
  		'type'       => 'mysql',
  		'connection' => array(
  			'hostname'   => '127.0.0.1',
  			'username'   => 'root',
  			'password'   => 'root',
  			'persistent' => FALSE,
  			'database'   => 'query7kwiki',
  		),
  		'table_prefix' => '',
  		'charset'      => 'utf8',
  		'caching'      => FALSE,
  		'profiling'    => TRUE,
  	),
  );

  ?>

Model

Compared to most ORMs (Django, Doctrine, Propel), Kohana’s ORM is relatively light. You don’t need to specify the fields of your table as the Kohana ORM doesn’t attempt to generate the tables for you. It simply maps attribute names of the model object to field names in the database table. Be sure to check the Kohana Documentation for a detailed explanation of the ORM.

application/classes/model/page.php

class Model_Page extends ORM
{

	protected $_table_name = 'page';

	public function rules()
	{
		return array(

			'title' => array(
						array('not_empty')
							)

		);
	}

}

Execute the following SQL:

CREATE TABLE `page` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL ,
`content` TEXT NOT NULL
) ENGINE = MYISAM ;

Routing

I define all routes at the bottom of application/bootstrap.php, however if you are working on a large application it may beneficial in the long run to define them in a separate file and then include them into the bootstrap file.

Route::set() accepts 2 parameters. The first is the name of the route and the second is the URI pattern it should match. Because Route::set() returns an instance of Kohana_Route, we can chain the defaults method onto it. There we specify the controller and action that should be executed if the route is matched.

The <page> section of the URI pattern is captured from the URI and automatically passed to the controller method as an argument.

Route::set('wiki-edit', 'wiki/<page>/edit')
	->defaults(array(
		'controller'=> 'wiki',
		'action'	=> 'edit_page',
	));

Route::set('wiki-save', 'wiki/<page>/save')
	->defaults(array(
		'controller'=> 'wiki',
		'action'	=> 'save_page',
	));

Route::set('wiki-page', 'wiki/<page>')
	->defaults(array(
		'controller'=> 'wiki',
		'action'	=> 'view_page',
	));

Route::set('default', 'wiki')
	->defaults(array(
		'controller' => 'wiki',
		'action'     => 'view_page',
		'id'		 => 'index',
	));

Views

Read this tutorial on generating domain-independent, non hardcoded URLs

application/views/single.php

<html>
	<head>
		<title><?php echo $page; ?></title>
	</head>

	<body>

		<h1><?php echo $page; ?></h1>
		<p>
			<?php echo $content; ?>
		</p>
		<hr>
		<p>
			<a href="/query7kwiki/index.php/wiki/<?php echo $page; ?>/edit">Edit</a>
		</p>
	</body>
</html>

application/views/create.php

<html>
	<head>
		<title><?php echo $page; ?> - Create</title>
	</head>

	<body>

		<h1><?php echo $page; ?></h1>
		<p>This page does not exist. <a href="/query7kwiki/index.php/wiki/<?php echo $page; ?>/edit/">Create?</a></p>

	</body>
</html>

application/views/edit.php

<html>
	<head>
		<title><?php echo $page; ?> - Edit</title>
	</head>

	<body>

		<h1><?php echo $page; ?> - Edit</h1>
		<p>
			<form method="POST" action="/query7kwiki/index.php/wiki/<?php echo $page; ?>/save/"">

				<textarea rows="10" cols="60" name="content"><?php echo $content; ?></textarea>
				<br />
				<input type="submit" value="Edit Page" name="submit">
			</form>
		</p>
	</body>
</html>

Controller

The wiki only has one controller, Controller_Wiki, located in application/classes/controller/wiki.php. All of the methods accept one parameter, the name of the page which is automatically passed by the URL Router.

The action_view_page() method will display the wiki page if it exists or a ‘create’ page if it does not exist. $single->loaded() will return true if the ORM returned a result, so if the page exists we load the ‘single’ view and attach the appropriate variables to the view, if it does not exist then we load the ‘create’ view.

public function action_view_page($page)
{

	$single = ORM::factory('page')
			->where('title', '=', $page)
			->find();

	if($single->loaded())
	{
		$v = View::factory('single');
		$v->page = $page;
		$v->content = $single->content;
				}
	else
	{
		$v = View::factory('create');
		$v->page = $page;
	}

	$this->response->body($v);

}

action_edit_page() returns the ‘edit’ page with the correct content field.

public function action_edit_page($page)
{
	$single = ORM::factory('page')
			->where('title', '=', $page)
			->find();

	if($single->loaded())
	{
		$content = $single->content;
	}
	else
	{
		$content = '';
	}

	$v = View::factory('edit');
	$v->page = $page;
	$v->content = $content;

	$this->response->body($v);
}

action_save_page() handles saving the page after the user submits the edit form. It first checks to see if the page exists. If it does exist then we update the content attribute of the model with whatever was posted in the form. If it doesn’t exist then we make a new page by instantiating a new model, assigning the title and content attributes and saving it.

public function action_save_page($page)
{
	$single = ORM::factory('page')
			->where('title', '=', $page)
			->find();

	$content = $this->request->post('content');

	if($single->loaded())
	{
		$single->content = $content;
		$single->save();
	}
	else
	{
		$new_single = new Model_Page();
		$new_single->title = $page;
		$new_single->content = $content;
		$new_single->save();
	}

	$this->request->redirect('http://127.0.0.1/query7kwiki/index.php/wiki/' . $page);

}

Full source code of the application is available on Github.

Leave a Reply

You must be logged in to post a comment.