Kohana: Buffering output on view and rendering it before in the source code

Sometimes you need to hack the order the source code is going to be rendered in a view:

– You want an extra piece of CSS that only aplies to that view, so you think it's not worth creating a single CSS file and including in your mashed file

– You need the same as above for javascript

– Your mind has not completely grasped the way to organize code in MVC  🙂

 

 

Here's a way to do it:

 

in your view you add something like this:

<?php View::start_buffer('head_end'); ?>
<style>
    ::-moz-selection {
        background: #b3d4fc;
        text-shadow: none;
    }

</style>
<?php  View::end_buffer('head_end'); ?>

 

Then, by taking advantage of the wonderful cascading file system that Kohana gives you, you create a View.php class in your application folder that will need to extend the render() function (I'm just adding the relevant changes for this to work; you can have your own extra sauce):

 

class View extends Kohana_View
{
    static public $buffers = array();

    public static function start_buffer($buffer_name)
    {
        self::$buffers[$buffer_name] = '';
        ob_start();
    }

    public static function end_buffer($buffer_name)
    {
        self::$buffers[$buffer_name] = ob_get_clean();
    }

    public function render($file = NULL)
    {
        $rendered = parent::render($file);

        if (! empty(self::$buffers['head_end']))
        {
            $rendered = str_replace('</head>', self::$buffers['head_end'] . '</head>', $rendered);
        }
        return $rendered;
    }

}

 

The buffer names are completely arbitrary, you can make them any way to want.

I leave up to you to improve the way each buffer will be mapped to different locations in the source code.

Drop me a line with your changes

Kohana 3.2.x: How to install taking advantage of submodules

I have improved my Kohana 3.2.x installation steps.

This new way takes advantages of submodules with Git thus making your life easier when upgrading to a new version, assuming it's backwards compatible.

This guide will assume you have the following structure for your website:

 

root/html   <!– public html folder

root/modules   <!– kohana files

root/source   <!– environment dependable files

 

 

Ready? here we go:

 

1. Create an empty git repository following this:

 

 

2. Create a submodule with Kohana's core using:

$ git submodule add git://github.com/kohana/core.git modules/system

 

3. Add all the modules you'll need:

$ git submodule add git://github.com/kohana/database.git modules/database

$ git submodule add git://github.com/kohana/image.git modules/image

$ git submodule add git://github.com/kohana/pagination.git modules/pagination

 

4. Initialize the submodules

 

$ git submodule init

Submodule 'modules/database' (git://github.com/kohana/database.git) registered for path 'modules/database'
Submodule 'modules/image' (git://github.com/kohana/image.git) registered for path 'modules/image'
Submodule 'modules/pagination' (git://github.com/kohana/pagination.git) registered for path 'modules/pagination'
Submodule 'modules/system' (git://github.com/kohana/core.git) registered for path 'modules/system'

 

5. Commit these changes

 


$ git commit -m 'Added initial submodules'
 
 

 

6. Create the bare minimum folder structure:
 
$ mkdir -p modules/application/classes/{controller,model}
$ mkdir -p modules/application/{config,views}
$ mkdir -p modules/application/{cache,logs}
$ chmod 0777 modules/application/{cache,logs}
$ echo '[^.]*' > modules/application/logs/.gitignore
$ echo '[^.]*' > modules/application/cache/.gitignore
 
 

7. Now we need index.php and bootstrap.php files:

$ mkdir html

$ wget http://github.com/kohana/kohana/raw/3.0/master/index.php -O html/index.php

$ wget http://github.com/kohana/kohana/raw/3.0/master/application/bootstrap.php -O modules/application/bootstrap.php

 

 

8. Fix file paths on html/index.php

<?php

 

$application = '../modules/application';
$modules = '../modules';
$system = '../modules/system';

 

9. Change the default timezone

<?php

date_default_timezone_set('America/Los_Angeles');

 

Kohana::init(array(
        'base_url'   => '/',
        'index_file' => '',
));
 
 

10. Add a default .htaccess

wget  https://raw.github.com/kohana/kohana/3.2/master/example.htaccess -O html/.htaccess

 

 

 

 

Kohana 3.2.6: Change Default Route

Let’s define a redirect module that will handle all requests that were not handled by any other controller. It will also be a good place to include a 404 page.

modules/application/bootstrap.php

Kohana::modules(array(
.
.
'redirect' => MODPATH . 'redirect', //Redirect module
.
.
));

Route::set('default', '(<request>)',
 array(
 'request' => '(.*)',
 ))
 ->defaults(array(
 'controller' => 'redirect',
 'action' => 'index',
 ));

 

And then define the controller itself:

modules/redirect/classes/controller/redirect.php

<?php defined('SYSPATH') or die('No direct script access.');
/**
 * Handles all the redirecions that may happen
 *
 * @package......Redirect
 * @category.....SEO
 * @author.......Mauricio Otta
 * @copyright....PortNumber53.com
 */

class Controller_Redirect extends Controller {

  static public function action_index() {
    echo "Controller_Redirect::action_index();<br />";
    echo Request::current()->param('request');
  }

}

 

 

 

Kohana 3.1.x: Common controller [step 2]

Define parent controller:

 

 

<?php defined('SYSPATH') or die('No direct script access.');

class Controller_Common_Content extends Controller_Template {

 public $template                = '';
 public $template_name           = 'default';
 public $layout                  = 'default';

 public $save_auto_render        = null;

 public $content                 = '{Do something to generate content}';

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

 $this->session = Session::instance();

 }

 public function before() {

 $this->save_auto_render = $this->auto_render;
 $this->auto_render = false;
 parent::before();
 $this->auto_render = $this->save_auto_render;

 if ($this->auto_render) {
 $this->template = View::factory('template/' . $this->template_name . '/' . $this->layout)
 ->bind('content', $this->content);

 }

 }

 public function action_view_html() {
 $path = $this->request->param('path');

 echo "PATH: $path";
 }

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

 if ($this->auto_render) {
 } else {
 $this->response->headers('content-type', 'application/json');
 echo json_encode($this->content);
 }

 }

}

 

 

 

 

Kohana 3.2.x: Master Template Controller [step 1]

Let's create a content module that will handle both static and dynamic content:

First enable the module:

modules/application/bootstrap.php

Kohana::modules(array(
.
.
'content' => MODPATH . 'content',   // Content module
.
.
));

 

Second, create the master template controller:

modules/content/classes/controller/base/template.php

template_name = Kohana::$config->load('content.template.name');
		$this->template = 'template/'.$this->template_name.'/index';
		parent::before();

		if ($this->auto_render) {
			$this->template->title		= '';
			$this->template->content	= '';

			$this->template->styles		= array();
			$this->template->scripts	= array();
		}

	}

	public function after() {
		if ($this->auto_render) {
			$styles = Kohana::$config->load('content.template.style');
			$scripts = Kohana::$config->load('content.template.script');

			$this->template->styles = array_merge( $this->template->styles, $styles );
			$this->template->scripts = array_merge( $this->template->scripts, $scripts );
		}
		parent::after();;
	}

}

 

Define routes to call the content module:

modules/content/init.php

<?php defined('SYSPATH') or die('No direct script access.');
 
/**
 * Routes for Content
 *
 * @package……Content
 * @category…..Routing
 * @author…….Mauricio Otta
 * @copyright….PortNumber53.com
 */
 
if (! Route::$cache) {
Route::set('homepage-content', '(<language–>"/)()',
array(
  'language' => '(pt-br)',
  'nothing' => '',
))
  ->defaults(array(
  'controller' => 'content',
  'action'     => 'homepage',
));

 Route::set('static-content', '(/).html',
  array(
   'language' => '(pt-br)',
   'path' => '[a-zA-Z0-9_/\.=\-]+',
  ))
  ->defaults(array(
   'controller' => 'content',
   'action'     => 'static',
  ));
}

 

Define the base content controller

response->body('Controller_Base_Content::index();
');
	}

	public function action_homepage() {
		$this->template->content = 'homepage';
	}

	public function action_static() {

		$path = $this->request->param('path');

		if ($filepath = Kohana::find_file('views', 'content/static/' . $path . '.html')) {
			$filepath = 'content/static/' . $path . '.html';
			//$this->template->content = 'static here'.$filepath;

			$content = new Model_Content();
			$latest_content = $content->get_last_posts(10);

			View::bind_global('latest_content', $latest_content);
			$this->template->content = View::factory($filepath, array(
				'latest_content' => $latest_content,
			))->render();

			switch ($path) {
				case 'privacy-policy': $title = 'Privacy Policy'; break;
				default:
					$title = 'unknown: ' . $path;
			}
			$this->template->facebook_og['og:title'] = $title;
			View::set_global('title', $title);
		} else {
			$this->action_dynamic();
		}
	}

	public function action_dynamic() {

		$path = '/'.$this->request->param('path', '');

		$content = new Model_Content();
		$latest_content = $content->get_last_posts(10);
		View::bind_global('latest_content', $latest_content);

		$post = $content->get_post_by_url($path);

		if ($post && $latest_content) {
			$this->template->content = View::factory('content/main', array(
					'latest_content' => $latest_content,
					'content' => $post,
				)
			);
		} else {
			$this->template->content = View::factory('content/main', array(
					'content' => array(
						'type' => Content::TYPE_UNKNOWN,
						'description' => 'Content not found',
					),
				)
			);
		}
	}
}

 

Define the content controller (~/modules/content/classes/controller/content.php):

<?php
class Controller_Content extends Controller_Base_Content { }
?>

 

Store some configuration values for the module (~/modules/content/config/content.php):

 array(
		'name' => 'default',
		'style' => array(
			'media/css/3-column-px.css' => 'screen',
			'media/css/screen.css' => 'screen, projection',
			'media/css/print.css' => 'print',
			'template/default/css/style.css' => 'screen',
		),
		'script' => array(
			'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js',
		),
	),
);

 

 

……………………………………………………………

 

Kohana 3.2 tutorial : 2 – Setting up and basic Redirect controller

1. Edit bootstrap.php under "application":

——————————

date_default_timezone_set('America/Los_Angeles');
Kohana::init(array(
        'base_url'   => '/',
        'index_file' => '',
));

——————–

2. Change the default route to a redirect controller (so we can deal with redirections for misplaced content/old content):

Route::set('default', '(<request>)',
	array(
		'request' => '(.*)',
	))
	->defaults(array(
		'controller' => 'redirect',
		'action'     => 'index',
	));

3.Create the redirect controller

/modules/redirect/classes/controller/redirect.php

<?php
 defined('SYSPATH') or die('No direct script access.');
/**
 * Handles all the redirecions that may happen
 *
 * @package      Redirect
 * @category     SEO
 * @author       Mauricio Otta
 * @license      Confidential. Internal use only.
 */
class Controller_Redirect extends Controller {

	static public function action_index() {
		echo "Controller_Redirect::action_index();<br />";
		echo Request::current()->param('request');
	}

}

4. Test it.

You should see something like this:

"Controller_Redirect::action_index();"

test with different URLs.

Notice the controller does not handle the Query String part ( http://php.net/parse_url )

 

 

TO-DO: Add query string handling

 

 

Kohana 3.2 tutorial : 1 – Installation

1. Go to kohana’s website

 

http://kohanaframework.org/

 

2. Download latest stable

 

$ wget http://dev.kohanaframework.org/attachments/download/1670/kohana-3.2.0.zip
--11:08:44--  http://dev.kohanaframework.org/attachments/download/1670/kohana-3.2.0.zip
           => `kohana-3.2.0.zip'
Resolving dev.kohanaframework.org... 173.245.60.22, 173.245.61.87
Connecting to dev.kohanaframework.org[173.245.60.22]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1,043,281 [application/zip]

100%[==============================================================================================================================================================>] 1,043,281      1.53M/s             

11:08:45 (1.53 MB/s) - `kohana-3.2.0.zip' saved [1043281/1043281]

3. Uncompress it and move stuff around

 

$ unzip kohana-3.2.0.zip

 

$ ls -la
total 981
drwxr-xr-x   5 portnumber53.com www-data               7 Dec  9 11:11 .
drwxr-x---  57 portnumber53.com www-data              70 Dec  9 10:23 ..
-rw-r--r--   1 portnumber53.com portnumber53.com      27 Dec  9 10:56 .htaccess
drwxr-x---   2 portnumber53.com www-data               2 Dec  9 10:23 cgi-bin
drwxr-x---   2 portnumber53.com www-data               2 Dec  9 10:57 html
drwxr-xr-x   5 portnumber53.com portnumber53.com      10 Jul 25 03:26 kohana-3.2-master-1
-rw-r--r--   1 portnumber53.com portnumber53.com 1043281 Dec  9 11:08 kohana-3.2.0.zip

$ rm kohana-3.2.0.zip

$ mv kohana-3.2-master-1/modules/ .

$ mv kohana-3.2-master-1/application/ modules/

$ mkdir -p vendor/modules

$ mv kohana-3.2-master-1/install.php html/

$ mv kohana-3.2-master-1/index.php html/

 

 

 

4. Combine the example.htaccess

 

$ nano kohana-3.2-master-1/example.htaccess

$ nano .htaccess

 

 

5. Try opening your site:

http://truvis.co/

Kohana install.php file will report what you need to fix…. hopefully just file paths:

 

6. Fix those paths (you millage may vary):

$ nano html/index.php

———————————————–

$application = ‘../modules/application’;

$modules = ‘../modules’;

$system = ‘../vendor/modules/system’;

————————

<?php

/**
 * The directory in which your application specific resources are located.
 * The application directory must contain the bootstrap.php file.
 *
 * @see  http://kohanaframework.org/guide/about.install#application
 */
$application = '../modules/application';

/**
 * The directory in which your modules are located.
 *
 * @see  http://kohanaframework.org/guide/about.install#modules
 */
$modules = '../modules';

/**
 * The directory in which the Kohana resources are located. The system
 * directory must contain the classes/kohana.php file.
 *
 * @see  http://kohanaframework.org/guide/about.install#system
 */
$system = '../vendor/modules/system';

/**
 * The default extension of resource files. If you change this, all resources
 * must be renamed to use the new extension.
 *
 * @see  http://kohanaframework.org/guide/about.install#ext
 */
define('EXT', '.php');

 

 

7. Test until you get Oks everywhere 🙂

 

NGINX with Kohana 3.x friendly URLs

I really enjoy working with Kohana and since I got a server from one of the hosting companies listed at LowEndBox, I decided to ditch Apache and go with Nginx, thing is… I also like pretty URLs 🙂

As a backup from the comment located here: http://forum.kohanaframework.org/discussion/comment/11553/#Comment_11553

I’m copying and pasting it in my blog for easier reference, plus it’s modified to fit my servers configuration:

location / {
    index    index.php index.html;

    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php/$1 last;
    }

    include  /home/httpd/domains/example.com/htaccess;
}

location ~ .php$ {
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /home/httpd/domains/example.com/html$fastcgi_script_name;

    include /etc/nginx/fastcgi_params;
}

# kohana
set  $path_info "";
location /index.php {
    if ($uri ~ "^/index.php(/.+)$") {
        set  $path_info  $1;
    }
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /home/httpd/domains/example.com/html/index.php;

    fastcgi_param  PATH_INFO $path_info;
    include /etc/nginx/fastcgi_params;
}

My current methods while using Kohana 3.0.8 – part 1

I’ve finally decided to get started on documenting how I’ve been using this wonderful framework.

So if you’re patient enough to deal with my crazy schedule (meaning this series may take a while to be finish), fasten your seatbelt:

First of all:

  • Know your environment (your public html folder, a private [but still accessible] folder; permissions etc);
  • Know the difference between server side and client side programming;
  • Download Kohana (http://kohanaframework.org/) 🙂
  • Have your favorite source code editor and ftp client close to you

For the sake of whoever wants to get started with Kohana, I’ll go over the basics (not programming) and I’ll also cover everything that got me breaking my head, so I have a copy outside my brain.

[To-Do: find short video of Sean Connery’s character explaining to Harrison Ford’s character why he wrote everything down on a book]

  • IGlr