Sign In  |   Register  

Kohana PHP 3.0 (KO3) Tutorial Part 4

ellisgl | February 1, 2010 | 61 Comments

Welcome to the fourth part in this series on how to develop with Kohana PHP V3 (KO3). If you haven’t read any of previous parts yet, I would search for and read them before going on. In this tutorial we will be going over how work with models.

So you might be asking your self, what is a model. From Kohana’s 2.x documents:

Models are classes designed to work with information given by or asked for by the controller. For example, you have a guestbook, the controller will ask the model to retrieve the last ten entries, the model returns those entries to the controller who passes them on to a view. The controller might also send new entries to the model, update existing ones or even delete some.

Simply a model is a data handler and manipulator.

The first thing we want to do is identify where and what the data is. Is it an XML feed, CSV, JSON, DB or something else? Well I’m going to make it easy. We are going to deal with our friend MySQL for this. The next step is to setup a MySQL DB connection.

Lets open up your bootstrap file (“application/bootstrap.php”) and find the like that reads “// ‘database’ => MODPATH.’database’, // Database access” and uncomment it. The whole block of code should look like the following:
[php]Kohana::modules(array(
// ‘auth’ => MODPATH.’auth’, // Basic authentication
// ‘codebench’ => MODPATH.’codebench’, // Benchmarking tool
‘database’ => MODPATH.’database’, // Database access
// ‘image’ => MODPATH.’image’, // Image manipulation
// ‘orm’ => MODPATH.’orm’, // Object Relationship Mapping
// ‘pagination’ => MODPATH.’pagination’, // Paging of results
// ‘userguide’ => MODPATH.’userguide’, // User guide and API documentation
));[/php]
Now save this. We’ve basically told the bootstrap to load the database module, but we need to configure it. Copy the “database.php” from “modules/database/config/” to “application/config/”. Open up the “application/config/database.php” file and edit accordingly to your settings. Mine looks like this:
[php]<?php defined(‘SYSPATH’) OR die(‘No direct access allowed.’);

return array
(
‘default’ => array
(
‘type’ => ‘mysql’,
‘connection’ => array(
/**
* The following options are available for MySQL:
*
* string hostname
* integer port
* string socket
* string username
* string password
* boolean persistent
* string database
*/
‘hostname’ => ‘localhost’,
‘username’ => ‘root’,
‘password’ => FALSE,
‘persistent’ => FALSE,
‘database’ => ‘mykohana3′,
),
‘table_prefix’ => ”,
‘charset’ => ‘utf8′,
‘caching’ => FALSE,
‘profiling’ => TRUE,
),
‘alternate’ => array(
‘type’ => ‘pdo’,
‘connection’ => array(
/**
* The following options are available for PDO:
*
* string dsn
* string username
* string password
* boolean persistent
* string identifier
*/
‘dsn’ => ‘mysql:host=localhost;dbname=mykohana3′,
‘username’ => ‘root’,
‘password’ => FALSE,
‘persistent’ => FALSE,
),
‘table_prefix’ => ”,
‘charset’ => ‘utf8′,
‘caching’ => FALSE,
‘profiling’ => TRUE,
),
);[/php]
Save this. You’ll notice I have a database setup just this tutorial series named “mykohana3″, you might want to do the same if you can. Now that we have saved, let get a table set up. Here’s the SQL:
[php]CREATE TABLE `posts` (
`id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) DEFAULT NULL,
`post` TEXT,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC;[/php]
Go run that in your favorite MySQL client, I personally like SQLYog. You might have noticed the “charset” is set to “utf8″ in both the config and create table statement. This will allow us to deal with i18n (Internationalization) stuff later on.

So let create a new folder under “application/classes” named “model”. Now lets create a new file and make it look like this:
[php]<?php
defined(‘SYSPATH’) or die(‘No direct script access.’);

class Model_Post extends Kohana_Model
{
/**
* Get the last 10 posts
* @return ARRAY
*/
public function getLastTenPosts()
{
$sql = ‘SELECT *’.”n”.
‘FROM `posts`’.”n”.
‘ORDER BY `id` DESC’.”n”.
‘LIMIT 0, 10′;

return $this->_db->query(Database::SELECT, $sql, FALSE)
->as_array();
}
}[/php]
Save this as “post.php” under “application/classes/model/”. Here’s an line by line explaination of the code.
[php] $sql = ‘SELECT *’.”n”.
‘FROM `posts`’.”n”.
‘ORDER BY `id` DESC’.”n”.
‘LIMIT 0, 10′;[/php]
This is a basic MySQL statement that selects up to ten rows from the DB which are sorted by the ‘id’ in a descending direction.
[php] return $this->_db->query(Database::SELECT, $sql, FALSE)
->as_array();[/php]
This return array of the result from a query. The “query” method in this example take 3 parameters. 1st being what type of query, our being select, we use the constant “Database::SELECT”. There are 3 others, “Database::INSERT”, “Database::UPDATE” and “Database::DELETE”. The “as_array()” will return an array of the results, no having to do “while($row = mysql_fetch_array())”.

Now that we have a model method, I’m sure we would want to put it use. Open up “ko3.php” in “/application/classes/controller” and lets add this into the class:
[php] public function action_posts()
{
$posts = new Model_Post();
$ko3 = array();
$this->template->title = ‘Kohana 3.0 Model Test’;
$this->template->meta_keywords = ‘PHP, Kohana, KO3, Framework, Model’;
$this->template->meta_description = ‘A test of of the KO3 framework Model’;
$this->template->styles = array();
$this->template->scripts = array();

// Get the last 10 posts
$ko3['posts'] = $posts->getLastTenPosts();
$this->template->content = View::factory(‘pages/posts’, $ko3);

}[/php]
Basically we’ve called our model’s “getLastTenPosts()” method and assigned it to an array which we pass to our view. Talking about views, open up a new file and put the following into it:
[php]<?php foreach($posts as $post):?>
<h1><?php echo $post['title'];?></h1>
<?php echo $post['post'];?>
<hr />
<?php endforeach;?>[/php]
Save to as “posts.php” under “application/views/pages/”. This view loops through the array we pass to it from the the controller and displays our posts from the DB. Wait, what? There’s no posts in our DB! Here’s some SQL you can run to populate your table:
[php]insert into `posts`(`id`,`title`,`post`) values (1,’Test Post’,'This is some sample text.’);
insert into `posts`(`id`,`title`,`post`) values (2,’Another post’,'Some more text’);[/php]
Now if you point your browser to “http://yourserver/mykohana3/ko3/posts” you should see the two entries on the screen.

Now lets add something to put data into our DB. Open the the post model (“application/classes/model/post.php”) and add this to the class:
[php] public function addPost($title, $post)
{
$sql = sprintf(‘INSERT INTO `posts`’.”n”.
‘SET `title` = %s,’.”n”.
‘ `post` = %s’,
$this->_db->escape($title),
$this->_db->escape($post));

$this->_db->query(Database::INSERT, $sql, FALSE);
}[/php]
The above is a pretty simple insert, but you may notice we are using “$this->_db>escape()”. This will wrap your strings in quotes and escape it content for you. Save it and now go back to the “posts.php” from “application/views/pages” and replace the contents with:
[php]<?php if(!empty($msg)):?>
<?php echo $msg.’<br />’;?>
<?php endif;?>
<?php foreach($posts as $post):?>
<h1><?php echo $post['title'];?></h1>
<?php echo $post['post'];?>
<hr />
<?php endforeach;?>
<form method=”POST” action=”<?php echo url::base();?>ko3/posts/”>
<table>
<tr>
<td>
Title
</td>
<td>
<input type=”text” name=”title” style=”border: 1px solid #000000;”/>
</td>
</tr>
<tr>
<td>
Post
</td>
<td>
<textarea cols=”20″ rows=”5″ name=”post”></textarea>
<input type=”submit” name=”submit” value=”Submit”/>
</td>
</table>
</form>[/php]
Save that and open the ko3 controller back up (“application/classes/controller/ko3.php”) and lets add a new method to it.
[php] private function _addPost($title, $post_content)
{
// Load model
$post = new Model_Post();

// Check required fields
if(empty($title))
{
return(array(‘error’ => ‘Please enter a title.’));
}
elseif(empty($post_content))
{
return(array(‘error’ => ‘Please enter a post.’));
}

// Add to DB
$post->addPost($title, $post_content);
return TRUE;
}[/php]
The above code is pretty much a middle man between the “action_posts” and the model that saves the post it self. Lets go back to the “action_posts” method and make it look like this:
[php] public function action_posts()
{
// Load model
$posts = new Model_Post();

// Setup view stuff
$ko3 = array();
$this->template->title = ‘Kohana 3.0 Model Test’;
$this->template->meta_keywords = ‘PHP, Kohana, KO3, Framework, Model’;
$this->template->meta_description = ‘A test of of the KO3 framework Model’;
$this->template->styles = array();
$this->template->scripts = array();
$ko3['msg'] = “”;

// Handle POST
if($_POST)
{
$ret = $this->_addPost((isset($_POST['title']) ? $_POST['title'] : “”),
(isset($_POST['post']) ? $_POST['post'] : “”));

if(isset($ret['error']))
{
$ko3['msg'] = $ret['error'];
}
else
{
$ko3['msg'] = ‘Saved.’;
}
}

// Get the last 10 posts
$ko3['posts'] = $posts->getLastTenPosts();

// Display it.
$this->template->content = View::factory(‘pages/posts’, $ko3);
}[/php]
Save this and reload your browser. Now you should see a pretty ugly form at bottom. Enter some stuff in and click the “submit” button. Your post should appear at the top along with the word “Saved”, this is if you entered stuff in both fields, if not you should see an error.

Before I end this tutorial, I want to go back to our little model for saving our posts. There are several ways to do queries in KO3, but want to quickly show you how you can use the query builder to do the same thing.
[php] public function addPost($title, $post)
{
DB::insert(‘posts’, array(‘title’,'post’))
->values(array($title, $post))
->execute();
}[/php]
That’s pretty simple! It does the same thing as the previous one, with less “hassle” There are advantages using the query builder method, like being able to convert between different DB types (MySQL to Oracle to what ever).

While I might not have gone over doing updates with your model, I thought I would give you a homework assignment to see if you can come up with you own update model for this. Until next time when we go over “H” in “HMVC”, happy coding.

Sources used: Unofficial Kohana 3 Wiki, Kohana PHP 2.x Docs, KO3 API Guide

<<Part 3 | Part 5>>

Post a New Comment

Comments and Reviews:

  1.  
  2.  
    Timoth­y: No proble­m! Hope you are enjoyi­ng this one!
  3.  
    Thanks­!Any chance­ you'll do someth­ing on the Auth module­ and user system­s in Kohana­ 3?
  4.  
    Kristo­ffer: I haven't play around­ with the new Auth module­, and didn't quite like the one in 2.x, so I've been thinki­ng about one part of the series­ doing a home grown ACL/Auth thing for a module­.
  5.  
    Thanks­ for this tutori­al! When should­ we be expect­ing the next part?An Auth tutori­al (either­ for Kohana­'s module­ or a home grown one) would be very useful­ as well!
  6.  
    I'm aiming­ for the week after next.
  7.  
    Thank you so much for these excell­ent tutori­als!!
  8.  
    Hi thereReally­ apprec­iating­ and enjoyi­ng these tutori­als! One small thing - when you say to point your browse­r at http://yourse­rver/mykoha­na3/ko3/post, I think you mean posts plural­, becaus­e your action­ method­ is action­_posts­().OK, I'll get back to workin­g throug­h it. Thanks­ again!
  9.  
    Next ! Next !Pleaaa­aaaase­ !
  10.  
    Added this to the Unoffi­cal Wiki at kerkne­ss.caThanks­ for the valuab­le instru­ctions­.
  11.  
    @Chris: You are right, it should­ be ko3/posts - I'll fix that.@Guilla­ume: Hopefu­lly I will be gettin­g the next part out by Friday­.@Adrian­: Thanks­!
  12.  
    Can you tell us the list of next chapte­rs ?
  13.  
    The next chapte­r, which I hope to have up tomorr­ow (If not, then next week), will be about HMVC. Then after that will be routin­g, then adding­ extern­al librar­ies, then helper­s, then module­s...
  14.  
    Part 5 is out: http://www.dealta­ker.com/blog/2010/02/25/kohana­-php-3-0-ko3-tutori­al-part-5/
  15.  
    wow, very very nice :)I'ts more beauti­ful if you can prepar­e a pdf :)thank you
  16.  
    About coming­ chapte­rs, do you deal with forms and valida­tion?
  17.  
    Actual­ly I will be coveri­ng forms in a couple­ tutori­als from now.
  18.  
    @Stepha­n: Good idea. I'll have to start doing that.
  19.  
    These are awesom­e tutori­als! Learni­ng so much here.> "You post should­ appear­ at the top along with the word “Saved”, this is if you entere­d stuff in both fields­, if not you should­ see an error."I see no such messag­e. That is of course­ becaus­e I don't output­ that anywhe­re in any of the views, which I, thanks­ to your tutori­als, know how to do! But, I was just wonder­ing if/where I have missed­ adding­ that in. Have I missed­ someth­ing, or did you forget­ to put it in there?
  20.  
    @Svish: Downlo­ad the source­ and compar­e what you have with the source­.
  21.  
    Well, found what was missin­g and alread­y knew what it was kind of. Just can't seem to find where you mentio­ned it in your tutori­al :p
  22.  
    @Svish: What looks to be missin­g?
  23.  
    @ellisg­l: The part with the code needed­ to get the word "Saved" and the error messag­e at the top of the page when the form is posted­.
  24.  
    Svish: Ah - yes. Fixed!
  25.  
    Just wonder­ing what are your reason­s for valida­ting data in the contro­ller and not in the model? I've read a few things­ that say model is prefer­red.
  26.  
    @Alex: You are right. I should­ have put the valida­tion in the Model.
  27.  
    Well, valida­tion, depend­s where data come from. and also where you're gettin­g the data. (Semant­ically­ differ­ent)
  28.  
    @Oliver­: Of course­ you could follow­ing the saying­: "Trust no one."
  29.  
    Hey ellisg­l!Thanks­ for these tutori­als!!! It really­ helped­ me get starte­d.Keep it up!-Rainie­r
  30.  
    @Rainie­r: Your welcom­e and I will =)
  31.  
    Oops! This link appear­s to be broken­.
  32.  
    Which link?
  33.  
    I did this exampl­e but displa­ying the error "ErrorE­xcepti­on [ Fatal Error ]: Class 'Databa­se' not found"How can i solve this Please­ help
  34.  
    This is a poor tutori­al in that the author­ totall­y misund­erstan­ds the MVC patter­n. Someth­ing like "get last 20 posts" should­ not be an instan­ce method­ of a Model_­Post. Why do I need to create­ a new post to find other posts? You have a broken­ unders­tandin­g of OOP. The functi­on should­ be static­; better­ yet, you should­ be using the ORM to do basic object­ persis­tence like this.
  35.  
    Why don't you use "$post = Model::factor­y('post');" instea­d of "$post = new Model_­Post();" ?I mean, you do the same with the views ;)
  36.  
    Those are some awesom­e tutori­als, thank you! Just a hint for those having­ troubl­e with model classe­s: don't use unders­cores in the filena­mes (even though­ unders­cores seem to work fine with views appare­ntly).
  37.  
    Super great tutori­al series­ man. I am really­ gettin­g a better­ idea of the MVC archit­ecture­. Thanks­.
  38.  
    Why do i get this error?ErrorE­xcepti­on [ Notice­ ]: Undefi­ned variab­le: postsAPPPAT­Hviews­posts.php [ 12 ]7 8 9 10 11 12 13 14 15 16 17
  39.  
    what goes inpublic­ functi­on action­_index­() {}
  40.  
    To be a stickl­er, should­n't the model extend­ Model, instea­d of Kohana­_Model­.
  41.  
    In applic­ation/classe­s/model/post.php, the final statem­ent isreturn­ $this->_db-> query(Databa­se::SELECT­, $sql, FALSE)->as_arr­ay();
  42.  
    My previo­us commen­t got posted­ before­ I finish­ed. It should­ read as follow­s: ========================================= In applic­ation/classe­s/model/post.php, the final statem­ent isreturn­ $this->_db-> query(Databa­se::SELECT­, $sql, FALSE)->as_arr­ay();Variab­le $this refers­ to Model_­Post which extend­s Kohana­_Model­ which should­ theref­ore have a proper­ty (an object­) called­ _db which should­ have a method­ called­ query(), but I can't find it... http://kohana­framew­ork.org/guide/api/Kohana­_Model­Please­ explai­n...thanks­
  43.  
    Fantas­tic tutori­al :)
  44.  
    Just one questi­on: Why do you extend­ Kohana­_Model­ and not Model as descri­bed in the API?abstra­ct Model extend­s Kohana­_Model­ Model base class. All models­ should­ extend­ this class.I change­d: class Model_­Post extend­s Kohana­_Model­ to class Model_­Post extend­s Model in my code and it did not seem to break anythi­ng. Am I missin­g someth­ing?
  45.  
    @TheReg­ge: I think you're right, Model should­ be extend­ed, not Kohana­_Model­.@mike: ...or maybe in theory­ one should­ create­ a PostMa­nager_­Model for list/filter­ method­s (that's how other MVC framew­orks' develo­pers recomm­end anyway­). Anyway­, using/not using ORMs is defini­tely outsid­e the scope here. What you say sounds­ more like an Enterp­rise-ready/multi-tier/multi-layer "Hello World". Judgin­g by this tutori­al alone there's now way of knowin­g whethe­r the author­ has "a broken­ unders­tandin­g" of MVC/ORM or not; but judgin­g by a certai­n reply anyone­ can see @mike is a rat-bag.
  46.  
    To answer­ the last questi­on just take a look under system­/classe­s/kohana­/model.php .../** * Model base class. All models­ should­ extend­ this class. */ abstra­ct class Kohana­_Model­ {The answer­ to the above questi­on about the $this->_db is also answer­ed in that file ...// Databa­se instan­ce protec­ted $_db = 'defaul­t';
  47.  
    @ajay: You probab­ly forgot­ to enable­ the Databa­se module­ in bootst­rap.php...
  48.  
    I have follow­ed the tutori­al and am not gettin­g the desire­d result­s. when access­ing http://localh­ost/mykoha­na3/ko3/posts/ am gettin­g an empty page. no errors­ in logs as well. I downlo­aded the code and tested­ ..but same error when I disabl­e // Get the last 10 posts $ko3['posts'] = $posts->getLas­tTenPo­sts(); line, the form appear­s.I have uncomm­ented lines in php.ini file requir­ed for mysql as well.pls check and see how this can be resolv­ed anyone­... thnx... san
  49.  
    Since kohana­ 3.1 class Model_­Post should­ extend­s Model_­Databa­se instea­d of Model or Kohana­_Model­.
  50.  
    omg thanky­ou raoul, I was pullin­g my hair out!
  51.  
    In tutori­al Part4 ,I am gettin­g some error while execut­ing querie­s. The Error is:ErrorE­xcepti­on [ Fatal Error ]: Call to a member­ functi­on query() on a non-object­ on line no 17 in your “applic­ation/classe­s/model/post.php”
  52.  
    thanks­, extend­s Model_­Databa­se instea­d of extend­s Model, that's right !
  53.  
    Model_­Databa­se saved my day.. thanks­
  54.  
    @Amarna­th see @raoul's commen­t above.Since kohana­ 3.1 class Model_­Post should­ extend­ Model_­Databa­se instea­d of Model or Kohana­_Model­.applic­ation/classe­s/model/post.php should­ contai­n: ... class Model_­Post extend­s Model_­Databa­se ...
  55.  
    someth­ing is defini­tely wrong here in chrome­ browse­r ...
  56.  
    Source­ code looks like terrib­ly withou­t format­ting.I think, author­s should­ fix this
  57.  
    Not to see the wood for the trees.
  58.  
    Hi Eric,Nice post!I had one of my sites hacked­ once and I'll tell you that it isn't setomh­ing you want to see when you bring it up. That was real notice­able becaus­e it was blatan­t and you could see that it was hacked­.But there are the hacks that you can't see that is bother­some becaus­e you really­ don't know they're there until you have some reason­ to invest­igate a proble­m.Thanks­ fro this post. I will bookma­rk this one for sure.Mike
  59.  
    Just look around­ in your crilce­ of friend­s. Or, better­ yet, start learni­ng how to do these things­ yourse­lf. It's not that hard, really­!
  60.  
    Hello can you give me an exampl­e of a html form to use so that the foliow­lng hardco­ded fields­ can be a variab­le eg from a users form input? messag­e' => Hello World', name' => Chad'
  61.  
    course­, I like your blog, so I add it to my RSS feed. I'm even got intere­sted on gilgbo­ng since I've visite­d your blog.