TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
Usage Examples (aka Snippet Share)
  • Thread for sharing of snippets. Commenting your code and following the CodingStyle is encouraged, but not required.

    Please do not ask for assistance with pastes, this is not meant to be a support thread. All snippets are for demonstration purposes only!

    All pastes are considered public domain, unless a copyright header is in the code.

    Paste away!

  • Here is an example of an extended controller being used as a CRUD tool for an ORM User_Model. (Using Kohana from SVN)

    Users_Controller

  • Example of validating uploads using Validation and the upload:: helper. (SVN)

    Validating Uploads

  • don't know if this is the right place to comment the snippets, if it's not please tell me anyway, in your Users_Controller at row 36 (function detail) you have this code: $user = $this->get_user($id); i suppose get_(model) is a function in your Base_Controller which takes the model given in function name after the underscore, loads it & get the record identified by id. Am i correct? Can you post the code? (i can understand such a behavior in theory but never done it)

    Thank

  • Posted By: phelz

    don't know if this is the right place to comment the snippets, if it's not please tell me
    anyway, in your Users_Controller at row 36 (function detail) you have this code:
    $user = $this->get_user($id);
    i suppose get_(model) is a function in your Base_Controller which takes the model given in function name after the underscore, loads it & get the record identified by id.
    Am i correct? Can you post the code? (i can understand such a behavior in theory but never done it)

    Thank


    There's a protected method get_user() at the bottom of the Users_Controller class.
  • uops! didn't saw that... sorry

  • Here is an example of all my base controllers i use with Kohana

    Website_Controller - This Controller is extended by all my webpages, it uses Kohanas Template system and also sets the header and footer within the class, they can easily enough be overwritten in the child.

    Ajax_Controller - This is a Controller i only extend if i want a url that can only be access by Ajax calls and not directly.

    Cron_Controller - This Controller is used for my Cron Jobs, it cannot be accessed from a URL by anyone and can only be accessed from the localhost using wget
  • Custom forge template, using unordered list instead tables

    Custom Forge Template
  • My forge template, uses only fieldsets, legends, and labels.

    forge_template.php - http://pastie.textmate.org/181933
    forge.css - http://pastie.textmate.org/181940

    a bit ugly and not tested too much because I don't use forge anymore but it worked everywhere I used it
    and created what seemed to me to be very clean markup.
  • Excuse the noob question, but how / where would I implement / place the custom 404 code that Geert submitted ? I placed the file in application/hooks/my_404.php

    I then created a custom controller controllers/error.php that I use to display a themed version of the page, but I still get the default Kohana error page.
  • simple ajax helper to handle ajax responses

  • I wrote an extension to email in order to make an easier way to send email from a website. A call to email::site_email($params) will use some values in your config/email.php - http://pastie.textmate.org/243594 - to send an email using this helper http://pastie.textmate.org/243592 If the $params to site_email are empty it searches for the values in the email.php config file for keys from, to, cc, bcc, subject.
  • I wrote an extension to Text to use PEAR Text_Wiki to render a string of wiki text: http://pastie.textmate.org/243598 A call is made to text::unwikify() with the text to convert as the first parameter and the rendering driver as the 2nd argument, default is mediawiki if not specified.
  • This is my version of alexsancho's history helper http://pastie.textmate.org/243604 the main difference is that it uses $config['size'] = 5; // size of history, 0 = no limit
    in a new config file history.php to determine the length of the history that is stored and a method last() which returns the last page visited (i'm not using the referer call). I needed the last() call as i'm using history::push() each time the website controller is initialised and therefore the most recent history item would be the current page (hence the array search for index 1)
  • http://pastie.textmate.org/243610 is my libraries/MY_Database.php for mysql to allow transactions and return the last insert id
  • http://pastie.textmate.org/243614 is an extension to date to return the date in different formats, based on a mysql timestamp or datetime format - it could be written much better but it's a start for someone looking to achieve something similar
  • wow.. thanks for all the code
  • before kohana had the upload helper i had written one which uses the PEAR upload class - http://pastie.textmate.org/243949

    it can be used to get a list of successful uploads using a call to the method get(), a list of valid uploads (based on extension and mime type) with a call to get_valid_types($valid_extensions = array(), $valid_mime_types = array()) and there are some examples of this such so you can call after uploading upload::get_pdfs() or upload::get_jpegs() to get the successfully uploaded files in your script
  • There's several ways to check/get an instance used in Kohana and various examples on the forum but this one was mine. I added to my inherited master controller a method get_model('modelname') to create or get an existing model instance by reference: http://pastie.textmate.org/243971 e.g. $users_model = $this->get_model('Users') will create or get an instance of Users_Model and return it by reference.
  • This is an alpha version of our library to provide support for LastFM Webservices. It requires the curl php extension and PEAR XML Unserializer. It currently works for providing the functions needed for a desktop application as described. An example of the steps:
    Setup the session token and get an auth url:

    $lf = new LastFM;
    $auth_url = $lf->get_auth_url(); // get a token and the url for user authorization
    $lastfm_token = $lf->get_config('token'); // retrieve the token for backend storage to call after user authorization at $auth_url
    $this->session->set('lastfm_token', $lastfm_token);

    Store the token in the cache, a database or session, cookie or whatever and then on a new page the user can click through to after they manually authorize:

    $lf = new LastFM;
    $lastfm_token = $this->session->get('lastfm_token'); // get the user application token
    $lf->set_config('token', $lastfm_token); // set the token in the lastfm object
    $lf_session = $lf->get_session(); // retrieve the authorized user session
    $this->session->set('lastfm_sk', $lf_session); // store the authorized session
    $this->session->delete('lastfm_token'); // token no longer needed

    Then on a post-authorized, post-session page

    $lf = new LastFM;
    $lastfm_sk = $this->session->get('lastfm_sk'); // retrieve the authorized user session key
    $lf->set_config('sk', $lastfm_sk); // set the session key in our object
    $lastfm_userdata = $lf->call('user.getinfo', '', 'user'); // perform an authenticated api request
  • I had completely missed it - I could write code based on that style. Is it out of the question to have a link to this on http://docs.kohanaphp.com/ ?
  • continuing the work dlib's started with jquery and forge, i've slightly modified the code to extend the validation library in Kohana 2.2.

    Just drop MY_Validation.php inside your application library folder and use it like this example

  • Posted By: alain91

    Hye,

    Posted By: cecplex

    Answering my own question because Google is awesome! :) The new URL is here:http://kohanaphp.com/resources/video/page_cache_hook.mov

    @Mabogie: You can do this without the page_cache hook. Just use the Cache library to set and get the raw data you'd like to cache as to prevent your scripts from running the query.

    I propose a code to manage the cache and let the process of Kohana terminates to be compatible with the display of execution times and other modules or lib whch use 'system.displat' event.

    I hope this will help.

    PS: Does anyone have an explanation if call argument in callback have to be value or reference for optimisation

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

    /**
    *
    * Author : Alain91 on Kohana Forum
    *
    */
    class Hook_page_cache
    {
    private $cache;

    public function __construct()
    {
    $this->cache = new Cache();
    Event::add('system.post_controller_constructor', array(&$this, 'load_cache'));
    }

    public function load_cache()
    {
    $id = session_id();
    if (!empty($id)) return; // probleme with trans_sid mode in files in cache

    $cache = $this->cache->get('Page_'.$tmp);
    if ( $cache ) {
    // Stop the controller setup benchmark
    Benchmark::stop(SYSTEM_BENCHMARK.'_controller_setup'); // due to the step where Cache is loaded in the process

    // Start the controller execution benchmark
    Benchmark::start(SYSTEM_BENCHMARK.'_controller_execution');

    // load the ob_start buffer
    echo $cache;
    // add event 'system.display' eventualy to fill some user variables like kohana render()

    // Stop the controller execution benchmark
    Benchmark::stop(SYSTEM_BENCHMARK.'_controller_execution');
    //Jump to normal end
    Kohana::shutdown();
    // To avoid exucetion of shutdown twice (bootstrap.php'
    exit;
    } else {
    // inssert event in head of the event list (to save the file with kohana variables or user variables
    MY_Event::add_first('system.display', array(&$this, 'save_cache'));
    }

    }

    public function save_cache()
    {
    $this->cache->set('Page_'.url::current(), Event::$data);
    }

    }
    new Hook_page_cache;

  • I got tired of juggling google api keys based upon whether it was the development/testing and the production environment. So I thought it would nice to be able to have a way to fix this what environment are we in problem without hacking away at the core files and also fitting into the already present system architecture. So here it goes....

    The Hook file:

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


    class Environment {

    //Holds the environment data
    static public $TYPE;

    /**
    * Called to grab config data on the system.ready event
    *
    * @access public
    * @param void
    * @return void
    *
    **/

    static public function setup(){
    self::$TYPE = Kohana::config('environment.current');
    }

    }

    Event::add('system.ready', array('Environment', 'setup'));

    ?>


    All this file does it setup a static class variable that can be used throughout the system to differentiate the environment. Pretty simple, but doing it this way allows for further extension possibilities as opposed to just a constant in the index.php file.

    Then the evironment.php config file.


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

    $config['current'] = 'DEVELOPMENT';


    Yet again pretty simple. Sets what the current environment is.

    Now the googlemaps.php config file.


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

    $config = array(
    'DEVELOPMENT'=> 'development_key_here',
    'PRODUCTION'=> 'production_key_here',
    );


    Pretty straightforward - it is a conifg array indexed by environment.

    Finally an excerpt of the view file that uses the key.


    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=<?= Kohana::config('googlemaps.'.Environment::$TYPE); ?>" type="text/javascript"></script>


    Now we use the system's Kohana::config() and the static class variable that was set to get the right key for the environment we are in. Finally, no more juggling keys.

    I could think of other ways to solve this but I think that this is simple and clean way for right now. Let me know what you think.
  • This is another version of Cron_Controller (based on one that was previously posted).

    I currently use it as module on my sites to run cleanup related tasks.
  • @themusicman, I think you're making things a bit harder. What about something like

    googlemaps.php config file

    <?php defined('SYSPATH') or die('No direct script access.'); 
    
    $config['key'] = (IN_PRODUCTION) ? 'production_key_here' : 'development_key_here'; 
    

    view file

    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=<?=Kohana::config('googlemaps.key')?>" type="text/javascript"></script> 
    

    Your solution solves the problem if you have more than two enviroments, but Kohana has the IN_PRODUCTION constant defined on index.php and can be used to simplify the whole thing on a development/production scenario.

  • Here's a class i use for GoogleAnalytics. It looks a little more complex than it really is, but, it covers most scenarios and allows for mutliple domains that could be "IN_PRODUCTION" mode or not. A similar approach would work for GoogleMaps.

    <?php
    /**
    * Class to display Google Analytics code.
    *
    * 1 step required to setup the class (see below)
    *
    * @example echo GoogleAnalytics::get();
    *
    */
    class GoogleAnalytics
    {
    /* STEP 1: Define each domain and it's corresponding tracker code */
    private static $DOMAINS = array(
    'example.library.dev' => 'UA-1111111-11', /* leave out the www. for each domain if STRICT = false */
    'staging-url.com' => 'UA-2222222-22', /* lowercase only */
    'development-url.com' => 'UA-3333333-33',
    'production-url.com' => 'UA-4444444-44',
    'example.com' => 'UA-5555555-55',
    );

    /* whether or not to treat www.example.com and example.com identically */
    const STRICT = FALSE;

    /**
    * Is our domain in the allowed list
    *
    * @return Boolean
    */
    public static function enabled()
    {
    $domain = self::domain();
    return (in_array($domain,array_keys(self::$DOMAINS)));
    }

    /**
    * Retrieve current domain
    *
    * @return String
    */
    public static function domain()
    {
    $domain = strtolower($_SERVER['HTTP_HOST']);

    if (self::STRICT) {
    return $domain;
    }

    return preg_replace('/^www\./i','',$domain);
    }

    /**
    * Retrieve google analytics code for a specific domain
    *
    * @return String
    */
    public static function get()
    {
    $js = null;

    $domain = self::domain();

    if (self::enabled()) {

    $tracker_code = self::$DOMAINS[$domain];

    /* To update the code just remeber to put the tracker_code var back into the string */
    $js =
    <<<JAVASCRIPT
    <script type="text/javascript">
    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl.&quot; : "http://www.&quot;);
    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
    </script>
    <script type="text/javascript">
    var pageTracker = _gat._getTracker("{$tracker_code}");
    pageTracker._trackPageview();
    </script>
    JAVASCRIPT;
    }

    return $js;
    }
    }
  • was just messing around with ORM_Tree tonight and made a menu many levels deep with categories but couldnt seem to find a good way of recursively going through the category tree to display the menu in my Views...
    so im wondering if this is a good idea...


    /* This is pieces/category_list.php */
    <ul>
    <?php foreach($categories as $category): ?>
    <li>
    <?php echo $category->name; ?>
    <?php if( $category->children ) View::factory('pieces/category_list')->set('categories', $category->children->as_array())->render(TRUE); ?>
    </li>
    <?php endforeach; ?>
    </ul>


    was wondering if using Views to handle recursion is a good idea or not. what do you guys suggest?
  • @ Zeelot3k
    That looks like a more than satisfactory solution which I have been known to use myself :)
  • If you are trying to prefix your controller as shown in the examples of the system/routes.php config file it will not work as shown.

    Example from the system/routes.php config file

    $config['admin'] = array
    (
    'admin/:controller/:method/:id',
    // Will change all controllers to admin_:controller
    'prefix' => array('controller' => 'admin_'),
    );


    You have to add a controller index to the $config array as shown below:

    $config['/admin/'] = array
    (
    'admin/:controller/:method/:id',
    //! This must be set
    'controller' => '',
    // Will change all controllers to admin_:controller
    'prefix' => array('controller' => 'admin_'),
    );


    The reason being that when the router is going through its setup process if it comes a across a $config array with the prefix index it looks to make sure that the controller index has been set in the $config array before it will actually add the prefix.

    Snippet from the 2.3 Router:

    if (isset($route['prefix']))
    {
    foreach ($route['prefix'] as $key => $prefix)
    {
    //!Makes sure that the controller index is set in the $config array
    if (isset($route[$key]))
    {
    // Add the prefix to the key
    $route[$key] = $route['prefix'][$key].$route[$key];
    }
    }
    }
  • My very simple helper for password generator
    http://pastie.org/283074
  • Maybe you guys could add to your posts for which version it is meant?
  • Date helper addon, age of a date like gmail shows in front of a message like "1 hour ago"

    http://kohana.pastebin.com/f6e8f9631

    I didnt make it but got it from some site.
  • We already have this: date::timespan

  • Posted By: Shadowhand

    We already have this:date::timespan



    So stupid of me........ my bad..... i should have seen the date class before posting it here......
  • Hi all.

    I've found only one example of using Auth module to create a login system: http://remorse.nl/weblog/kohana_auth_module_working_example/

    Anyone willing to share another updated (Kohana 2.3) and working login system snippet?
  • Hi,

    I added some functions/tips to the auth module docs (http://docs.kohanaphp.com/addons/auth) a few days ago, the main login function and some code for the construct of a controller, it was partially based on the post on remorse.nl but updated (and working) for 2.3.
    User login/create: http://pastie.textmate.org/347339
    I have some more code some user management and some code for adding/removing roles for users: http://pastie.textmate.org/347337 . Stuff for roles: http://pastie.textmate.org/347341. I still need to do something for editing user info, changing passwords etc.
    I haven't supplied the forms and template that I used but in the user controller there is a link to an online form generator.

    Hoe this helps
  • Here is a small addition to the database library to get rid of duplicate queries in run time.
    I am currently building a forum module for kohana and I had to implement run time results storage as whenever one user has several posts or topics on the same page, the query for that users information in running several times. I first wanted to store database results in objects but decided that a small db extension would be more useful


    class Database extends Database_Core {

    private static $results = array();

    public function query($sql = '')
    {
    if( ! array_key_exists(md5($sql), self::$results[(int)$this->link]))
    {
    self::$results[(int)$this->link][md5($sql)] = parent::query($sql);
    }
    return self::$results[(int)$this->link][md5($sql)];
    }

    public function connect()
    {
    parent::connect();
    if( ! array_key_exists((int)$this->link, self::$results))
    {
    self::$results[(int)$this->link] = array();
    }
    }
    }
  • @avalanche123: Your extension is unnecessary, as this is what Database will do if you enable the cache option of your configuration group.

  • Made some PostgreSQL compatible SQL code for installing the Auth module on PostgreSQL:

    CREATE TABLE roles (
    id serial NOT NULL,
    name varchar(32) NOT NULL UNIQUE,
    description varchar(255) NOT NULL,
    PRIMARY KEY (id)
    );

    INSERT INTO roles (id, name, description) VALUES(1, 'login', 'Login privileges, granted after account confirmation');
    INSERT INTO roles (id, name, description) VALUES(2, 'admin', 'Administrative user, has access to everything.');

    CREATE TABLE roles_users (
    user_id int NOT NULL,
    role_id int NOT NULL,
    PRIMARY KEY (user_id,role_id)
    );

    CREATE TABLE users (
    id serial NOT NULL,
    email varchar(127) NOT NULL UNIQUE,
    username varchar(32) NOT NULL default '' UNIQUE,
    password char(50) NOT NULL,
    logins int NOT NULL default '0',
    last_login int,
    PRIMARY KEY (id)
    );

    CREATE TABLE user_tokens (
    id serial NOT NULL,
    user_id int NOT NULL,
    user_agent varchar(40) NOT NULL,
    token varchar(32) NOT NULL UNIQUE,
    created int NOT NULL,
    expires int NOT NULL,
    PRIMARY KEY (id)
    );

    ALTER TABLE roles_users
    ADD CONSTRAINT roles_users_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
    ADD CONSTRAINT roles_users_ibfk_2 FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE;

    ALTER TABLE user_tokens
    ADD CONSTRAINT user_tokens_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE;


    ps. It is a shame that those databases don't support fully T-SQL.
  • When working with templates, I like to use the Template_Controller do define a base template, then use smaller view files for each page's content.
    But sometimes, I only want to include a certain CSS or JS file on one page, or exclude certain files.
    So I copy the template.php file from /system/controllers/template.php to my application folder and add the following to the __construct:

    $head['meta'] = array('description' => 'Description of site',
    'keywords' => 'key, words, for, site',
    'author' => 'Corey');

    $head['css'] = array('/css/styles.css' => 'screen',
    '/css/print.css' => 'print');

    $head['js'] = array('/js/jquery.js', '/js/jquery_ui.js', '/js/fancybox.js');

    $this->template->head = $head;
    </pre>


    And then in my base template file:

    <html>
    <head>
    <?php foreach ($head['meta'] as $key => $val) { ?>
    <meta name="<?php echo $key; ?>" content="<?php echo $val; ?>" />
    <?php }
    foreach ($head['css'] as $key => $val) { ?>
    <link rel="stylesheet" type="text/css" media="<?php echo $val; ?>" href="<?php echo $key; ?>" />
    <?php }
    foreach ($head['js'] as $val) { ?>
    <script type="text/javascript" src="<?php echo $val; ?>"></script>
    <?php } ?>
    </head>
    <body>

    <?php echo $page; ?>

    </body>
    </html>
    </pre>


    So then later in my Controllers, I can simply add or remove what I need/don't need.


    $this->template->head[js][] = '/js/new_script.js';
    unset($this->template->head[css][1]);
    </pre>
  • I'm creating a web API for an iPhone application and I found this useful.

    MY_request.php:

    <?php defined('SYSPATH') OR die('No direct access allowed.');
    
    class request extends request_Core {
    
        public static function is_iphone()
        {
            return (bool) (strpos(strtolower(Kohana::user_agent('agent')), 'iphone') !== false);
        }
    
    }
    
  • CLI call:

    if (PHP_SAPI === 'cli')
    // In CLI mode
  • My hook for using different database configurations:


    // hooks/somehook.php
    public function __construct() {
    Event::add('system.ready', array($this, 'fill_configs'));
    }

    public function fill_configs() {
    $configs = Kohana::config('database');
    $default_size = count($configs['default']);
    $default_connection_size = count($configs['default']['connection']);
    $default_prefix = strlen($configs['default']['table_prefix']) > 0 ? $configs['default']['table_prefix'] : FALSE;
    foreach ($configs as $name => $config) {
    if ($name === 'default') continue;
    if (count($config) != $default_size) {
    $newconfig = arr::overwrite($configs['default'], $config);
    $default_prefix !== FALSE AND $newconfig['table_prefix'] = $default_prefix.$newconfig['table_prefix'];
    }
    if (!isset($config['connection'])) {
    $newconnection = $configs['default']['connection'];
    }
    elseif (count($config['connection']) != $default_connection_size) {
    $newconnection = arr::overwrite($configs['default']['connection'], $config['connection']);
    }
    isset($newconfig) AND Kohana::config_set('database.'.$name, $newconfig);
    isset($newconnection) AND Kohana::config_set('database.'.$name.'.connection', $newconnection);
    }
    }

    // somewhere in modules/xxxmodule/config/database.php
    $config['forum'] = array
    (
    'table_prefix' => 'forum_',
    );

    Now we can apply this profile this->db = 'forum' in models before parent:GDN__construct(). All skipped params are filled by defaults.
  • The cleanest and easiest way to use pagination, the documentation should do it this way :)


    /**
    * Index
    *
    * @return void
    * @author Mathew
    **/
    public function index()
    {
    $this->template->content = View::factory('news/index');

    // Total number of enabled news items.
    $total = ORM::factory('news')->where('enabled', 1)->count_all();

    // Pagination
    $pagination = Pagination::factory(
    array
    (
    'base_url' => Router::$controller.'/'.Router::$method,
    'total_items' => $total
    )
    );

    // Grab the news items.
    $this->template->content->news = ORM::factory('news')
    ->where('enabled', 1)
    ->orderby('date_added', 'DESC')
    ->limit($pagination->items_per_page, $pagination->sql_offset)
    ->find_all();

    // Pagination links
    $this->template->content->pagination = $pagination;
    }
  • @The Pixel Developer

    Why do you use find_all(), not count_records()?

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion