Beruflich Dokumente
Kultur Dokumente
Cristian Gil on Jul 9th 2009 with 170 comments Kohana is a PHP 5 framework that uses the Model View Controller (MVC) architectural pattern. There are several reasons why you should choose Kohana but the main ones are security, weightlessness and simplicity. In this tutorial, Ill introduce its main features, and, with a simple demonstration, Ill show you how much time Kohana can potentially save you.
Kohana is a PHP5 framework that uses the Model View Controller architectural pattern. MVC keeps application logic separate from the presentation. This allows us to create cleaner code and save time for bug searching. In unfamiliar with this pattern: A Model represents data on which the application operates. Usually a database. A View contains presentation code such as HTML, CSS and JavaScript. A Controller interprets input from the user and sends to the model and/or view. Kohana was originally a fork of CodeIgniter (CI), which is an open-source product from EllisLab. There are many similarities between CI and Kohana, but all of the code is either new or completely rewritten. As you can read on the official Kohana web site, the main features are: Highly secure Extremely lightweight Short learning curve Uses the MVC pattern 100% UTF-8 compatible Loosely coupled architecture Extremely easy to extend
Lets get started. Visit Kohanas official web site http://kohanaphp.com and click on the green box in the right corner to download the latest version. All Kohana libraries, helpers, and views are included in the default download package, but you may select extra modules, vendor tools, and languages if you want. For the purpose of this tutorial, the default package can be enough. Click on Download Kohana! to begin the download.
Server with Unicode support PHP version >= 5.2.3 An HTTP server. I suggest you use XAMPP. XAMPP is an easy all-in-one tool to install MySQL, PHP and Perl. Database (MsSQL, MySQL, MySQLi, PostgreSQL, PDOSqlite) There are also some required extensions. PCRE iconv mcrypt SPL If your installation completes successfully, you will be redirected to this test page:
If any of the tests fail, you must correct them before moving forward. If all tests have passed, go to the Kohana directory and remove or rename the install.php script. Refresh, and you will see a welcome page like this:
Our application will be placed in the application folder. In this folder there are several sub folders but we need the following for our project: config folder hosts all the configuration files coded as simple static arrays. controllers folder hosts our custom controllers class models folder hosts our custom models class views folder hosts our custom files written in HTML (or any markup language or script needed to display data and interface controls to the user) The remaining sub folders are not required for this tutorial, so I invite you to learn more on the Kohana web site. The system folder host the Kohana core and the Kohana tools like libraries, helpers and predefined configuration files. In this project we will use some libraries and some helpers good tools to speed up your work. The assets folder is not a predefined Kohana folder. I have created it for media files like CSS, JS, and images. Ill show you how to include these files in the project. The modules folder is the place to put reusable collections of related files that together add a particular
functionality to an application. The authentication module, provided by the Kohana team, is an example of module. This is a very brief introduction to the Kohana file system, but its enough for the purposes of this tutorial. I dont want to bore you more with theory.
43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59.
(7, 'Folk'), (8, 'Metal'), (9, 'Hawaiian'), (10, 'Imports'), (11, 'Indie Music'), (12, 'Jazz'), (13, 'Latin'), (14, 'New Age'), (15, 'Opera'), (16, 'Pop'), (17, 'Soul'), (18, 'Rap'), (20, 'Soundtracks'), (21, 'World Music');
ALTER TABLE `albums` ADD CONSTRAINT `genre_inter_relational_constraint` FOREIGN KEY (`genre_id`) REFERENCES `genres` (`i
As you can see, the SQL creates two tables, albums and genres, and populates them with some data. The last SQL statement adds a constraint for the foreign key genre_id. The database structure is very simple and doesnt need much explanation.
Now, you have to tell Kohana where your database is located and how to access it. Edit the global configuration file system/config/database.php as follows view plaincopy to clipboardprint? 1. $config['default'] = array 2. ( 3. 'benchmark' => TRUE, 4. 'persistent' => FALSE,
5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. );
'connection' => array ( 'type' => 'mysql', 'user' => 'root', 'pass' => 'root', 'host' => 'localhost', 'port' => FALSE, 'socket' => FALSE, 'database' => 'cd_collection' ), 'character_set' => 'utf8', 'table_prefix' => '', 'object' => TRUE, 'cache' => FALSE, 'escape' => TRUE
This code tells Kohana to connect to a MySQL database called cd_collection on localhost with the username root and the password root. You have to change these settings according to your database server configuration.
PHP5 OOP is a prerequisite. So if you arent well-versed, you can learn more here. The constructor function, called __construct, initializes the class and calls the parent constructor. The index function is the default function, so it will be called if we call the controller without specifying any function (e.g. http://localhost/index.php/kohana/album. After the name controller
there isnt any function, the default index function will be called.) Given these basic rules, lets focus on our application. The album controller implements all the actions for the albums collection management. This controller allows us to create a new album, to show the albums stored in our database, to update an album, and to delete an album. So, lets change the class as follows. Create a file called album.php in application/controllers/ and paste the following. view plaincopy to clipboardprint? 1. <?php defined('SYSPATH') OR die('No direct access allowed.'); 2. 3. class Album_Controller extends Controller 4. { 5. private $album_model; 6. private $genre_model; 7. 8. private $list_view; 9. private $create_view; 10. private $update_view; 11. 12. public function __construct() 13. { 14. parent::__construct(); 15. $this->album_model = new Album_Model; 16. $this->genre_model = new Genre_Model; 17. $this->list_view = new View('list'); 18. $this->update_view = new View('update'); 19. $this->create_view = new View('create'); 20. } 21. 22. public function index() 23. { 24. $this->show_albums_list(); 25. } 26. 27. private function show_albums_list() 28. { 29. $albums_list = $this->album_model->get_list(); 30. $this->list_view->set('albums_list',$albums_list); 31. $this->list_view->render(TRUE); 32. } 33. 34. public function show_create_editor() 35. { 36. $this->create_view->set('genres_list',$this->get_genres_list()); 37. $this->create_view->render(TRUE); 38. } 39. 40. public function show_update_editor($id) 41. { 42. $album_data = $this->album_model->read($id); 43. $this->update_view->set('album_id',$album_data[0]->id); 44. $this->update_view->set('name',$album_data[0]->name); 45. $this->update_view->set('author',$album_data[0]->author);
46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. }
$this->update_view->set('genre_id',$album_data[0]->genre_id); $this->update_view->set('genres_list',$this->get_genres_list()); $this->update_view->render(TRUE); } public function create() { $album_data=array( 'name' => $this->input->post('name'), 'author' => $this->input->post('author'), 'genre_id' => $this->input->post('genre_id') ); $this->album_model->create($album_data); url::redirect('album'); } public function update() { $album_data = array( 'name' => $this->input->post('name'), 'author' => $this->input->post('author'), 'genre_id' => $this->input->post('genre_id') ); $this->album_model->update($this->input->post('album_id'),$album_data); url::redirect('album'); } public function delete($id) { $this->album_model->delete($id); url::redirect('album'); } private function get_genres_list() { $db_genres_list = $this->genre_model->get_list(); $genres_list = array(); if(sizeof($db_genres_list) >= 1) { foreach($db_genres_list as $item) { $genres_list[$item->id] = $item->name; } } return $genres_list; }
Let me explain what this code does. Five members variables are declared at the top of the class: view plaincopy to clipboardprint? 1. private $album_model; 2. private $genre_model; 3.
4. private $list_view; 5. private $create_view; 6. private $update_view; These members are private because I want to limit visibility only to this class. In the construct method the model and view objects are created using the five members: view plaincopy to clipboardprint? 1. 2. 3. 4. 5. $this->album_model = new Album_Model; $this->genre_model = new Genre_Model; $this->list_view = new View('list'); $this->update_view = new View('update'); $this->create_view = new View('create');
To create a model object use this syntax: view plaincopy to clipboardprint? 1. $obj_name = new Name_Model; To create a view object, use this syntax: view plaincopy to clipboardprint? 1. $obj_name = new View('view_filename_without_extension'); Now there are two objects to access the album and genre model, and three objects to access the views needed to render the presentation. The index method call the show_albums_list method that lists all albums stored in the database. view plaincopy to clipboardprint? 1. $albums_list = $this->album_model->get_list(); 2. $this->list_view->set('albums_list',$albums_list); 3. $this->list_view->render(TRUE); In this method you can see how the model and view object are used to access relative methods. get_list is a model method (we will see it later) that returns all the albums stored in the database. The result is saved in the $album_list array. To pass the result array from the controller to the view, the set method is called on the view object. This method requires two parameters: a new empty variable (album_list) to contain data of an existing variable ($album_list). Now the new variable album_list contains the $album_list array (we will see later how to show the content in the view). The method render, with the TRUE parameter, is necessary to output data to the browser. The show_create_editor method shows the user interface to insert a new album. view plaincopy to clipboardprint? 1. $this->create_view->set('genres_list',$this->get_genres_list()); 2. $this->create_view->render(TRUE); The list of the genres is passed to the view. The show_update_editor method shows the user interface to update an existing album. view plaincopy to clipboardprint?
1. 2. 3. 4. 5. 6. 7.
read is a model method (we will see it later) that returns data ($album_data) of the album with an id equal to $id. Then, every single element of the returned data album is passed to the view. The create method receives data, for a new album, from the view and data are stored in the database. view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. $album_data=array( 'name' => $this->input->post('name'), 'author' => $this->input->post('author'), 'genre_id' => $this->input->post('genre_id') ); $this->album_model->create($album_data); url::redirect('album');
$album_data is an array that contains the POST data from the view. To save the album, the array is passed to the create model method. The last line is a call to a helper method. Helpers are simply functions that assist you with development. The helper classes are automatically loaded by the framework. Helpers are declared as static methods of a class, so there is no need to instantiate the class. In this case the method redirect of the helper url is called and tells Kohana to redirect the browser to the album controller. This avoids a new insert (for example pressing F5). Helpers are simply functions that assist you with development. The update and delete methods work in the same manner as the create method above. The last method get_genres_list gets the genres list from the model ($db_genres_list) and builds a new array ($genres_list) for the select box in the views. view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. $db_genres_list = $this->genre_model->get_list(); $genres_list = array(); if(sizeof($db_genres_list) >= 1) { foreach($db_genres_list as $item) { $genres_list[$item->id] = $item->name; } } return $genres_list;
Album_Model must have the Model class as (grand)parent Here is the album model code. Create a file called album.php in application/models/ and paste the code below on it. view plaincopy to clipboardprint? 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. <?php defined('SYSPATH') OR die('No direct access allowed.'); class Album_Model extends Model { private $album_table; private $genre_table; public function __construct() { parent::__construct(); $this->album_table = 'albums'; $this->genre_table = 'genres'; } public function read($id) { $this->db->where('id', $id); $query = $this->db->get($this->album_table); return $query->result_array(); } public function delete($id) { $this->db->delete($this->album_table, array('id' => $id)); } public function update($id,$data) { $this->db->update($this->album_table, $data, array('id' => $id)); } public function create($data) { $this->db->insert($this->album_table, $data); } public function get_list() { $this->db->select('albums.id as id,albums.name as name,albums.author as author, genres.name as genre' $this->db->from($this->album_table); $this->db->join($this->genre_table,'genres.id','albums.genre_id'); $query = $this->db->get(); return $query->result_array(); } }
All the methods in the models make use of the Query builder syntax. This Kohana tool speeds up database development times and simplify the queries creation. Two members variables are declared at the top of the class:
view plaincopy to clipboardprint? 1. private $album_table; 2. private $genre_table; These members are private because I want to limit the visibility only to this class. They are the containers for the database tables names. The first line in the constructor method loads the Kohana database library into $this->db. In the second and third lines the two class members are initialized. view plaincopy to clipboardprint? 1. parent::__construct(); 2. $this->album_table = 'albums'; 3. $this->genre_table = 'genres'; The query in the read method retrieves album records that have a certain identifier ($id). view plaincopy to clipboardprint? 1. $this->db->where('id', $id); 2. $query = $this->db->get($this->album_table); 3. return $query->result_array(); The query in the delete method deletes the albums table row that have a certain identifier ($id). view plaincopy to clipboardprint? 1. $this->db->delete($this->album_table, array('id' => $id)); 2. The query in the update method updates the albums table row that has a certain identifier ($id) with new values from the $data array. view plaincopy to clipboardprint? 1. $this->db->update($this->album_table, $data, array('id' => $id)); 2. The $data array must contain record names as keys of the array, and value as values of the array. The $data array must have this form: view plaincopy to clipboardprint? 1. $data = array( 2. 'name' => 'album_name', 3. 'author' => 'author_name', 4. 'genre_id' => 'genre_id' 5. ); 6. The query in the create method inserts a new record with values of the $data array. view plaincopy to clipboardprint? 1. $this->db->insert($this->album_table, $data); 2. The $data array must have this form:
view plaincopy to clipboardprint? 1. $data = array( 2. 'id' => 'album_id', 3. 'name' => 'album_name', 4. 'author' => 'author_name', 5. 'genre_id' => 'genre_id' 6. ); 7. The query in the get_list method retrieves all the albums rows. view plaincopy to clipboardprint? 1. 2. 3. 4. 5. $this->db->select('albums.id as id,albums.name as name,albums.author as author, genres.name as genre'); $this->db->from($this->album_table); $this->db->join($this->genre_table,'genres.id','albums.genre_id'); $query = $this->db->get(); return $query->result_array();
Now, the genre model. Create a file called genre.php in application/models/ and paste the code below it: view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. <?php defined('SYSPATH') OR die('No direct access allowed.'); class Genre_Model extends Model { private $genre_table; function __construct() { parent::__construct(); $this->genre_table = 'genres'; } function get_list() { $query = $this->db->get($this->genre_table); return $query->result_array(); } }
This model is very simple so Ill waste no further time to comment upon it. The Models and the controller are ready to go. Lets now work on the Views.
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.
/DTD/xhtml1-strict.dtd"> <html> <head> <?php echo html::stylesheet(array ( 'assets/css/style' ), array ( 'screen' ), FALSE); ?> <title>CD COLLECTION</title> </head> <body> <?php echo html::image('assets/images/add.png'); echo html::anchor('album/show_create_editor', 'Add new album'); ?> <table class="list" cellspacing="0"> <tr> <td colspan="5" class="list_title">CD Collection</td> </tr> <tr> <td class="headers">Album name</td> <td class="headers">Author</td> <td colspan='3' class="headers">Genre</td> </tr> <?php foreach($albums_list as $item) { echo "<tr>"; echo "<td class='item'>".$item->name."</td>"; echo "<td class='item'>".$item->author."</td>"; echo "<td class='item'>".$item->genre."</td>"; echo "<td class='item'>".html::anchor('album/delete/'.$item->id,html::image('assets/images /delete.png'))."</td>"; echo "<td class='item'>".html::anchor('album/show_update_editor /'.$item->id,html::image('assets/images/edit.png'))."</td>"; echo "</tr>"; } ?> </table> </body> </html>
This view shows an html page containing a list of all albums. This list has been created using foreach loop that prints the information in an html table. For each album row, there are two images: a red cross and a pocketbook. They link respectively the controller delete method and the update method. Both pass the album id to the album controller using a get request. Above the list there is a button to create new albums. In this code we also make use of an html helper provided by Kohana that speeds up operations to write html pages. Lets now create a file called create.php in application/views/. view plaincopy to clipboardprint?
1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1 /DTD/xhtml1-strict.dtd"> 2. <html> 3. <head> 4. <?php 5. echo html::stylesheet(array 6. ( 7. 'assets/css/style' 8. ), 9. array 10. ( 11. 'screen' 12. ), FALSE); 13. ?> 14. <title>CD COLLECTION</title> 15. </head> 16. <body> 17. <?php echo form::open('album/create'); ?> 18. <table class='editor'> 19. <tr> 20. <td colspan='2' class='editor_title'>Create new album</td> 21. </tr> 22. <?php 23. echo "<tr>"; 24. echo "<td>".form::label('name', 'Name: ')."</td>"; 25. echo "<td>".form::input('name', '')."</td>"; 26. echo "</tr>"; 27. 28. echo "<tr>"; 29. echo "<td>".form::label('author', 'Author: ')."</td>"; 30. echo "<td>".form::input('author', '')."</td>"; 31. echo "<tr/>"; 32. 33. echo "<tr>"; 34. echo "<td>".form::label('genre', 'Genre: ')."</td>"; 35. echo "<td>".form::dropdown('genre_id',$genres_list)."</td>"; 36. echo "<tr/>"; 37. 38. echo "<tr>"; 39. echo "<td colspan='2' align='left'>".form::submit('submit', 'Create album')."</td>"; 40. echo "</tr>"; 41. ?> 42. </table> 43. <?php echo form::close(); ?> 44. </body> 45. </html> The last but not the least is the update view. Lets create a file called update.php in application/views/. view plaincopy to clipboardprint? 1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1 /DTD/xhtml1-strict.dtd"> 2. <html> 3. <head> 4. <?php 5. echo html::stylesheet(array 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. 47. 48. 49.
'assets/css/style' ), array ( 'screen' ), FALSE); ?> <title>CD COLLECTION</title> </head> <body> <?php echo form::open('album/update'); ?> <table class='editor'> <tr> <td colspan='2' class='editor_title'>Update album</td> </tr> <?php echo "<tr>"; echo "<td>".form::label('name', 'Name: ')."</td>"; echo "<td>".form::input('name', $name)."</td>"; echo "</tr>"; echo "<tr>"; echo "<td>".form::label('author', 'Author: ')."</td>"; echo "<td>".form::input('author', $author)."</td>"; echo "<tr/>"; echo "<tr>"; echo "<td>".form::label('genre', 'Genre: ')."</td>"; echo "<td>".form::dropdown('genre_id',$genres_list, $genre_id)."</td>"; echo "<tr/>"; echo "<tr>"; echo "<td colspan='2' align='left'>".form::submit('submit', 'Update album')."</td>"; echo "</tr>"; ?> </table> <?php echo form::hidden('album_id',$album_id); echo form::close(); ?> </body> </html>
The first one is a simple editor that enables the user to insert information about a new album. The fields like author and name will be inserted using an html input and genre using a combo box. Once the user clicks on the create button, all information is passed, as a POST request, to the create/update method in the album controller. When the controller receives these posted variables, it calls the model that inserts a new album into the database. The forms, in both views, makes use of Kohana form helper. To give a bit of style to our application, create the assets folder in the Kohana root at the same level of the application folder. Now, open it and create two new folders: css and images. In the css folder create a new file called style.css and paste this: view plaincopy to clipboardprint?
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. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57.
a{ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ; font-weight: normal; font-size: 12px; color: #00F; vertical-align:text-top; } img { border: 0; } label { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ; font-weight: normal; font-size: 12px; } input { border: 1px solid #000; } select { width:185px; } table.editor { text-align: center; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ; font-weight: normal; font-size: 11px; color: #fff; width: 280px; background-color: #666; border: 0px; border-collapse: collapse; border-spacing: 0px; } table.editor td.editor_title { background-color: #666; color: #fff; padding: 4px; text-align: left; font-weight: bold; font-size: 16px; } table.editor td { padding: 4px; } table.list {
58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97.
text-align: center; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ; font-weight: normal; font-size: 11px; color: #fff; width: 280px; background-color: #666; border: 0px; border-collapse: collapse; border-spacing: 0px; } table.list td.item { background-color: #CCC; color: #000; padding: 4px; text-align: left; border: 1px #fff solid; } table.list td.list_title,table.list td.headers { background-color: #666; color: #fff; padding: 4px; text-align: left; border-bottom: 2px #fff solid; font-weight: bold; } table.list td.list_title { font-size: 16px; } table.list td.headers { font-size: 12px; }
Now copy the following images to the images folder: Thats all. Point your browser to http://localhost/kohana/index.php/album and you should see something similar to this:
If you try to create a new album or to edit an existing one you should see something similar to this:
Like
By Cristian Gil
Hello, my name is Cristian Gil, I'm a freelance PHP/MySQL developer and I work in the beautiful city of Brescia, Italy. As a Web developer, I'm specialise in building custom PHP/MySQL web applications and Kohana and Codeigniter frameworks are my main tools. My skillset also includes xHTML, CSS, JQuery. My development environment of choice is Ubuntu using Aptana Studio as editor/debugger. What else to say...follow nettuts for more tutorials by me.