ORM: Relationships - has_one/belongs_to
Since there is a demand for tutorials on ORM and especially relationships I’ll try to cover some aspects of in a series of posts. This post will cover the has one/belongs to relationships
The following diagram explains relationships in general. I’ll use the same terms and entities so the tutorial will be easy to follow. Kohana does not (yet) support the ‘through’ type of relation so I won’t get into that. In the various posts I’ll cover all these relationships except for the through type.

has_one - belongs_to
We’ll deal with the first example of the diagram. First the SQL
CREATE TABLE IF NOT EXISTS `cars` ( `id` mediumint(9) NOT NULL AUTO_INCREMENT, `name` varchar(255) collate utf8_unicode_ci NOT NULL, `student_id` mediumint(9) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ; INSERT INTO `cars` (`id`, `name`, `student_id`) VALUES (1, 'car 1', 1); CREATE TABLE IF NOT EXISTS `students` ( `id` mediumint(9) NOT NULL AUTO_INCREMENT, `name` varchar(255) collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ; INSERT INTO `students` (`id`, `name`) VALUES (1, 'student 1');
Important is that the id field is necessary as well as the student_id field in the cars table. Also you see that the car table has one record which links to the one student in the student table.
Now, onto the models. Your model will look like
//models/student.php class Student_Model extends ORM{ protected $has_one= array('car'); } //models/car.php class Car_Model extends ORM{ protected $belongs_to=array('student'); }
So, what about relationship retrieval.
class Test_Controller extends Controller{ public function index() { //from the student to the car $student=new Student_Model(1); $car=$student->car; //$student->car, //car is an object of type Car_Model echo 'Car:'. $car->name; //Retrieve name from the Car_Model echo '<br>'; //from the car to the student $car=new Car_Model(1); echo 'Student:'.$car->student->name; //$car->student, //student is an object of type Student_Model echo '<br>'; $student=new Student_Model(1); $car=$student->find_related_car(); echo 'Car:'. $car->name; if($student->has_car()) { echo 'Student has car'; } } }
Piece of cake. Next step, adding, removing relations
First removing the car from the student.
public function removing(){ $student=new Student_Model(1); $student->remove_car(1); if(!$student->has_car()) { echo 'Car was stolen from student'; } }
Let’s add a car back to the student:
public function adding(){ $car=new Car_Model; $car->name='Ferrari'; $student=new Student_Model(1); $student->add_car($car); if($student->has_car()) { echo 'Insurance got the student a new car'; } }
So, that’s about it for the simplest relationship out there. I hope it helps. The other relationships are pretty similar but I’ll cover them anyway.
April 9th, 2008 at 8:00 pm
A friend of mine just emailed me one of your articles from a while back. I read that one a few more. Really enjoy your blog. Thanks.
Jason Whitmen
April 10th, 2008 at 6:37 pm
Firstly, Kohana rocks… it’s doing everything i had wished Code Igniter had… only wish i’d found it sooner.
Apologies if this seems unrelated to the blog… i couldn’t find a comments box in the kohana pages.
But if there is a bugbear i have it’s regarding DB querying…
I’d like to just write..
$sql = whatever…
return $query = $db->query($sql)
but i have to put in another few lines of code to test for whether a result is valid.
$sql = whatever…
$query = $db->query($sql)
if($query->valid()) return $query;
else return FALSE
wouldn’t it be better if $db->query() returned false on zero result ? I may go ahead and write my own DB class to do this… am i missing something?
April 10th, 2008 at 6:58 pm
I don’t know out of the top of my head as I rarely use the $db->query methods. You can do if($query->count()>0) on a result but I don’t know if that’s what you mean.
April 10th, 2008 at 7:01 pm
Actually, i’ve done some testing, and i’ve changed my mind… it’s pretty cool all in all just to get the object back…. while i’d prefer the method above as it would save a line of code, it’s not such a big deal. I think it’s better to have available all the class methods from your db query…. makes sense now…
May 1st, 2008 at 10:11 pm
The example did not work for me using my analogous tables (stations and networks).
The form:
$student = new Student_Model($id);
$car = $student->car;
will in general throw an error, but the form:
$car = new Car_Model($id);
$student = $car->student;
will not throw an error.
The reason is that the second form accesses the car table which has a foreign key (student_id) to point it directly back to the correct entry in the student table.
The first form accesses the student table which does not have a foreign key. In order to find the correct entry in the car table it has to find the entry in the car table where student.id = car.student_id. Hence the method find_related_car must be used.
I’m guessing the example works because there is only one student and one car. In my case I have more than one of each.
May 1st, 2008 at 10:52 pm
You’re right. This tutorial covers the has_one/belongs_to (one) relationship. I (incorrectly?) assume students don’t have enough money to pay for more than one car.
In any case, if the relationship is that one entity can have many other things find_related_* must be used. It returns an array of related records.
When I have time I hope to write the other tutorials explaining the other relationships.
June 1st, 2008 at 2:16 am
I don’t understand how this line works:
$student->remove_car(1);
June 1st, 2008 at 9:11 am
It removes the car relationship from the student and the car had id=1
June 5th, 2008 at 4:45 pm
[...] been a while since the last tutorial on this subject but here is the next in the series. As the title suggest we will cover the has [...]
June 12th, 2008 at 2:35 pm
I followed the steps here exactly, but when i do:
$student=new Student_Model(1);
$car=$student->car;
echo ‘Car:’. $car->name;
the output is empty, does this really work?
June 12th, 2008 at 2:49 pm
$student=new Student_Model(1);
$car = $student->find_related_car();
car is also empty when using find_related.
(i dumped the object, but the members are not hydrated accordingly to the relations and the data present in the db)
June 12th, 2008 at 2:58 pm
Correction to the posts above for the newcomer:
Do create models exactly as specified in this tutorial, not in the model/orm tutorials where the constructor is overridden, afterwards, all mentioned in the two posts above will work perfectly.
June 12th, 2008 at 7:26 pm
Thanks for clearing that up.