ORM: Relationships - has_many/belongs_to

Difficulty: Advanced

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.


11 Responses to “ORM: Relationships - has_many/belongs_to”

  1. Julian Simpson Says:

    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

  2. dlib Says:

    Thanks for the input. I wrote this tutorial pretty fast so it needs a little brushing up. Your suggestion will surely be incorporated.

  3. Zoxive Says:

    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.

  4. dlib Says:

    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()

  5. Syndicut Says:

    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?

  6. dlib Says:

    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.

  7. Anotherhero Says:

    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?

  8. dlib Says:

    I’m working on that post, it will be covered shortly

  9. Mike Says:

    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;

  10. dlib Says:

    No it isn’t, $students is an ORM_Iterator object and not an ORM object.

  11. bunnyhero Says:

    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

Leave a Comment