Kohana PHP

Object Relational Mapping guide

Written by Sam Clark Version 1.4 (Draft)

http://sam.clark.name

Kohana PHP Object Relational Mapping guide

Contents
Introduction Credits and contributions What is this ORM thing anyway? Creating an ORM class Using Customer_Model with Customer_Controller Extending the behaviour of Customer_Model Creating ORM relationships
One to many relationship Many to many relationship ORM relationships summary

3 3 4 5 8 14 16
16 18 20

Using ORM relationships in your code
find_related add remove

21
21 21 21

Appendix A - Full Files
customers.sql customer_addresses.sql addresses.sql customers_addresses.sql application/models/customer.php application/models/customer_address.php application/models/address.php application/controllers/customer.php

22
22 22 23 23 24 24 24 25
2

ORM delivers a robust data manipulation toolset that provides almost everything you could possibly need to write clean.kohanaphp. sometimes in the third and sometimes the person is missing altogether.Kohana PHP Object Relational Mapping guide Introduction The impetus for writing this guide came from discovering there was no real documentation for my favourite feature within Kohana PHP . This document originally started as a blog post but as it started to grow. This is currently only the first draft and I will update in time . I decided to create a structured document rather than a meandering post.a brief introduction” at http://learn.ORM guide” post (http://sam. I decided to try and finish the missing bits regarding creating relationships.clark.kohanaphp. After reading through many of the posts within the Kohana PHP forum. Hopefully this should help the guys working hard to develop Kohana PHP with some extra documentation in the future. plus reading an introduction to ORM on the Kohana PHP Development blog.but this will be helped if you help me by telling me what works for you. I have been using and waxing lyrical about Kohana PHP for the last four months on my blog (http://sam. just post them on my blog under the “Kohana PHP . “it will get better”. For this I can only apologise and say. as well as on the geekUp mailing list. You can read more about ORM at http://doc.com/libraries/orm . Because of this.name/2008/03/31/orm-guide/).0 UK: England & Wales License. If you have any comments.com. sometimes the language in this document is in the first person.com/2008/02/14/kohanas-orm-a-brief-introduction/. especially what doesn’t and anything you think I missed out.clark.ORM.kohanaphp. Based on a work at learn. Credits and contributions Proof reading and error correction by phelz Further proof reading and error corrections by atomless and Louis Licence Kohana PHP Object Relational Mapping Guide by Sam Clark is licensed under a Creative Commons Attribution-Non-Commercial-Share Alike 2. I was inspired to write this document after reading “Kohana’s ORM .name). 3 . I am a PHP developer based in South London. fast code to do wonderful things.

manipulate the data in any way you like and then save the result back to the database without one line of SQL. as well as the Kohana PHP framework. The assumption is that you are already familiar with PHP and MySQL. ORM will even automatically save your object back database if you wish it too. You may be thinking that this is just a database abstraction layer and you wouldn’t be entirely wrong. The idea of an Object Relational Mapping is to allow manipulation and control of data within a DB as though it was a PHP object. It goes further by providing methods for maintaining relationships across tables (joins) and finding data by criteria. I move on to the more complex task of creating relationships between models. 4 . This document provides a very basic introduction to ORM for the uninitiated. it allows you to tailor how data moves to and from different tables within your Database. Using ORM within your code allows you to pull data from your database. Once ORM is explained. But ORM goes further than just removing SQL code from your PHP code.Kohana PHP Object Relational Mapping guide What is this ORM thing anyway? ORM (Object Relational Mapping) is an object that mirrors data within a database.

This means that the core contents of your ORM class are going to be very similar across differing data sets. `title` TEXT NOT NULL COMMENT 'Title'. If you have a table for customers within your database. but more on that later. The SQL code creates a table with five fields. To create your ORM class to map to the table you have just created you will need to open your editor and navigate to the application/models folder. 3. 8. If you’re planning to use ORM within Kohana you need to adhere to some important naming conventions when naming tables in your database. 6. as you can also find and return many records.kohanaphp. CREATE TABLE `customers` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'. To map this table to a ORM class. 5.for more. you need to ensure your ORM class is named using a singular form. 2. Notice the use of the singular name following our naming convention.php’. Now you have your database table correctly set up. but each instance of your ORM model will only work on one of those records. The main convention you need to remember is singular and pluralisation of data set names. then you will need to call it something like ‘customers’ (always lowercase). ‘Customer_Model’ for example.com/libraries/orm) Using plural and singular versions of data set names is good practice as your customers table will store many customer records. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple customer table' This will create your very simple customer table. 5 . The SQL code for creating your customers table within MySQL is as follows. (The capitalisation and inclusion of ‘_Model’ is mandatory and should be noted as your model will throw and error if the names are not formatted properly . 4. `firstname` TEXT NOT NULL COMMENT 'Firstname'. `surname` TEXT NOT NULL COMMENT 'Surname'. giving you all the methods of ORM through inheritance. see http://doc. you can forget SQL and begin creating your ORM class to manipulate data within the this table. `email` TEXT NOT NULL COMMENT 'Email Address'. This is not always the case when using ORM. 1.Kohana PHP Object Relational Mapping guide Creating an ORM class How does one create an ORM class to use in Kohana? First you will need to create your table within your database. 7. indexed by a unique id that auto-increments. then create a new file called ‘customer. All of your ORM classes are going to be extensions of the core ORM class.

9. 21. } public function __get( $key ) { return parent::__get( $key ). 10. but the inclusion demonstrates what the default ORM method calls are for constructing an instance. 17. 1. 13. 8. 15. class Customer_Model extends ORM { } ?> That’s it. If you do not supply the id of a record. 5. not the database. 1. when you set a value using this method you are only updating your model within PHP. 7. 4. 7. A quick note on the __set() method. 12. <?php defined('SYSPATH') or die('No direct script access. When Customer_Model is initiated the __construct() method is called. Using this code you could now begin manipulating your data within your customers table. class Customer_Model extends ORM { } ?> public function __construct( $id = FALSE ) { parent::__construct( $id ). 19. } Please note that the inclusion of these three methods is not required. 14. 16. ORM will assume this is a new record and insert it as such when you are finished. 18.id` within the database. Hopefully the __get() and __set() methods should be self explanatory. <?php defined('SYSPATH') or die('No direct script access. $value ) { parent::__set( $key . 5. 11. plus getting and setting data. } public function __set( $key .').'). 2. 3. This class constructor accepts an ‘id’ as the argument which is referring to the field `customers.Kohana PHP Object Relational Mapping guide Lets set up our Customer_Model for ORM use. 4. However this does not really show the inner workings of ORM. which in turn calls the ORM __construct() method. 2. so I’m going to add an additional couple of lines of code. 6. $value ). 20. 6 . 3. By default. 6. To set the data in stone you need to invoke the save() method using $my_customer_object->save() for example.

3. 2. public function __destruct() { $this->save(). use the first example. 1. public function __construct() { parent::__construct().Kohana PHP Object Relational Mapping guide If you want to reduce your lines of code or do not want to have to remember to save each time. } Which method you use will depend on your application logic. $my_customer_object = new Customer_Model(). 2. $this->auto_save = TRUE. $my_customer_object->auto_save = TRUE. You could also achieve this by adding this __destruct() method to your Customer_Model. If you want to automatically save on an ad hoc basis. 1. you can invoke the ‘auto_save’ feature of ORM that saves the instance state upon destruction. you set ‘auto_save’ on your instance after initialisation within a controller. 5. 4. If you always want to automatically save your object state to the database I recommend one of the latter solutions. 3. 2. } Or you could set auto_save within your __construct() method in your Customer_Model. 7 . parent::__destruct(). 5. 1. To do this manually. 4.

it is now available throughout Kohana for use. 23. 12. 3. 8. 4. 11. 19. 7. 15. 20. 8 .Kohana PHP Object Relational Mapping guide Using Customer_Model with Customer_Controller With your Customer_Model saved. otherwise create a new record (handled by ORM) */ public function edit( $id = FALSE ) { } } This sets up the Customer_Controller class with three methods. 1. 28. <?php defined('SYSPATH') or die('No direct script access. 24. 10. 31. 26. It’s always good practice to at least hint at what this class * does **/ class Customer_Controller extends Controller { /** * Default controller behaviour. 13. 17. 27. 6. 2. 18. /** * My Customer Contoller.php to control my customer data. display a single record and edit records. 5. Now to set up the default behaviour by adding some code to the index() method. 16. This controller needs to show all customer data. Within the controllers folder I have created a file called customer.'). All models within application/models folder are automatically loaded for you so all you need to do is call it when ready. 9. 14. show all records in this case */ public function index() { } /** * View a record */ public function view( $id = FALSE ) { } /** * Edit a record if id supplied. 21. 25. Now we can concentrate on the individual methods in turn. 30. 22. 29.

10. 2. 7. the last lines of code output each customer record (Surname. {$customer->firstname}</ } $output . The next line uses ORM’s powerful db builder 1 syntax to find all records.com/libraries/orm#using_db_builder_methods 9 . but you could fix that by checking how many results find_all() returned. 9. 15. 4. It currently is not very clever because it will throw an error if there are no customers in the database. 14. Here is what the index() method is doing. First of all. 1 Read more about db builder at http://doc. we will use the view() method. 12. 16. 11. $customers = $customers->orderby(‘surname’. 5. Of course you can assign the results to another variable if desired. Firstname) to a buffer $output. 6. we want to output the results. echo $output. 3. As we are assigning the result back to our Customer_Model instance $customers. When you navigate to: http://<yourservername>/customer/ you will now see a list of all your customers.= “<li>{$customer->surname}. ‘asc’)->find_all(). 13. li>”.kohanaphp.Kohana PHP Object Relational Mapping guide 1. Using an ordered list. public function index() { $customers = new Customer_Model().= “</ol>”. it creates a new instance of our Customer_Model. } $output = “<ol>”. this instance is replaced by the result of the query. ordered alphabetically by surname. Finally the buffer is printed using echo. foreach( $customers as $customer ) { $output . this method will output a list of all registered customers. To concentrate on an individual customer record. Once the results are collected. When run. 8.

10 . h1>”. $output = “<h1>{$customer->surname}. 3. Forge creates and processes forms for you and can perform validation using Kohana PHP’s own validate module. but I’ll come back to this later when I add more methods to Customer_Model.you could use a 404 error here if you liked. or if record id is omitted then the user will be creating a new record. The view() method takes one argument. 6. 15. If no id is supplied then the output informs the user of their mistake . 5. With the data loaded. 12. 13. 14.= “<p>Email : {$customer->email}</p>”. This isn’t fully robust as we should check to see if the id supplied is valid. public { } function view( $id = FALSE ) if( !$id ) { $output = “You must supply an article id”. Finally we can echo our output. 2. but I prefer to be a little more informative. 10.kohanaphp. echo $output. I am going to use another Kohana PHP helper called Forge to do this and you can read more about all of this at http:// doc. If an id is supplied. 4.Kohana PHP Object Relational Mapping guide 1.com/addons/forge . we can populate our $output with the full name and email of the customer. } else { $customer = new Customer_Model( $id ). 7. which is the id of the record you wish to load. All that is to be done now is create our edit() method. 11. a new Customer_Model instance is created using the id submitted. 9. {$customer->firstname}</ } $output . Our edit method is going to either load an existing record and allow the user to edit it. 8.

22. I will step through what is happening here in blocks. 9. else $customer = new Customer_Model(). 4. 38. 27. finally a submit button to send the form. 13. 34.30]')->value( $customer->title ). $edit_form->input( ‘surname’ )->label( TRUE )->rules('required| length[2. The edit() method is certainly the most complicated. 25. } echo $edit_form->render(). 7. one hidden id. $customer->firstname = $edit_form->firstname->value. but then it has to do the most. $edit_form->hidden( ‘id’ )->value($id). 3. $edit_form->input( ‘firstname’ )->label( TRUE )->rules('required| length[2. 2. 20. 11 . 5. 23. 14. 11. $customer->title = $edit_form->title->value. 17. $edit_form->input( ‘email’ )->label( TRUE )->rules('required| length[2. $edit_form->input( ‘title’ )->label( TRUE )->rules('required| length[2. 18.50]|valid_email_rfc')->value( $customer->email ). 10. $customer->email = $edit_form->email->value. $customer = new Customer_Model( $id ). 39. public function edit( $id = FALSE ) { // Create a new form using Forge $edit_form = new Forge(). 8. 32.50]')->value( $customer->surname ). 28. 16. 31. 37. 12. } } else { } if ( $customer->save() ) { echo “<p>Record saved!</p>”. 6. 21. First we create a new Forge instance and then set up some fields. 24. $customer->surname = $edit_form->surname->value. } else { echo “<p>Problem saving record</p>”. four inputs for title. 29. 26. surname and email. $edit_form->submit( ‘Submit’ ).Kohana PHP Object Relational Mapping guide 1. 35. firstname. // If the form is valid if( $edit_form->validate() ) { if( $edit_form->id ) $customer = new Customer_Model( $edit_form->id->value ). 36.50]')->value( $customer->firstname ). 41. 30. 19. 15. 33. 40.

8. 15. 11. 18. $edit_form->input( ‘firstname’ )->label( TRUE )->rules('required| length[2. 16. } else { echo “<p>Problem saving record</p>”.50]')->value( $customer->surname ). Next we check if the form is valid. The code first establishes the edit type. 12 . 25. 24. 14. 27.30]')->value( $customer->title ). Once all of the fields customer are updated within the object. 19. if ( $customer->save() ) { echo “<p>Record saved!</p>”. 10. else $customer = new Customer_Model(). 6. 28. 33. 26. $customer->surname = $edit_form->surname->value.Kohana PHP Object Relational Mapping guide 3. 12. 7. 32. $customer->email = $edit_form->email->value. $edit_form->hidden( ‘id’ )->value($id). then this is a new customer record. $edit_form->input( ‘surname’ )->label( TRUE )->rules('required| length[2. 30. 9.50]')->value( $customer->firstname ). // If the form is valid if( $edit_form->validate() ) { if( $edit_form->id ) $customer = new Customer_Model( $edit_form->id->value ). 22. $edit_form->submit( ‘Submit’ ). $customer->title = $edit_form->title->value. 23.50]|valid_email_rfc')->value( $customer->email ). 17. 34. $customer = new Customer_Model( $id ). ORM handles the difference in SQL between UPDATE and INSERT for us. 31. 21. } $customer->firstname = $edit_form->firstname->value. the customer instance is saved. 20. } If the $edit_form->id value is false. 4. $edit_form->input( ‘title’ )->label( TRUE )->rules('required| length[2. 5. 13. Otherwise the customer record is loaded before the values are updated. which can only be true if the form is submitted and if the form input is valid using the rules defined setting up the form. $edit_form->input( ‘email’ )->label( TRUE )->rules('required| length[2. // Create a new form using Forge $edit_form = new Forge(). 29.

otherwise you will create a new record. as well as better error handling if arguments are not supplied. 37. else { } echo $edit_form->render(). then the form we defined at the top of the edit() method is printed. Validation of the inputs is handled by Forge and it will automatically output the form with highlighted fields if your input was incorrect. You should do more to protect from XSS and other malicious input. 36. 38. 35. which is why use of Forge is highly recommended. 13 . It should be noted that this is a very basic.Kohana PHP Object Relational Mapping guide If no form has been submitted. To use this you can no navigate to: http://<yourservername>/customer/edit/[<record id>] If you supply the optional id then you’ll edit an existing record.

9. 6. 10. 8. 17. $value ). I want to ensure that the values are capitalised correctly. 5. __get() and __set() methods from the ORM parent. $value ) if( $key === ‘title’ || $key === ‘firstname’ || $key === ‘surname’ ) { // Ensure the title. 4. I am going to concentrate on the __set() method. 21. 2. 4. } public function __set( $key . firstname or surname are formatted } $value = ucwords(strtolower($value)). 11. You can perform as many tasks as you like before your set 14 . 1. 15. 6. 3. $value ). 5. } I am now going to demonstrate how you can extend your model to your needs. I redefined the __constructor(). $value ) { parent::__set( $key .if anything. 16. surname and title. Now before Customer_Model sets any value. 12. it first checks to see if any of the keys match title. 8. Currently the methods mimic the behaviour of the parent by calling their parents equivalent methods. When I set my values for firstname. 18. } public function __get( $key ) { return parent::__get( $key ). 20. 14. <?php defined('SYSPATH') or die('No direct script access. 7. 1. 13. 10. and then decide what to do .Kohana PHP Object Relational Mapping guide Extending the behaviour of Customer_Model You will remember that when I set up my Customer_Model class. To do this I first need to inspect what $key is being set. 7. firstname or surname. public { correctly } function __set( $key.'). 3. 19. 2. Finally the data is set using the ORM method as usual. 9. If they do then $value is lowercased and then the first letter of each word is uppercased using the standard PHP functions strtolower() and ucwords(). parent::__set( $key. class Customer_Model extends ORM { } ?> public function __construct( $id = FALSE ) { parent::__construct( $id ).

Just ensure you check the keys you are working with before transforming their values. 15 .Kohana PHP Object Relational Mapping guide your values in your models.

But what happens if we need to link a customer record to an address or addresses in the database? Well the short answer is ORM can do this to. `country` TEXT NOT NULL COMMENT 'Country'.Kohana PHP Object Relational Mapping guide Creating ORM relationships So far I have detailed how ORM deals with single data sets. `postalcode` TEXT NOT NULL COMMENT 'Post code'. 3. In addition to this. Make sure your required field name data-type matches the parents. naming the file containing the model. Now we need to create an address model and tell both models about the relationships between customers and addresses. 4. a field providing the related parent needs to be included. 5. 8.php. `type` TEXT NOT NULL COMMENT 'Type of address. 10. Lets create the address model first. The field name should be named using a singular parent name followed by an underscore and the field name that this record is linked to in the parent table (the id of the customer in this instance). This also follows a strict naming convention. 1. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple address table' NOTE: Kohana PHP has an inflector helper to help determine the correct plural or singular version of a word. but you need to set up your parent child relationships in your ORM model as well as within your database. 2. `customer_id` INT( 12 ) NOT NULL COMMENT 'The id of the customer'. This means a table called customer_addresses is created with a required field name called customer_id to cement the relationship. 11. 12. 6. 7. One to many relationship First of all I am going to create an address table that is directly related to my Customer_Model. 16 . work etc'. The other variations should become easier to interpret once you’ve read through this chapter. `line1` TEXT NOT NULL COMMENT 'First line'. The MySQL code is below. I will demonstrate a ‘One to many’ and ‘Many to many’ relationship. 9. `line2` TEXT NOT NULL COMMENT 'Second line'. with Customer_Model being the parent of addresses. The table name has to start with a singular version of the parent followed by underscore and the a plural version of the child name. The address table has to have some key information to ensure ORM works properly for this relationship. `property` TEXT NOT NULL COMMENT 'Property name or number'. customer_address. This is the simplest of relationships. CREATE TABLE `customer_addresses` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'. home. `city` TEXT NOT NULL COMMENT 'City'. particularly useful for decoding the singular of addresses.

8. 6. } public function __get( $key ) { return parent::__get( $key ). 23. 25. 11. <?php defined('SYSPATH') or die('No direct script access.Kohana PHP Object Relational Mapping guide 1. 7. 19. public function __construct( $id = FALSE ) { parent::__construct( $id ). class Customer_Address_Model extends ORM { // Relationships protected $belongs_to = array(‘customer’). 29. 2. 6. firstname or surname are formatted } $value = ucwords(strtolower($value)). 2. you have probably realised you can associate this model with more than one other model. 26.'). 9. 16. This is because we are using a singular version of customers and a singular version of addresses. 3. } function __set( $key. 1. 27.'). This tells ORM which model this model is a child of. 6. 24. which matches the rules stated earlier. 14. 3. 13. 18. it is time to inform the customer model that it has some children. 8. 21. } ?> Following the same rules as before. the address model is named Customer_Address_Model. 17 . 4. 9. <?php defined('SYSPATH') or die('No direct script access. public { correctly } ?> } parent::__set( $key. 4. 12. 7. The $belongs_to array has one entry. 10. protected $belongs_to = array(‘customer’). 28. 5. 15. ‘customer’. 17. As $belongs_to is an array. 22. 5. With the address model set up. 20. $value ). $value ) if( $key === ‘title’ || $key === ‘firstname’ || $key === ‘surname’ ) { // Ensure the title. class Customer_Model extends ORM { // Relationships $has_many = array(‘addresses’).

Kohana PHP Object Relational Mapping guide Once again the relationship is defined before anything else. As there now are many of both data types in our relationship. This time address data is not a direct child of customer data. `address_id` INT( 12 ) UNSIGNED NOT NULL COMMENT 'Address id'. 1. You have now completed your relationship declaration. 10. 2. `type` TEXT NOT NULL COMMENT 'Type of address. 5. `country` TEXT NOT NULL COMMENT 'Country'. home. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple address table' Notice that the table name is plural (‘addresses’ ) this time and the field that ties each record to a customer_id is gone. CREATE TABLE `customers_addresses` ( `customer_id` INT( 12 ) UNSIGNED NOT NULL COMMENT 'Customer id'. work etc'. `line1` TEXT NOT NULL COMMENT 'First line'. 9.`address_id`) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple customers pivot table' 18 . PRIMARY KEY (`customer_id`. This time I am going to assume addresses can be shared between customers. as there are many addresses that could relate to this instance. Many to many relationship When it comes to many to many relationships the set up slightly differs. 2. 3. the pivot table name is called `customers_addresses` .all plural. 7. 8. So the table in MySQL will be more similar to the structure of the customer table. `postalcode` TEXT NOT NULL COMMENT 'Post code'. 6. Notice there is no `id` field. 3. 4. 4. `city` TEXT NOT NULL COMMENT 'City'. an additional table is created to map the addresses to their customers. just the `{related table name}_id` for each table in the join. but you could map them in reverse if your application logic dictated that. `property` TEXT NOT NULL COMMENT 'Property name or number'. Because all of the relationship data is gone from the addresses table. 5. With the customer model we use the plural version of the model name. CREATE TABLE `addresses` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'. `line2` TEXT NOT NULL COMMENT 'Second line'. This is the pivot table and has a specific naming convention like all other tables. 11. Model will know to look for Customer_Address_Model because you have declared the relationship in $has_many. two or more customers can use the same address record for example. 1. I am choosing that Customers is still parent of Addresses for this example.

Notice the classes is now plural as the relationship is ‘to many’. but belongs to many customers as defined in $belongs_to_many = array(‘customers’). 8. 7. 9. class Address_Model extends ORM { // Relationships protected $belongs_to_many = array(‘customers’). 5. 2. 15. I should note that I have also removed the __construct() and __get() functions as they were unchanged from their parents default behaviour. 2. 7. $value ). firstname or surname are formatted } $value = ucwords(strtolower($value)). 4. $value ) if( $key === ‘title’ || $key === ‘firstname’ || $key === ‘surname’ ) { // Ensure the title. 3. 4. The relationship is now $has_and_belongs_to_many = array(‘addresses’). class Customer_Model extends ORM { // Relationships $has_and_belongs_to_many = array(‘addresses’). 19. 14. 6. 3. A new file called address. 12. To get the join to work within ORM we need to do some modification of the Customers_Model and create a new Addresses_Model. 11. 16.php should be created within the application/models folder with the code below. 13. } ?> Now the Address_Model is not a child of any other class. 9. <?php defined('SYSPATH') or die('No direct script access. 1. 8. 6. <?php defined('SYSPATH') or die('No direct script access.Kohana PHP Object Relational Mapping guide This completes the database table set up required for many to many joins. 10. 17. 1. 19 .').'). 5. public { correctly } ?> } parent::__set( $key. function __set( $key. Below is the refined Customers_Model file with newly updated relationships. 18.

The { P } under ‘Many to many’ signifies it requires a pivot table to be created as this is a join. Producing a database diagram before coding should make the relationships apparent. Relationship One to one One to many Many to many {P} Many to one Parent class header $has_one = array(‘child’) $has_many = array(‘childs’) $has_and_belongs_to_many = array(‘childs’) $has_one = array(‘child’) Child class header $belongs_to = array(‘parent’) $belongs_to = array(‘parent’) $belongs_to_many = array(‘parents’) $belongs_to_many = array(‘parents’) Pivot tables do not require a unique id. which will help writing ORM classes and their relationships. but do require the singular {related}_id for each table within the join. ORM will be able to update all tables by using methods for finding. it will add an ‘s’ to child instead. 20 . These are outlined in the next chapter. “Using ORM relationships in your code”.Kohana PHP Object Relational Mapping guide Once your models are in place and correctly linked. The incorrect use of ‘childs’ is deliberate as Kohana PHP’s Inflector class will not resolve child to children. adding and removing relationships. You can read more about the ORM conventions on the Kohana PHP web site. The table below outlines the parent and child declarations for the different data types. ORM relationships summary The biggest hurdle when dealing with ORM relationships is getting the naming conventions correct.

$address = new Customer_Address_Model(). $addresses = $customer->find_related_addresses(). 17. $address->type = ‘home’. but the following methods become available using the example above. $address->country = ‘United Kingdom’. $address->city = ‘London’. 21 . I am not going to go into great detail here. 12. $customer->save(). 5. 11.Kohana PHP Object Relational Mapping guide Using ORM relationships in your code With all relationships set up between models. $address->line1 = ‘Brockle Gate Drive’. 10. 14. 9. 16. add $parent->add_$child( $instance ) 1. 7. $customer = new Customer_Model(). $addresses = $customer->find_related_addresses(). This will add a new address to the $customer instance. $addresses will contain all addresses that belong to this customer. find_related $parent->find_related_$child 1. 2. 18. 2. $customer = new Customer_Model(1). 3. 19. 13. // Add $address to $customer $customer->add_address( $address ). $address->property = ‘1’. additional methods within ORM become available. $customer = new Customer_Model(1). 6. $customer->save(). all data across models and database tables will be updated. When you perform. 4. $address->postalcode = ‘SE1 1PP’. // Remove the first related $address $addresses[0]->remove(). 8. remove $child->remove( ) 15.

`surname` TEXT NOT NULL COMMENT 'Surname'. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple customer table' customer_addresses. 8. `email` TEXT NOT NULL COMMENT 'Email Address'. 9.sql SQL Code for the customer_addresses table 1. `property` TEXT NOT NULL COMMENT 'Property name or number'. 24. `type` TEXT NOT NULL COMMENT 'Type of address. `city` TEXT NOT NULL COMMENT 'City'. 26. 4. CREATE TABLE `customers` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'. `line1` TEXT NOT NULL COMMENT 'First line'. 21. 23. `postalcode` TEXT NOT NULL COMMENT 'Post code'. `country` TEXT NOT NULL COMMENT 'Country'. 11. home. customers. `line2` TEXT NOT NULL COMMENT 'Second line'. If you have any comments about the files (such as incorrect code).Full Files On the following pages I provide my finished files in full. 27. work etc'. `title` TEXT NOT NULL COMMENT 'Title'.sql SQL Code for the customers table 20. CREATE TABLE `customer_addresses` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'. 3.Kohana PHP Object Relational Mapping guide Appendix A . which should hopefully help some of you to get going quickly. 10. 2. you’re welcome to fix it and post it back on my blog (http://sam. 12.name) as I’ll be keeping this document up to date. 7. 5. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple address table' 22 . 25. 22. `firstname` TEXT NOT NULL COMMENT 'Firstname'.clark. 6. `customer_id` INT( 12 ) NOT NULL COMMENT 'The id of the customer'.

11. 5. work etc'. CREATE TABLE `customers_addresses` ( `customer_id` INT( 12 ) UNSIGNED NOT NULL COMMENT 'Customer id'. `postalcode` TEXT NOT NULL COMMENT 'Post code'. 4. `line2` TEXT NOT NULL COMMENT 'Second line'. 6. 2. 7.Kohana PHP Object Relational Mapping guide addresses. 10. home. 3. `city` TEXT NOT NULL COMMENT 'City'. 2. 3.sql SQL Code for the addresses table (Many to many relationship) 1. 8. PRIMARY KEY (`customer_id`. `type` TEXT NOT NULL COMMENT 'Type of address. 9. CREATE TABLE `addresses` ( `id` INT( 12 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id'.sql SQL Code for the customers_addresses pivot table (Many to many relationship) 1. `country` TEXT NOT NULL COMMENT 'Country'. PRIMARY KEY ( `id` ) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple address table' customers_addresses. `address_id` INT( 12 ) UNSIGNED NOT NULL COMMENT 'Address id'. `property` TEXT NOT NULL COMMENT 'Property name or number'.`address_id`) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT = 'A very simple customers pivot table' 23 . 5. `line1` TEXT NOT NULL COMMENT 'First line'. 4.

class Customer_Model extends ORM { // Relationships $has_and_belongs_to_many = array(‘addresses’). application/models/customer_address. 7. 3. <?php defined('SYSPATH') or die('No direct script access. 2. 2. <?php defined('SYSPATH') or die('No direct script access.'). 12. 9. class Customer_Address_Model extends ORM { // Relationships protected $belongs_to = array(‘customer’). 8. 9. 8. <?php defined('SYSPATH') or die('No direct script access. 7.php PHP code for Customer_Address_Model (Many to one relationship) 1. $value ). 4.'). 4.Kohana PHP Object Relational Mapping guide application/models/customer. 10. 8. 5. 4. 9. } ?> application/models/address. class Address_Model extends ORM { // Relationships protected $belongs_to_many = array(‘customers’). firstname or surname are formatted } $value = ucwords(strtolower($value)). 19. 13.php PHP code for Address_Model (Many to many relationship) 1. 2. 18. 16. function __set( $key. 6. 17. 15. 5. 6. public { correctly } ?> } parent::__set( $key. $value ) if( $key === ‘title’ || $key === ‘firstname’ || $key === ‘surname’ ) { // Ensure the title. 3. 11. 7. } ?> 24 .'). 5. 6. 3.php PHP code for Customer_Model (Many to many relationship) 1. 14.

li>”. 53. 24. 37. } else { $customer = new Customer_Model( $id ). 17. 29. 39. /** * View */ h1>”. 38. 11. /** * My Customer Contoller. a record if id supplied. 30. 22. 46. 50. a record public { } function view( $id = FALSE ) if( !$id ) { $output = “You must supply an article id”. 41.= “<p>Email : {$customer->email}</p>”. 10. echo $output.Kohana PHP Object Relational Mapping guide application/controllers/customer. 52. 34. 32. 8. 19. 48. 6. 21. 14. /** * Edit */ } $output = “<ol>”. {$customer->firstname}</ } $output . 45. 33. 2. 47. otherwise create a new record (handled by ORM) public { function edit( $id = FALSE ) // Create a new form using Forge $edit_form = new Forge(). $output = “<h1>{$customer->surname}. 18.php PHP code for Customer_Controller 1.'). 23. 44. 35. 15. 16. <?php defined('SYSPATH') or die('No direct script access. It’s always good practice to at least hint at what this class * does **/ class Customer_Controller extends Controller { /** * Default controller behaviour. $customer = new Customer_Model( $id ). 3. ‘asc’)->find_all().= “<li>{$customer->surname}.= “</ol>”. $customers = $customers->order_by(‘surname’. 42. show all records in this case */ public function index() { $customers = new Customer_Model(). 49. 7. 28. 25. 43. 51. 31. 9. 20. 26. echo $output. foreach( $customers as $customer ) { $output . 5. 27. 25 . 4. 40. 36. 12. 13. {$customer->firstname}</ } $output .

64. 79. 84. } } } else { } if ( $customer->save() ) { echo “<p>Record saved!</p>”. else $customer = new Customer_Model(). 71. $edit_form->input( ‘email’ )->label( TRUE )->rules('required| length[2. 68. $edit_form->hidden( ‘id’ )->value($id). 87. $edit_form->input( ‘firstname’ )->label( TRUE )->rules('required| length[2. $customer->title = $edit_form->title->value. 72. } echo $edit_form->render(). 70.Kohana PHP Object Relational Mapping guide 54. 85.50]')->value( $customer->firstname ).30]')->value( $customer->title ). 89. 61. 63. $edit_form->input( ‘title’ )->label( TRUE )->rules('required| length[2. 57. 56. // If the form is valid if( $edit_form->validate() ) { if( $edit_form->id ) $customer = new Customer_Model( $edit_form->id->value ). $edit_form->input( ‘surname’ )->label( TRUE )->rules('required| length[2. 26 . $customer->surname = $edit_form->surname->value. 75. 66. 73. 59. 60. 74. } else { echo “<p>Problem saving record</p>”. 81. 76. 86. 80. $edit_form->submit( ‘Submit’ ).50]|valid_email_rfc')->value( $customer->email ). 88. $customer->email = $edit_form->email->value.50]')->value( $customer->surname ). $customer->firstname = $edit_form->firstname->value. 77. 62. 69. 82. 67. 58. 55. 83. 65. 78.

Sign up to vote on this title
UsefulNot useful