kohana 3.2 tutorial

Kohana is discontinued. I’m now using PhalconPHP / Laravel, but any framework supported by HHVM is a good choice. RIP Kohana, it was nice to do business with you…


Below you will find an article / tutorial on Kohana 3.2 – An elegant HMVC PHP5 framework that provides a rich set of components for building web applications.

I am sharing a site template that use authentication & internationalization. You can download it from github. Any pull request will be more than welcome!

Download via Github:
https://github.com/patricksebastien/kohana-3.2-example


Topics



Install

Using GIT:
http://kohanaframework.org/3.2/guide/kohana/tutorials/git
or
Download:
http://kohanaframework.org/download


Structure of folders:
www/yoursite/site/index.php & .htaccess -> and your assets (css, images, js)
www/yoursite/application -> the very core of your site
www/yoursite/module & system -> core of kohana
or:
www/kohana/version/system & module -> multiple site using kohana
or:
everything in www/yoursite/site (application, module, system, index.php, .htaccess, …)


Test:
127.0.0.1/
If it’s greenish, then remove install.php


index.php
Reflect this structure in www/yoursite/site/index.php:

1
2
3
$application = '../application';
$modules = '../modules';
$system = '../system';

bootstrap.php
Modify application/bootstrap.php

1
date_default_timezone_set('America/Montreal');

Set PRODUCTION vs DEVELOPMENT

1
2
3
4
5
if (isset($_SERVER['KOHANA_ENV'])) {
    Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV']));
} else {
    Kohana::$environment = ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' ? Kohana::DEVELOPMENT : Kohana::PRODUCTION);
}

Initialize Kohana

1
2
3
4
5
'base_url'   => '/', // or for example: /yoursite/site/mykoapp
'index_file' => FALSE, // SEO (avoid index.php/mycontroller/action)
'profile' => (Kohana::$environment !== Kohana::PRODUCTION), //see how good you are
'caching' => (Kohana::$environment === Kohana::PRODUCTION),
'errors' => TRUE, //for custom 404, 500 FALSE for internal error handling

Enable modules (for example):

1
2
3
'auth'       => MODPATH.'auth',       // Basic authentication
'database'   => MODPATH.'database',   // Database access
'orm'        => MODPATH.'orm',        // Object Relationship Mapping

Many modules are available:
https://github.com/kolanos/kohana-universe
http://kohana-modules.com/

Set the routes (default controller will be login.php in this example)
http://kohanaframework.org/3.2/guide/kohana/routing

The order of your routes are important!

1
2
3
4
5
Route::set('default', '(<controller>(/<action>(/<id>)))')
    ->defaults(array(
        'controller' => 'login', // application/classes/controller/login.php
        'action'     => 'index',
    ));

.htaccess
Add this line at the very top of .htaccess (protect from sniffing directory)

1
Options All -Indexes -Multiviews

and modify (/ or for example: /yoursite/site/mykoapp)

1
2
# Installation directory
RewriteBase /

 
Template
http://kerkness.ca/kowiki/doku.php?id=template-site:create_the_template

Create the template controller (classes/controller/template/website.php) extending Controller_Template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Template_Website extends Controller_Template
{
    public $template = 'template/website';

    /**
     * The before() method is called before your controller action.
     * In our template controller we override this method so that we can
     * set up default values. These variables are then available to our
     * controllers if they need to be modified.
     */

    public function before() {
        parent::before();
        if ($this->auto_render) {
            // Initialize empty values
            $this->template->title   = '';
            $this->template->content = '';
            $this->template->styles = array();
            $this->template->scripts = array();
        }
    }
     
    /**
     * The after() method is called after your controller action.
     * In our template controller we override this method so that we can
     * make any last minute modifications to the template before anything
     * is rendered.
     */

    public function after() {
        if ($this->auto_render) {
            $styles = array(
            'assets/css/website.css' => 'screen, projection',
            );
            $scripts = array(
            'http://code.jquery.com/jquery.min.js',
            );
            $this->template->styles = array_merge( $this->template->styles, $styles );
            $this->template->scripts = array_merge( $this->template->scripts, $scripts );
        }
        parent::after();
    }
}

Create the controller (classes/controller/login.php) extending Controller_Template_Website (look at the second action for an example on how to use another template per action):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Controller_Login extends Controller_Template_Website {

    public function action_index()
    {
        $this->template->title = 'Log in';
        $this->template->content = View::factory('login'); // application/views/login.php
    }

        // this action is using another template but using the same Controller_Template_Website
    public function action_showinfooverlay()
    {
        $this->template = 'template/overlay';
        parent::before();
        $this->template->title = 'Log in';
        $this->template->content = View::factory('login'); // application/views/login.php
    }
}

Create the html template (view/template/website.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo substr(I18n::$lang, 0, 2); ?>" lang="<?php echo substr(I18n::$lang, 0, 2); ?>">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="language" content="<?php echo I18n::$lang ?>" />
<title><?php echo $title ?></title>
<?php foreach ($styles as $file => $type) echo HTML::style($file, array('media' => $type)), PHP_EOL ?>
<?php foreach ($scripts as $file) echo HTML::script($file), PHP_EOL ?>
</head>
<body>
<div id="wrapper">
<?php echo $content ?>
</div>
</body>
</html>

Finally create your view content application/views/login.php

1
2
3
4
5
6
7
8
9
<?php echo Form::open(); ?>
<dl>
    <dt><?php echo Form::label('username', 'User') ?></dt>
    <dd><?php echo Form::input('username') ?></dd>
    <dt><?php echo Form::label('password', 'Pwd') ?></dt>
    <dd><?php echo Form::password('password') ?></dd>
</dl>
<p><?php echo Form::submit(NULL, 'Log in'); ?></p>
<?php echo Form::close(); ?>

At this point you can point your browser to see the login page:
http://localhost/ -> depending on base_url and .htaccess (could be in a sub-folder)
http://localhost/login -> not defined login as the default controller in bootstrap.php

Someone on #kohana (irc / freenode) made a suggestion of using view classes instead of template controller. Here’s two solutions: https://github.com/zombor/kostache & https://github.com/beautiful/view

 
Configure
Database
Copy modules/database/config/database.php to application/config/database.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'default' => array
(
    'type'       => 'mysql',
    'connection' => array(
        'hostname'   => 'localhost',
        'database'   => 'yourdb',
        'username'   => 'user',
        'password'   => 'pwd',
        'persistent' => FALSE,
    ),
    'table_prefix' => '',
    'charset'      => 'utf8',
    'caching'      => FALSE,
    'profiling'    => FALSE, // if you use profiling turn this on (to see querys)
),

Cookie
in application/bootstrap.php
must be after: spl_autoload_register(array(‘Kohana’, ‘auto_load’));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Cookie
 */

// Set the magic salt to add to a cookie
Cookie::$salt = 'fjsdijeihrewhbfsugfuyegwufewgwb';
// Set the number of seconds before a cookie expires
Cookie::$expiration = DATE::WEEK; // by default until the browser close
// Restrict the path that the cookie is available to
//Cookie::$path = '/';
// Restrict the domain that the cookie is available to
//Cookie::$domain = 'www.mydomain.com';
// Only transmit cookies over secure connections
//Cookie::$secure = TRUE;
// Only transmit cookies over HTTP, disabling Javascript access
//Cookie::$httponly = TRUE;

Session (stored in database)
http://kohanaframework.org/3.2/guide/kohana/sessions
in application/bootstrap.php add the default session handler:

1
Session::$default = 'database';

Copy system/config/encrypt.php to application/config/encrypt.php

1
2
3
4
5
6
7
8
9
return array(

    'default' => array(
        'key'   => 'fjdsjkfdskjfurew',
        'cipher' => MCRYPT_RIJNDAEL_128,
        'mode'   => MCRYPT_MODE_NOFB,
    ),

);

Create a table if you want to use database session

1
2
3
4
5
6
7
CREATE TABLE  `sessions` (
            `session_id` VARCHAR(24) NOT NULL,
            `last_active` INT UNSIGNED NOT NULL,
            `contents` TEXT NOT NULL,
        PRIMARY KEY (`session_id`),
        INDEX (`last_active`)
        ) ENGINE = MYISAM;

Copy system/config/session.php to application/config/session.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
return array(
    'database' => array(
        'name' => 'session',
        'encrypted' => TRUE, // need a key in config/encrypt.php
        'lifetime' => DATE::HOUR, // 0 = expire when the browser close
        'group' => 'default',
        'table' => 'sessions',
        'columns' => array(
            'session_id'  => 'session_id',
            'last_active' => 'last_active',
            'contents'    => 'contents'
        ),
        'gc' => 500,
    ),
);

Use it in your controller:

1
2
Session::instance()->set('key', 'value');
Session::instance()->get('key');

yoursite
Create a file in application/config/yoursite.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php defined('SYSPATH') or die('No direct access allowed.');
return array(
    'myconfig1' => 'fjdsjkfdskjfurew',
       'playlists' => array
    (
        1478363 => 10171,
        22857234 => 10171,
        386 => 10171,
        722 => 10171,
        893 => 10171,
        237 => 10171,
    ),
   
);

Then you can call a config like this:

1
2
$playlists = Kohana::$config->load('yoursite.playlists');
Kohana::$config->load('yoursite.myconfig1 ');

Message
(might be better to use I18N directly)

Create a file in application/message/yoursite.php for you project

1
2
3
4
5
<?php defined('SYSPATH') or die('No direct script access.');
return array(
    'permission'         => 'You don\'t have the permission',
    'wrong'         => 'Wrong username or password',
);

Then you can use it like this:

1
Kohana::message('yoursite', 'permission');

Translation
http://blog.mixu.net/2010/11/11/kohana-3-i18n-tutorial/

1
<?php echo __('Dear :firstname, your username is: :user', array(':firstname' => 'gfdgfdg', ':user' => 'gfdgfd')); ?>

 
Validation
http://kohanaframework.org/3.2/guide/kohana/security/validation
Copy system/messages/validation to application/message/validation.php if you want to change the error message

1
2
3
4
5
6
7
8
9
10
11
12
13
// Validate a form ($_POST)
if (isset($_POST) && Valid::not_empty($_POST)) {       
    // Validate the login form
    $post = Validation::factory($_POST)
    ->rule('username', 'not_empty')
    ->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
    ->rule('password', 'not_empty')
    ->rule('password', 'min_length', array(':value', 3));
           
    // If the form is valid and the username and password matches
    if ($post->check()) {
        echo 'Validated';
    }

Using a callback for custom validation & error message

1
2
3
4
5
6
7
8
9
// form post handling
if (isset($_POST) && Valid::not_empty($_POST)) {           
    // validate
    $post = Validation::factory($_POST)
    ->rule('username', 'alpha_numeric')
    ->rule('password', array($this, 'pwdneusr'), array(':validation', ':field', 'username'));              
    if ($post->check()) {
        }
}
1
2
3
4
5
6
7
8
9
// CALLBACK
// validation rule: password != username
public function pwdneusr($validation, $password, $username)
{
    if ($validation[$password] === $validation[$username])
    {
        $validation->error($password, 'pwdneusr');
    }
}

 
Error page

http://kohanaframework.org/3.2/guide/kohana/tutorials/error-pages

Create the views
views/error/404.php / 500.php etc…

Extend the exception handler of Kohana
classes/kohana/exception.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php defined('SYSPATH') or die('No direct script access.');
class Kohana_Exception extends Kohana_Kohana_Exception {
    public static function handler(Exception $e)
    {
        if (Kohana::DEVELOPMENT === Kohana::$environment)
        {
            parent::handler($e);
        }
        else
        {
            try
            {
                Kohana::$log->add(Log::ERROR, parent::text($e));
 
                $attributes = array
                (
                    'controller' => 'error',
                    'action'  => 500,
                    'message' => rawurlencode($e->getMessage())
                );
 
                if ($e instanceof HTTP_Exception)
                {
                    $attributes['action'] = $e->getCode();
                }
 
                // Error sub-request.
                echo Request::factory(Route::get('error')->uri($attributes))
                ->execute()
                ->send_headers()
                ->body();
            }
            catch (Exception $e)
            {
                // Clean the output buffer if one exists
                ob_get_level() and ob_clean();
 
                // Display the exception text
                echo parent::text($e);
 
                // Exit with an error status
                exit(1);
            }
        }
    }
}

Create the controller:
classes/controller/error.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Error extends Controller_Template_Nobrand {
    public function before()
    {
        parent::before();
        // Internal request only!
        if (Request::$initial !== Request::$current) {
            if ($message = rawurldecode($this->request->param('message'))) {
                $this->template->message = $message;
            }
        } else {
            $this->request->action(404);
        }
        $this->response->status((int) $this->request->action());
    }
    public function action_404()
    {
        $this->template->title = '404 Not Found';
        $this->template->content = View::factory('error/404' );
    }
    public function action_500()
    {
        $this->template->title = 'Internal Server Error';
        $this->template->content = View::factory('error/500' );
    }
    public function action_503()
    {
        $this->template->title = 'Maintenance Mode';
        $this->template->content = View::factory('error/503' );
    }
}

Edit application/bootstrap.php to add the route:

1
2
3
4
Route::set('error', 'error/<action>(/<message>)', array('action' => '[0-9]++', 'message' => '.+'))
    ->defaults(array(
        'controller' => 'error'
    ));

 
Authentication
Copy modules/auth/config/auth.php to application/config/auth.php

1
2
3
4
5
6
7
return array(
    'driver'       => 'orm',
    'hash_method'  => 'sha256',
    'hash_key'     => 'wigbble',
    'lifetime'     => Date::HOUR * 2,
    'session_key'  => 'auth_user',
);

Schema for mysql / postgresql located:
modules/orm/auth-schema-mysql.sql

Change the rules if you don’t want to required an email (you will also need to remove the index in mysql: uniq_email – BTREE)
Copy modules/orm/classes/model/auth/user.php to application/classes/model/auth/user.php and change the public function rules() to your needs

It’s a good idea to add a new role for your normal user, that way you can list them easily:

1
$p = ORM::factory('role', array('name' => 'participant'))->users->find_all();

Create application/messages/models/user.php

1
2
3
4
5
<?php defined('SYSPATH') or die('No direct script access.');
return array(
    'username.unique'         => 'Username must be unique',
    'email.unique'         => 'Email must be unique',
);

If you want to use the remember feature:

1
2
$remember = isset($post['remember']);
Auth::instance()->login($post['username'], $post['password'], $remember)

then you need to be sure to have a cookie salt in application/bootstrap.php

1
2
3
4
/**
* Cookie salt for remember user info
*/

Cookie::$salt = 'fdsh-tretgd-re-gfds-gt-erg-fdg-';

Some useful stuff:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Add an administrator (in a temporary controller)
$model = ORM::factory('user');
$model->values(array(
    'username' => 'admin',
    'password' => 'admin',
    'password_confirm' => 'admin',
        'email' => 'your@email.com',
));
$model->save();
// remember to add the login role AND the admin role
// add a role; add() executes the query immediately
$model->add('roles', ORM::factory('role')->where('name', '=', 'login')->find());
$model->add('roles', ORM::factory('role')->where('name', '=', 'admin')->find());
1
2
3
4
5
6
7
8
9
// If this user doesn't have the admin role, and is not trying to login, redirect to login
public function before()
{
  parent::before();
  if ( ! Auth::instance()->logged_in('admin') AND Request::current()->uri() !== 'manage')
  {
    $this->request->redirect('/manage');
  }
}
1
2
3
4
// Administrator already logged in, redirect to dashboard
if (Auth::instance()->logged_in('admin')) {
    $this->request->redirect('manage/dashboard');
}
1
2
// Log the user
Auth::instance()->login($post['username'], $post['password'], FALSE)
1
2
// Check if the user have the admin permission
if(!Auth::instance()->logged_in('admin')) {
1
2
// Log user out
Auth::instance()->logout();
1
2
3
4
// check if email or username (automagic) is already taken
if(ORM::factory('user')->unique_key_exists($_POST['username'])) {
       echo "FOUND";
}

 
ORM
http://kohanaframework.org/3.2/guide/orm/
http://karlsheen.com/kohana/kohana-3-orm-tutorial-and-samples/
http://kohanaframework.blogspot.com/2010/12/kohana-3-orm-simple-example.html
http://www.geekgumbo.com/2011/05/24/kohana-3-orm-a-working-example/
http://kohanaframework.org/3.2/guide/api/ORM

ORM is included with the Kohana 3.x install but needs to be enabled before you can use it. In your application/bootstrap.php file modify the call to Kohana::modules and include the ORM modules:

1
'orm' => MODPATH.'orm',

The table name must be in plural;
The table must have an id with auto increment (required);
You must create a Model that extends ORM class (this one not in plural)

1)
Create a table with a “s” as the end:

tracking -> trackings
category -> categories

2)
Create a model (application/classes/model) without the “s”

tracking.php
category.php

1
2
3
4
5
<?php defined('SYSPATH') or die('No direct access allowed.');
class Model_Tracking extends ORM
{
    ...
}
1
2
3
4
5
<?php defined('SYSPATH') or die('No direct access allowed.');
class Model_Category extends ORM
{
    ...
}

3)
Establish your relation (one-to-one, one-to-many etc…)
http://kohanaframework.org/3.2/guide/orm/relationships

4)
Use your model / ORM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try
{
    $tracking = ORM::factory('tracking');
    $tracking->user_id = Auth::instance()->get_user()->id;
    $tracking->session_id = Session::instance()->id();
    $tracking->title = ' fdsfdsf ';
    if($tracking->save()) {
        echo "save";
    } else {
        echo "for some reason, there's an error";
    }
  }
catch (ORM_Validation_Exception $e) {
    echo "error";
    var_dump($e->errors());
}

Some useful stuff:

1
2
3
$user = ORM::factory('user');
echo $user->count_all();
echo $user->last_query();
1
2
3
4
$playlists = ORM::factory('playlist')->where('week_id', '=', 1)->find_all();
foreach ($playlists as $playlist) {
    echo $playlist->url;
}

Last ID from ->save();

1
2
$myormmodel->save();
echo $myormmodel->id();

Dynamic ORM query builder

1
2
3
4
5
6
7
8
public function search_keywords(array $keywords)
    {
            foreach($keywords as $keyword)
            {
                    $this->or_where('title', 'like', '%'.$keyword.'%');
            }
            return $this->find_all();
    }

ORM Validation
http://kohanaframework.org/3.2/guide/orm/examples/validation
http://kohanaframework.org/3.2/guide/kohana/security/validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php defined('SYSPATH') or die('No direct access allowed.');
class Model_Member extends ORM {
    public function rules()
    {
        return array(
            'username' => array(
                array('not_empty'),
                array('min_length', array(':value', 4)),
                array('max_length', array(':value', 32)),
                array(array($this, 'username_available')),
            ),
            'password' => array(
                array('not_empty'),
            ),
        );
    }
    public function filters()
    {
        return array(
            'password' => array(
                array(array($this, 'hash_password')),
            ),
        );
    }
    public function username_available($username)
    {
        // There are simpler ways to do this, but I will use ORM for the sake of the example
        return ORM::factory('member', array('username' => $username))->loaded();
    }
 
    public function hash_password($password)
    {
        // Do something to hash the password
    }
}

 
Database:
http://kohanaframework.org/3.2/guide/database/
http://kohanaframework.org/3.2/guide/api/Database

There’s 2 ways to query a database: prepared (normal SQL) and query builder (dynamic)

Prepared:

1
2
3
4
5
6
$query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user AND status = :status');
 
$query->parameters(array(
    ':user' => 'john',
    ':status' => 'active',
));

Query builder:

1
2
3
4
$query = DB::select()->from('users')->where('username', '=', 'john');
$query = DB::select('username')->distinct(TRUE)->from('posts');
$query = DB::select()->from(`posts`)->limit(10)->offset(30);

Results:

1
2
3
4
5
6
$results = DB::select()->from('users')->where('verified', '=', 0)->execute();
foreach($results as $user)
{
    // Send reminder email to $user['email']
    echo $user['email']." needs to verify his/her account\n";
}
1
2
3
4
5
6
$results = DB::select()->from('users')->where('verified', '=', 0)->as_object()->execute();
foreach($results as $user)
{
    // Send reminder email to $user->email
    echo $user->email." needs to verify his/her account\n";
}

Only get 1 result:

1
$total_users = DB::select(array('COUNT("username")', 'total_users'))->from('users')->execute()->get('total_users', 0);
1
2
3
// Get the total number of records in the "users" table
$db = Database::instance();
$count = $db->count_records('testi');

 
3rd party libraries
The convention is to place 3rd party files in application/vendor. For instance, if you had an installation of Doctrine, you would place it in application/vendor/doctrine.

1
2
require Kohana::find_file('vendor', 'Swift-4.0.5/lib/swift_required');
$transport = Swift_SmtpTransport::newInstance(...); // This is autoloaded for me by Swiftmailer

PHPExcel – create PDF, CSV, Excel:
application/vendor/phpexcel/PHPExcel.php & PHPExcel
then in your controller:

1
2
require Kohana::find_file('vendor', 'phpexcel/PHPExcel');
$objPHPExcel = new PHPExcel();

Email – you can use this module:
https://github.com/Luwe/Kohana-Email
or directly use swiftmailer:
http://swiftmailer.org/

1
2
3
4
5
6
7
8
9
10
11
12
require Kohana::find_file('vendor', 'swift/swift_required');
//Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
//Create a message
$message = Swift_Message::newInstance('Email')
->setFrom(array('from@email.net' => 'From'))
->setTo(array('to@email.net'))
->setBody('An email');
//Send the message
$result = $mailer->send($message);

 
Helper
http://kohanaframework.org/3.2/guide/api/Arr
If you want to add some custom helper (generally used statically) or library (instantiated / object), for example: application/classes/participants.php

1
2
3
4
5
<?php defined('SYSPATH') or die('No direct script access.');
class Participant {
    static function currentweek() {
    }
}

in your controller:

1
$weektodisplay = Participant::currentweek();

 
Tips
To get the params in a controller (depending on your routes in application/bootstrap.php)

1
$this->request->param('id')

Debug:

1
echo Debug::vars();

To get the current controller:

1
echo Request::current()->uri();

To point at the right directory use:

1
<?php echo URL::base(); ?>

To get a custom column from users (auth):

1
echo Auth::instance()->get_user()->week;

Date:

1
2
Date::formatted_time('now', 'm-d-Y');
//constant Date::WEEK Date::YEAR

Way to use the model and the post for edition in form:

1
2
3
4
5
// Received the POST
if (isset($_POST) && Valid::not_empty($_POST)) {
    // keep but not saved
    $participant->values($_POST, array('email', 'username','password'))
}

To redirect use:

1
$this->request->redirect('manage/dashboard');

To make a link use:

1
<?php echo HTML::anchor('playlist', 'Playlist', array('style' => 'color: #FFF')); ?>

Function inside controller:
inside action_x():

1
array_walk($trackings, array($this, '_replaceplaylistendtime'), $params);

outside action_x():

1
2
3
static function _replaceplaylistendtime(&$value, $key, $p) {
    ...
}

 
Jquery
Use the latest minified version on google server:
http://code.jquery.com/jquery.min.js

User interface:
http://ninjaui.com/
http://jqueryui.com/
http://flowplayer.org/tools/index.html

Ajax:
In your “ajax” controller / action

1
2
3
4
5
if ($this->request->is_ajax()) {
    $id = json_decode($_POST['refresh']);
    $this->auto_render = FALSE;
    echo json_encode(array('result' => $id));
}

In your jquery:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$.ajax({
                type: "POST",
                url: "<?php echo URL::base(); ?>home/refresh",
                data: "refresh=1",
                async: true,
                dataType: "json",
                success: function(resultArray, textStatus, XMLHttpRequest)
                {
                    var result = parseInt(resultArray['result']);
                    alert(result);
                },
                error: function(request, textStatus, errorThrown)
                {
                    alert('error refreshing the session');
                }
});

 
Bookmarks
http://kohanaframework.org/3.2/guide/kohana/tutorials/
http://kohanaframework.org/3.2/guide/api or http://kohana.nerdblog.pl/api/

 
Deploying:
See this for more information about deploying Kohana application
http://nerdblog.pl/2011/09/05/deploying-kohana-3-2-application-in-production/

04

04 2010

7 Comments Add Yours ↓

  1. psc #
    1

    hi Omry,

    have a look at my site template that use authentication & internationalization:
    https://github.com/patricksebastien/kohana-3.2-example
    http://www.workinprogress.ca/ko32example/site/

    regards

  2. 2

    hi,
    i would like to see i18n implemenatation, for content, forms and messages.

    regards,
    Omry

  3. psc #
    3

    Hi Sinan,

    GIT doesn’t add empty directories. Fixed (by adding a .gitignore).

  4. Sinan E. #
    4

    Please add “cache” and “logs” folders to your application folder.
    In unix system it causes errors if they do not exist.
    Thanks for the project.

  5. psc #
    5

    Hi Robert,

    You’re right, I forgot to add the “reset_token” field in “users”. You have to implement the mailing functionality yourself (you can see an example in this post under 3rd party libraries). After that, the reset password will work. About the logging, the “Remember” checkbox should add a cookie BUT something is missing in “config/ko32example.php”: session_lifetime => 0. Will fix it soon.

    The best thing would be to make a pull request on github if you want to contribute your code.

    EDIT: fixed on github

  6. Robert #
    6

    Thanks for the excellent article/code example. It really helps me a lot to implement my own authentication stuff.

    I have a few questions, and I hope you are willing to answer them.

    In function action_password() in class Controller_Account you have got the following line:

    $user = ORM::factory(‘user’)->where(‘email’, ‘=’, $_GET[‘email’])->where(‘reset_token’, ‘=’, $_GET[‘token’])->find();

    If I am correct, there is no field “reset_token” in table users.

    So action_reset does not work, or does it?

    I noticed you commented out the mailing stuff and replaced it with “//TODO email”.

    That is no problem, because I think I will be able to add the mailing functioality myself.

    A few questions though:

    – Did you implement it afterwards? If so, is the code available?

    – Do you use a field “reset_token”, or do you use table “user_tokens” to store the tokens? And if you haven’t implemented this part (yet), what would you advise to do?

    It would be best fantastic if you could complete action_reset and action_password.

    I am going to try it myself, but I am fairly new to Kohana, so it won’t be easy. If I succeed, I will send you a copy.

    Thanks again for the article/code example.

    Cheers,
    Robert

    PS: It looks like the user stays logged in. It does not make a difference you choose ‘remember’ or not. A small bug?

  7. 7

    Thanks for this article! I’m sure many will find this very useful. Also thanks for showing me http://kohana.nerdblog.pl/api/ :)



Your Comment