Simple Is Good!

How To Web Dev

Kohana 3 ORM relationships

Kohana 3.x docs (kohanaframework.org/3.3/guide/orm/relationships) leaves a bit to be desired (much like my writing skills) when it comes to how exactly ORM relationships work.  If you take the time to to a little bit of experimenting you can pretty quickly find out how $_belongs_to, $_has_one and $_has_many works.  Well I am hoping to maybe give another perspective on it and see if I can help out those of you who are doing a google search to find out how to use them.  So here we go, for our example I am going to use a simple school example for the data:

Tables: Department, Courses, Teachers and Students.

// Each department can have many courses
departments
id, name
 
// Each course can have one department, one teacher and many students.
courses
id, department_id, teacher_id, name
 
// Each teacher can teach only one course but can have many students
teachers
id, name
 
// Each student can have many courses
students
id, name
 
// Keeps the many to many relationship between courses and students
courses_students
course_id, student_id

Department Model

Remember, our department model would be something along the lines of “Business, Physical Therapy, Computer Science”. Each department can have many courses, but each course can only belong to one department (Yes I realize this is not always true in real life, just stick with the example please!)

class Model_Department extends ORM {
 
  protected $_has_many = array(
    'courses' => array(
      'model' => 'Course',
      'foreign_key' => 'department_id',
    ),
  );
 
}

Courses Model

Like we stated above, a course can belong to one, and only one department. A course has only a single teacher that can teach that course. Finally each course has many students that are enrolled into the course.

class Model_Course extends ORM {
 
  protected $_belongs_to = array(
    'department' => array(
      'model' => 'Department',
    ),
  );
 
  protected $_has_many = array(
    'students' => array(
      'model' => 'Student',
      'through' => 'courses_students',
    ),
  );
 
}

Teacher Model

If the real world worked like this, teaching would be easy: A teacher can only teach one course, and thats it. Nope, not getting into “A teacher can have many students”. $_has_one represents a 1:1 relationship, not the “one” side of a one to many relationship.  This is a mistake that is very common and easy to make because, well, it just makes sense that the other side of $_has_many would be $_has_one instead of $_belongs_to but that would be incorrect.

class Model_Teacher extends ORM {
 
  protected $_has_one = array(
    'course' => array(
      'model' => 'Course',
      'foreign_key' => 'teacher_id',
    );
  );
}

Student Model

Lastly we come to the humble student, each student can be enrolled into multiple courses.

class Model_Student extends ORM {
 
  protected $_has_many = array(
    'courses' => array(
      'model' => 'Course',
      'through' => 'courses_students',
    ),
  );
 
}

But how do I use that in real code?

I am glad you asked, because it took me a long time to figure that out! Maybe I am just a little slow on the uptake, but if you are reading this part I might not be the only one. Or if you already know, just sit back and bask in your programming genius.

Getting a departments courses: $_has_many

// Unique ID of the Computer Science department
$department_id = 1;
 
// Load the row using ORM
$math_department = ORM::factory('Deparment', $department_id);
 
// Using the relationship we set find all the courses
$math_courses = $math_department->courses->find_all();
 
// Lets loop through them:
foreach ($math_courses as $math_course)
{
  // Lets output the name of the course.
  $math_course->name; // Math 101 | Calc | etc.
}

An interesting note, when accessing the $_has_many side of things, you have to call the find_all() method, this is different then how kohana 2.x handled things and different then how calling the $_belongs_to alias work as you’ll see in the next example.

Fetch a courses department: $_belongs_to

// Unique ID of the Intro to programming course
$course_id = 5;
 
// Load the row using ORM
$programming_course = ORM::factory('Course', $course_id);
 
// Using the relationship we find the deparment
$department = $programming_course->deparment;
 
// Output, xdebug makes this look pretty by the way.
echo $department->name; // Computer Science

You’ll notice that we didn’t need to call find() in order to get the department ORM object.

Fetch a courses students: $_has_many through

// Unique ID of the Intro to programming course
$course_id = 5;
 
// Load the row using ORM
$programming_course = ORM::factory('Course', $course_id);
 
// Using the relationship we find the students
$students = $programming_course->students->find_all();
 
// Iterate over the students
foreach ($students as $student)
{
  echo $student->name; // Billy | Bobby | Socrates | Aristotle
}

Get a teachers course: $_has_one 1:1

// Unique ID of the teacher
$teacher_id = 10;
 
// Load the row using ORM
$teacher = ORM::factory('Teacher', $teacher_id);
 
// Using the relationship we find the course
$course = $teacher->course;
 
echo $course->name; // Intro to assembly

Hopefully that helps clear up any confusion that may have been there for you dealing with Kohana 3 ORM and the relationships between database objects. If not, well let me know and I’ll do my best to make the examples better.