Saturday, October 16, 2010

Lesson 1 - Getting started

Let's get started with the site. This is roughly the structure we are looking for:

First let's configure our application. Kohana's configuration file is located in application/bootstrap.php



The file contains several sections. First are the configurations for the php environment. Set them according to your server configuration. I'll leave the rest untouched for now and will change only the default controller to news as this will be my default controller for this application.

Now the section looks like that:
/**
 * Set the routes. Each route must have a minimum of a name, a URI and a set of
 * defaults for the URI.
 */
Route::set('default', '((/(/)))')
 ->defaults(array(
  'controller' => 'news',
  'action'     => 'index',
 ));

Next I'll enable the .htaccess file. Kohana comes with default .htaccess which is located in the root directory of the framewark and is called example.htaccess

First let's create default controller, which will handle all the template rendering for us:

application/classes/controller/defaulttemplate.php
<?php
defined('SYSPATH') or die('No direct script access.');
/**
 * Description of defaulttemplate
 *
 * @author aquilax
 */
class Controller_DefaultTemplate extends Controller_Template {

  //The webpage title
  private $site_title = 'Kohana Hacker News';
  
  //The default template
  public $template = 'templates/default_tpl';

  //This variable will hold the data passed to the views
  public $data = array();

  public function before() {
    parent::before();

    if($this->auto_render) {
      $this->template->title            = '';
      $this->template->meta_keywords    = '';
      $this->template->meta_description = '';
      $this->template->meta_copywrite   = '';
      $this->template->content          = '';
    }
  }

  public function after() {
    /*
     * Set the page title to $site_title if title is not set,
     * otherwise create title 'path'
     */
    if ($this->template->title){
      $this->template->title = $this->template->title.' » '.$this->site_title;
    } else {
      $this->template->title = $this->site_title;
    }
    parent::after();
  }

  public function render($template = FALSE, $view = FALSE){
    /*
     * Force specific template
     */
    if ($template){
      $this->template = $template;
    }
    /*
     * Use default view logic if $view is not forced
     */
    if (!$view){
      $view = 'pages/'.$this->request->controller.'/'.$this->request->action.'_tpl';
    }
    $this->template->content = View::factory($view, $this->data);
  }
}
?>

Also the news controller:

application/classes/controller/news.php
<?php
/**
 * Description of news
 *
 * @author aquilax
 */
class Controller_News extends Controller_DefaultTemplate{

  public function  __construct($request) {
    parent::__construct($request);
  }

  public function action_index(){
    $this->render();
  }
}
?>

What remains is to create our views structure. Create the following directories in application/views:

application/views/blocks - will contain the partial elements and reusable blocks
application/views/pages - will contain the page views
application/views/templates - - will contain the page templates

We may create perfectly usable webpage without such complex view structure, but this will make our web application easily maintainable.

Now let's populate the directories:
This will be our default template:
application/views/templates/default_tpl.php
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title><?php echo $title ?></title>
  <meta name="description" content="<?php echo $meta_description ?>" />
  <meta name="KEYWORDS" content="<?php echo $meta_keywords ?>" />
  <link rel="stylesheet" href="/assets/css/style.css" type="text/css" />
</head>
<body>
  <div id="wrapper">
    <div id="header">
<?php echo View::factory('blocks/header_tpl')->render(); ?>
    </div>
    <div id="main">
<?php echo $content ?>
    </div>
    <div id="footer">
<?php echo View::factory('blocks/footer_tpl')->render(); ?>
    </div>
  </div>
</body>
</html>

It uses two block: views/blocks/header_tpl.php and views/blocks/footer_tpl.php which we will leave empty for now but make sure the files are created.

Now let's create the folder vews/pages/news/. Every controller with view will have it's own subdirectory in pages and the default view name for the corresponding action will be called [action_name]_tpl.php

In this case we want to create a view for the News controller's action index. The file will be:
views/pages/news/index_tpl.php
<?php
  echo 'First page content goes here';
?>

Now open http://knh.localhost/ and if everything is fine, should be able to see the "First page content goes here" message.

That was rather long and boring lesson but let's hope it will pay off.

The source code for this project can be found at: http://code.google.com/p/kohana-tutorial/

9 comments:

  1. I'm got error
    ErrorException [ Recoverable Error ]: Argument 1 passed to Kohana_Controller::__construct() must be an instance of Request, none given, called in D:\server\htdocs\wew\a\application\classes\controller\defaulttemplate.php on line 20 and defined

    can yiu tell me why?

    ReplyDelete
  2. Having a similar bug, is this tutorial incompatible with latest versions of Kohana?

    ReplyDelete
  3. Pass a request in through the constructor as well.

    ReplyDelete
  4. v3.2 requires a response object be passed to the controller constructor too:

    (in Controller_News)
    public function __construct($request, $response) {
    parent::__construct($request, $response);
    }

    ReplyDelete
  5. This was a horrible tutorial, I still don't know anything more about how Kohana works then before reading this "tutorial"...

    ReplyDelete
  6. kohana 3.3.0

    defaulttemplate.php
    $view = 'pages/'.$this->request->controller.'/'.$this->request->action.'_tpl';

    change to

    $view = 'pages/'.$this->request->controller().'/'.$this->request->action().'_tpl';

    AND

    news.php
    public function __construct($request) {
    parent::__construct($request);
    }

    change to

    public function __construct(\Request $request, \Response $response) {
    parent::__construct($request, $response);
    }

    ReplyDelete
  7. Don't listen to these people, I did what you said, looked at kabod's comment and it works fine. Thanks Kabod and to the author.

    ReplyDelete
  8. $this->template->title = 'Skunk Stoner > Welcome';
    $this->render();

    Isn't being pushed to the view template, because undefined title variable.. But da heck.. it's filled..

    ReplyDelete
  9. can show me your interface about this sample

    ReplyDelete