ORM: Relationships - has_many/belongs_to
It’s 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 many, belongs_to relationship.
It is the second picture in the following diagram. 
Again, we need the sql to handle this relationships. We’ll use a students table like last time and a new dorms table. We won’t be needing the cars table.
-- -- Table structure for table `dorms` -- CREATE TABLE IF NOT EXISTS `dorms` ( `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=2 ; INSERT INTO `dorms` (`id`, `name`) VALUES (1, 'dorm 1'); -- -- Table structure for table `students` -- CREATE TABLE IF NOT EXISTS `students` ( `id` mediumint(9) NOT NULL AUTO_INCREMENT, `name` varchar(255) collate utf8_unicode_ci NOT NULL, `dorm_id` mediumint(9) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ; INSERT INTO `students` (`id`, `name`, `dorm_id`) VALUES (1, 'student 1', 1), (3, 'student 2', 1);
Now we have to write our models.
//models/student.php class Student_Model extends ORM{ protected $belongs_to= array('dorm'); //singular dorm, i.e. student belongs to one dorm } //models/dorm.php class Dorm_Model extends ORM{ protected $has_many=array('students'); //plural students, i.e. dorm has many students }
Pay attention to the plural and singular forms of the relationships.
On to relationship retrieval
class Test_Controller extends Controller{ public function index() { //select the student and get the dorm $student=new Student_Model(1); $dorm=$student->dorm; //the dorm property of $student is retrieved using the magical __get and gives back the right instance of Dorm_Model, in this case $student->dorm=new Dorm_Model(1); echo 'Dorm: '.$dorm->name; echo '<br>'; //select the dorm and get the students $dorm=new Dorm_Model(1); $students=$dorm->find_related_students(); foreach($students as $student) { echo $student->name . '<br>'; } if($dorm->has_student()) { echo 'Dorm has at least one student'; } } }
Adding students to the dorm
//create new student $student=new Student_Model(); $student->name='freshman'; //add student to the dorm $dorm=new Dorm_Model(1); $dorm->add_student($student);
Removing a student from the dorm
//get the newly added student $student=new Student_Model(); $student->find_by_name('freshman'); $dorm=new Dorm_Model(1); $dorm->remove_student($student);
I think this covers about everything there is to know about this relationship. The code has been tried and tested but if you encounter any problems feel free to let me know.
June 9th, 2008 at 10:10 am
Thanks for posting this tutorial. Of all the uses for ORM this is, IMO, the most common and it’s the one I first looked for examples for when I began using ORM.
The magic that happens inside __get() makes this one a little bit non intuitive and it can take a while to discover that simply referencing $student->dorm is all that’s needed to retrive the related object.
This tutorial demostrates that perfectly although perhaps a bit more description for the relationship retrieval snippet would help spell it out definitively.
Cheers,
Webthink-Julian
June 9th, 2008 at 11:59 am
Thanks for the input. I wrote this tutorial pretty fast so it needs a little brushing up. Your suggestion will surely be incorporated.
June 23rd, 2008 at 10:37 pm
Something that you could elaborate more on, or just point out is that this is possible. Along with most of the other functions.
$students=$dorm->limit(5)->find_related_students();
It wasn’t obvious to me at first.. and I had to do some digging.
June 23rd, 2008 at 11:01 pm
I think I covered it in another ORM tutorial, the one that focuses on the Object Mapping rather than the relations. You can indeed use the methods of the db builder in ORM except for a few like query(). You can also set where() and select()
June 30th, 2008 at 11:22 am
Thanks, very helpfull tutorial to understand basics.
But one question, from SQL sight: does dorm_id have to be defined as foreign key in students table?
June 30th, 2008 at 1:05 pm
Not explicitly, ORM handles it and to my knowledge MyISAM doesn’t support it. If you’re using a database supporting foreign key constraints it might be wise, especially considering cascading deletes and the like. Again, not sure how ORM handles all this.
July 15th, 2008 at 7:20 pm
Kohana version: As of r3054 ORM has been greatly revised. See this post for an overview
If i click See this post for an overview.. It cannot be found, so what did change?
July 15th, 2008 at 7:29 pm
I’m working on that post, it will be covered shortly
July 30th, 2008 at 2:06 am
I have a question. I was trying do the same, but for many objects to create a list of studnets, and it is not going to work, right?
$students = new Student_Model();
$students = $students->orderby(’id’,'desc’)->limit(10)->find_all();
$dorm=$students->dorm;
July 30th, 2008 at 8:24 am
No it isn’t, $students is an ORM_Iterator object and not an ORM object.
August 4th, 2008 at 10:36 pm
FWIW, the new ORM v2 does not support the use of add()/remove()/has() for one-to-many relationships. add()/remove()/has() are now only for many-to-many. see this thread in the forums:
http://forum.kohanaphp.com/comments.php?DiscussionID=887&page=1#Item_11