📜 ⬆️ ⬇️

Remaking the CD Collection application

So, in the previous topic (only visible to blog subscribers!) I referred to an article about Kohana posted on NetTuts + . Since there are flaws in the application described in it, I propose to find and neutralize them.

1. Optimizing work with templates (VIEWS)



You are not confused by the need for each template to create a page from scratch (including the doctype, styles, etc.)? So after all not for long and on a statics to pass. Therefore, the first thought is to implement nested templates.

In all the templates there is a certain common part, which we put into a separate file and will be connected in each controller method. Create an index.php file in the views folder:
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  1. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  2. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  3. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  4. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  5. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  6. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  7. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  8. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  9. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  10. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  11. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  12. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  13. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  14. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  15. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  16. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  17. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  18. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  19. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  20. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  21. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  22. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  23. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
  24. <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > < html > < head > <? php echo html::stylesheet ( array ( 'assets/css/style' ), array ( 'screen' ), FALSE ); ? > < title > CD COLLECTION </ title > </ head > < body > <!-- BEGIN NAVIGATION MENU --> < ul id ="navigation" > < li ><? =html::anchor('album', 'Albums')? ></ li > </ ul > <!-- END NAVIGATION MENU --> <? =$content? > </ body > </ html > * This source code was highlighted with Source Code Highlighter .

')
I made a header for the pages in a separate file, and also added the navigation menu from myself (for now, from one item, but later we will expand it). Note the $ content variable, which will contain the results of the work of the Album_Controller controller. Add the following lines to the style.css file (rules for the navigation menu):

  1. #navigation {
  2. overflow: hidden;
  3. list-style-type: none;
  4. }
  5. #navigation li {
  6. float: left;
  7. margin-left: 0.5em;
  8. border: 1px solid black;
  9. }
  10. #navigation li a {
  11. font-size: 14px;
  12. display: block;
  13. padding: 2px 5px;
  14. text-decoration: none;
  15. color: #fff;
  16. background: # 666;
  17. }
* This source code was highlighted with Source Code Highlighter .


Next, cut out all the excess of the available templates. I will show the final result using the list.php file as an example :

  1. <? php defined ( 'SYSPATH' ) or die ( 'No direct script access.' );
  2. echo html :: image ( 'assets / images / add.png' );
  3. echo html :: anchor ( 'album / show_create_editor' , 'Add new album' );
  4. ? >
  5. < table class = "list" cellspacing = "0" >
  6. < tr >
  7. < td colspan = "5" class = "list_title" > CD Collection </ td >
  8. </ tr >
  9. < tr >
  10. < td class = "headers" > Album name </ td >
  11. < td class = "headers" > Author </ td >
  12. < td colspan = '3' class = "headers" > Genre </ td >
  13. </ tr >
  14. <? php
  15. foreach ($ albums_list as $ item )
  16. {
  17. echo " < tr > ";
  18. echo " < td class = 'item' > ". $ item- > name. " </ td > ";
  19. echo " < td class = 'item' > ". $ item- > author. " </ td > ";
  20. echo " < td class = 'item' > ". $ item- > genre- > name. " </ td > ";
  21. echo " < td class = 'item' > " .html :: anchor ('album / delete /'.$ item- > id, html :: image (' assets / images / delete.png ')). " </ td > ";
  22. echo " < td class = 'item' > " .html :: anchor ('album / show_update_editor /'.$ item- > id, html :: image (' assets / images / edit.png ')). " </ td > ";
  23. echo " </ tr > ";
  24. }
  25. ? >
  26. </ table >
* This source code was highlighted with Source Code Highlighter .


As you can see, now only information directly related to the output of the list of albums remains in the template. However, it is not enough to change only the templates, you will have to climb into the Album_Controller controller (I show changes in the show_albums_list () method):

  1. // now our controller is a descendant of Template_Controller!
  2. class Album_Controller extends Template_Controller
  3. {
  4. // set the basic template
  5. public $ template = 'index';
  6. ...
  7. private function show_albums_list ()
  8. {
  9. $ albums_list = $ this- > album_model- > get_list ();
  10. $ this- > template- > content = View :: factory ('list')
  11. - > set ('albums_list', $ albums_list);
  12. }
  13. ...
* This source code was highlighted with Source Code Highlighter .


First, we did the inheritance from Template_Controller . Those. Now the $ this-> template property will appear in each controller, which will contain the basic template (don't be confused by the string value, the $ template variable in the controller will become an object of the View class). In addition, by default, this basic template will be automatically displayed, i.e. calling $ this-> template-> render (TRUE) at the end of each method is no longer needed.

Secondly, you can put as many other templates as you like (and other objects in general) in each template. So, in the example above, we set the ' content ' variable that contains the list.php template in the $ this-> template property , and in turn we passed the variable ' albums_list '. Thus, we no longer need to store variables of type $ list_view (remove them from the controller).

You can use several methods to set the value of variables in a template. The set () method is useful in the case of sequential manipulations on an object; in this case, such a chain of calls is obtained. Assigning values ​​directly ( $ this-> template-> content = ... ) does the same, but reads more pleasantly (IMHO).


In principle, nothing has changed, but now, if we need to change the list of css-files or items in the navigation menu, we will edit only one file ( index.php ).

And do not confuse the URL of the application?



Of course, localhost / kohana / index.php / album somehow does not look. Since all progressive humanity has long used .htaccess , but at the office. The site has information about its configuration , we make a small adjustment in the config / config.php file :

  1. / **
  2. * Name of the front controller for this application. Default: index.php
  3. *
  4. * This can be removed by using URL rewriting.
  5. * /
  6. $ config ['index_file'] = '';
* This source code was highlighted with Source Code Highlighter .


Now the name of the front controller ( index.php ) in the URL can be omitted. Additionally, we configure default routing on our Album_Controller controller:

  // config / routes.php
 $ config ['_ default'] = 'album'; 


Now localhost / kohana will lead the same way as localhost / kohana / index.php / album .

Using models by the author



Consider the Album_Model-> read ($ id) method, which should return an album with the identifier $ id :

  1. public function read ($ id)
  2. {
  3. $ this- > db- > where ('id', $ id);
  4. $ query = $ this- > db- > get ($ this- > album_table);
  5. return $ query- > result_array ();
  6. }
* This source code was highlighted with Source Code Highlighter .


I don’t understand why to fetch an array of records from the database if only one album is expected? We remake a method:

  1. public function read ($ id)
  2. {
  3. return $ this- > db
  4. - > where ('id', $ id)
  5. - > get ($ this- > album_table)
  6. - > current ();
  7. }
* This source code was highlighted with Source Code Highlighter .


Since we are only interested in one record, we use the current () method to get the first line. If no records were found, FALSE will be returned. Accordingly, changes will be made to show_update_editor () (for example, instead of saving the album fields separately, you can simply save the entire record) and you’ll have something like this:

  1. public function show_update_editor ($ id)
  2. {
  3. $ album_data = $ this- > album_model- > read ($ id);
  4. if (FALSE === $ album_data)
  5. Event :: run ('system.404');
  6. $ this- > template- > content = View :: factory ('update')
  7. - > set ('album', $ album_data)
  8. - > set ('genres_list', $ this- > get_genres_list ());
  9. }
* This source code was highlighted with Source Code Highlighter .


A check for the existence of an edited album has been added to the beginning of the method, and if it does not find it, the system message ' system.404 ' is generated, leading to the corresponding error. All information about the found album is saved in the template as a $ album variable, so we will make changes to the views / update.php file:

  1. <? php echo form :: open ( 'album / update' ); ? >
  2. < table class = 'editor' >
  3. < tr >
  4. < td colspan = '2' class = 'editor_title' > Update album </ td >
  5. </ tr >
  6. <? php
  7. echo " < tr > ";
  8. echo " < td > " .form :: label ('name', 'Name:'). " </ td > ";
  9. echo " < td > " .form :: input ('name', $ album- > name). " </ td > ";
  10. echo " </ tr > ";
  11. echo " < tr > ";
  12. echo " < td > " .form :: label ('author', 'Author:'). " </ td > ";
  13. echo " < td > " .form :: input ('author', $ album- > author). " </ td > ";
  14. echo " < tr /> ";
  15. echo " < tr > ";
  16. echo " < td > " .form :: label ('genre', 'Genre:'). " </ td > ";
  17. echo " < td > " .form :: dropdown ('genre_id', $ genres_list, $ album- > genre_id). " </ td > ";
  18. echo " < tr /> ";
  19. echo " < tr > ";
  20. echo " < td colspan = '2' align = 'left' > " .form :: submit ('submit', 'Update album'). " </ td > ";
  21. echo " </ tr > ";
  22. ? >
  23. </ table >
  24. <? php
  25. echo form :: hidden ( 'album_id' , $ album- > id);
  26. echo form :: close ();
  27. ? >
* This source code was highlighted with Source Code Highlighter .


ORM to the stage!



All changes made were mostly cosmetic. However, it is time to show one of the most popular tools in Kohana - the ORM library. Why manually write various methods of sampling from the database, if there is a ready-made library with numerous possibilities?

Let's bring the Album_Model and Genre_Model models to ORM - see:

  1. class Album_Model extends ORM
  2. {
  3. protected $ belongs_to = array ('genre');
  4. }
  5. class Genre_Model extends ORM {
  6. protected $ has_many = array ('albums');
  7. }
* This source code was highlighted with Source Code Highlighter .


Everything! More (for now) for our needs do not need anything. But the most interesting is how we will use ORM in the controller. Let's look at an example of displaying a list of albums:

  1. private function show_albums_list ()
  2. {
  3. $ albums_list = ORM :: factory ('album') - > with ('genre') - > find_all ();
  4. $ this- > template- > content = View :: factory ('list')
  5. - > set ('albums_list', $ albums_list);
  6. }
* This source code was highlighted with Source Code Highlighter .


The ORM :: factory ('album') -> with ('genre') -> find_all () record can be translated as “select all albums with genre information”, i.e. join between the albums and genres tables will automatically be generated. As a result, the ORM_Iterator object will be returned, but we will simply work with it as with an array. ;)

In fact, if we comment out the method call with () , everything will still work! The ORM implemented lazy loading ( lazy loading ), so when you try to access the $ album-> genre property, a database query will be made. It is simply better to do one join than to make additional selections of genres in a loop. If you do not want to manually select genres with albums each time, add the following line to Album_Model :

  protected $ load_with = array ('genre'); 


After that, genres will be loaded with albums automatically.


Forming a drop-down list of genres



As you remember, the get_genres_list () method was created to obtain a list of genres in the Album_Controller controller:

  1. private function get_genres_list ()
  2. {
  3. $ db_genres_list = $ this- > genre_model- > get_list ();
  4. $ genres_list = array ();
  5. if (sizeof ($ db_genres_list) > = 1)
  6. {
  7. foreach ($ db_genres_list as $ item)
  8. {
  9. $ genres_list [$ item- > id] = $ item- > name;
  10. }
  11. }
  12. return $ genres_list;
  13. }
* This source code was highlighted with Source Code Highlighter .


Let's wave a magic wand and the method will turn into one line:

  1. private function get_genres_list ()
  2. {
  3. return ORM :: factory ('genre') - > find_all () - > select_list ('id', 'name');
  4. }
* This source code was highlighted with Source Code Highlighter .


Creating and editing ORM objects



Finally - the most delicious. The create () and update () methods do not perform any checks, but simply try to slip the data entered into the Album_Model model. But Kohana has a wonderful Validation library, which is very convenient to use with ORM !

To begin with, let's add a few lines to the Album_Model model:

  1. public function Validate (array & $ array, $ save = FALSE)
  2. {
  3. $ array = Validation :: factory ($ array)
  4. - > pre_filter ('trim')
  5. - > add_rules ('name', 'required')
  6. - > add_rules ('author', 'required')
  7. - > add_rules ('genre_id', 'required')
  8. - > add_callbacks ('name', array ($ this, '_album_available'));
  9. return parent :: validate ($ array, $ save);
  10. }
  11. public function _album_available (Validation $ array, $ field) {
  12. $ result = (bool)! $ this- > db
  13. - > where (array ('name' = > $ array ['name'], 'author' = > $ array ['author'], 'id! =' = > $ this- > id))
  14. - > count_records ($ this- > table_name);
  15. if (! $ result) $ array- > add_error ($ field, 'album_exists');
  16. return $ result;
  17. }
* This source code was highlighted with Source Code Highlighter .


This is the validate () method, which is actually responsible for validating the entered data using the Validation library, and a non-standard rule (more precisely, even a callback ) that is responsible for the uniqueness of the Album + Artist combination. Using them is very simple, consider the modified create () method:

  1. public function create ()
  2. {
  3. if ($ this- > input- > post ())
  4. {
  5. $ data = array
  6. (
  7. 'name' = > NULL,
  8. 'author' = > NULL,
  9. 'genre_id' = > NULL
  10. );
  11. $ data = arr :: overwrite ($ data, $ this- > input- > post ());
  12. $ album = ORM :: factory ('album');
  13. if ($ album- > validate ($ data, TRUE)) {
  14. url :: redirect ('album');
  15. }
  16. else {
  17. Session :: instance () - > set ('errors', $ data- > errors ('album'));
  18. Session :: instance () - > set ('data', $ data- > as_array ());
  19. }
  20. }
  21. url :: redirect ('album / show_create_editor');
  22. }
* This source code was highlighted with Source Code Highlighter .


We consistently checked the data availability in $ _POST , loaded the fields of interest to us into the $ data array (the overrrite () method of the arr helper is used for this) and sent it to the validate () method for verification. The second parameter, set to TRUE , means that in case of a successful check, the ORM object will be saved. If there is a validation error, we save the description of the errors and the current values ​​from the form in the session (no one likes to re-enter numerous form fields because of a tiny typo), and redirect back to the editor. Accordingly, it is necessary to make changes to the show_create_editor () method and its template ( create.php ):

  1. public function show_create_editor ()
  2. {
  3. $ errors = Session :: instance () - > get_once ('errors', array ());
  4. $ data = array ('name' = > '', 'author' = > '', 'genre_id' = > '');
  5. $ data = arr :: overwrite ($ data, Session :: instance () - > get_once ('data', array ()));
  6. $ genres_list = $ this- > get_genres_list ();
  7. $ this- > template- > content = View :: factory ('create')
  8. - > set ('genres_list', $ genres_list)
  9. - > set ('errors', $ errors)
  10. - > set ('data', $ data);
  11. }
* This source code was highlighted with Source Code Highlighter .


  1. <? php echo form :: open ( 'album / create' ); ? >
  2. <? php foreach ($ errors as $ error )
  3. echo " < div class = 'error' > ". $ error. " </ div > ";? >
  4. < table class = 'editor' >
  5. < tr >
  6. < td colspan = '2' class = 'editor_title' > Create new album </ td >
  7. </ tr >
  8. <? php
  9. echo " < tr > ";
  10. echo " < td > " .form :: label ('name', 'Name:'). " </ td > ";
  11. echo " < td > " .form :: input ('name', $ data ['name']). " </ td > ";
  12. echo " </ tr > ";
  13. echo " < tr > ";
  14. echo " < td > " .form :: label ('author', 'Author:'). " </ td > ";
  15. echo " < td > " .form :: input ('author', $ data ['author']). " </ td > ";
  16. echo " < tr /> ";
  17. echo " < tr > ";
  18. echo " < td > " .form :: label ('genre', 'Genre:'). " </ td > ";
  19. echo " < td > " .form :: dropdown ('genre_id', $ genres_list, $ data ['genre_id']). " </ td > ";
  20. echo " < tr /> ";
  21. echo " < tr > ";
  22. echo " < td colspan = '2' align = 'left' > " .form :: submit ('submit', 'Create album'). " </ td > ";
  23. echo " </ tr > ";
  24. ? >
  25. </ table >
  26. <? php echo form :: close (); ? >
* This source code was highlighted with Source Code Highlighter .


Most of the changes in the method are an attempt to get data from the session and substitute it into a template for display to the user. Errors are displayed at the very beginning of the form, but no one bothers to display them in front of the corresponding input fields. Similar changes must be made to the update () , show_update_redactor () and update.php template.

Error Validation



Notice the $ data-> errors ('album') method in line 17 of the create () method? A bit strange for an array, right? The fact is that after the $ data array has been passed to the validate () method, it becomes a Validation object. And it already has an errors () method that returns validation errors. If you transfer to it the name of the i18n file, the errors will be translated using the specified file. Let's make a translation of possible errors:

  1. // file i18n / ru_RU / album.php
  2. <? php defined ( 'SYSPATH' ) or die ( 'No direct script access.' );
  3. $ lang = array
  4. (
  5. 'name' = > array (
  6. 'required' = > 'Album name not specified',
  7. 'album_exists' = > 'Combination album + artist has already been added',
  8. ),
  9. 'author' = > array
  10. (
  11. 'required' = > 'Artist name not specified',
  12. ),
  13. 'genre_id' = > array
  14. (
  15. 'required' = > 'No genre of album selected',
  16. ),
  17. );
* This source code was highlighted with Source Code Highlighter .


  1. // file i18n / en_US / album.php
  2. <? php defined ( 'SYSPATH' ) or die ( 'No direct script access.' );
  3. $ lang = array
  4. (
  5. 'name' = > array (
  6. 'required' = > 'Album name required',
  7. 'album_exists' = > 'Album & artist combination already exists',
  8. ),
  9. 'author' = > array
  10. (
  11. 'required' = > 'Author name required',
  12. ),
  13. 'genre_id' = > array
  14. (
  15. 'required' = > 'Genre required',
  16. ),
  17. );
* This source code was highlighted with Source Code Highlighter .


I made two files - in Russian and in English, text resources are grouped by the names of the form fields. Guess which file will be used by default in our application? Of course, English. Copy the file locale.php from the system / config folder and correct the values ​​for the Russian language:

  1. <? php defined ('SYSPATH') OR die ('No direct access allowed.');
  2. / **
  3. * @package Core
  4. *
  5. * Default language locale name (s).
  6. * First item must be a valid i18n directory name, subsequent items are alternative locales
  7. * for OS's that don't support the first (eg Windows). The first valid locale in the array will be used.
  8. * @see php.net/setlocale
  9. * /
  10. $ config ['language'] = array ('en_US', 'Russian_Russia');
  11. / **
  12. * Locale timezone. Defaults to use the server timezone.
  13. * @see php.net/timezones
  14. * /
  15. $ config ['timezone'] = '';
* This source code was highlighted with Source Code Highlighter .


Results



It seems that all the main points I told. Try to make changes to the project NetTuts ' and, if that - you can peek into the archive I got. Of course, there are many different trifles missing (sorting, sampling by certain artists or genres), but in the framework of this article it is unrealistic. If you want to work independently, you can also put the artists in a separate table, it will require some effort to change the controllers and templates.

Source: https://habr.com/ru/post/64084/


All Articles