Learn Containable Behavior by Example

In cakephp, adding relationships is easy. We just have to declare the hasOne, belongsTo, hasMany and the famous HABTM relationship to do all the dirty work of joining tables. But declaring them all at once could lead to a slow page.

In version 1.1, what we do is utilize the bindModel() and unbindModel(). We do not declare all associations in the Model class yet. This was a good solution. I was looking for this option in version 1.2 and I found the Containable Behavior. Studying containable was a little rough before but there are documents now that are really helpful.
Today, I’ll be showing you how to use Containable in pagination and in regular find method. You must have a fair understanding of the behavior so I suggest you read the above articles first. If you are ready, follow the instructions below:

  1. Download the latest 1.2 release of cake. As of this writing, I tested it in cake_1.2.0.7296-rc2. Do the usual cake installation procedures.
  2. Download this file and unzip. It must contain an “app” folder
  3. Replace the /app from #1 with the /app from #2 but leave the config file of #1.
  4. Use the /app/class.sql to setup your database
The idea of the sample is taken from a virtual school application. So we have Departments, Courses, Classes, Students and Teachers, Students Comments on Class and Students Ratings on Class. The following is an explanation of tables declared in class.sql so you can follow the relationships:
TABLERELATIONSHIP
departmenthas many courses
courseshas many classes
belongsto departments
classesbelongs to courses
belongs to teacher
has many comments
has many ratings
teachershas many classes
ratingsbelongs to class
belongs to student
commentsbelongs to class
belongs to student
studentshas many comments
has many ratings

Exampe1: List of Classes

What we will do is get only the basic information for the list of classes. Those includes:

  • Class title
  • Course it belongs to
  • Department it belongs to
  • Teacher name
It will look like this (replace the http://localhost with your local address)
http://localhost/cake/my_classes/index

Let’s compare the recursive and containable method.

Using The Recursive Method
Check the MyClassesController::unfiltered_result() for your reference. First try is I added the ffg line
$this->MyClass->recursive = 1; 
but the problem is that I could not get the Department name. Then I tried
$this->MyClass->recursive = 2; 
and there I have all the information I need. The problem is that there are just to many data I do not need. Another option is to use the the paginate fields filter. Try adding this:
$this->paginate['MyClass']['fields'] = array( 'Course.title', 'MyClass.title' );

The result? Check it for yourself in http://localhost/cake/my_classes/unfiltered_result

Using Containable Behavior
If you look at MyClassesController::index2(), you would see the ffg:
        $this->paginate['MyClass']['contain'] = array ( 
            'Teacher', 
            'Course' => array ( 
                'Department' => array ( 
                    'fields' => array ( 
                        'Department.title', 
                        'Department.id' 
                    ) 
                ) 
            ) 
        );
That basically tells cake to find the Class Teacher and return all fields, the course it belongs to and return all the fields and finally the course' Department title and ID. Now run this http://localhost/cake/my_classes/filtered_result and compare the result with the previous example. It became cleaner isn't it?

With Containable, you can specify which tables to include and what fields to include each table. You can also add order and limit filters and also conditions. It took me a while to grasp the format because at first glance it is a bit difficult to follow. I use the following format:

$this->Model0->contain( array(
 'Model1' => array ( 
 'fields' 	 => array( 'modelField1', 'modelField2' ),
 'conditions' => array( 'your condition here' ),
 'order' 	 => array( 'id' => 'asc' ),
 ),
 'Model2',
 'Model2'
 )
)

Example2: Class View

This is just to show you a more complicated containable query. We want to get more information about the class. That includes:

  • Class title
  • Course it belongs to
  • Department it belongs to
  • Teacher name
  • Student comments that were approved and student name
  • Student ratings that were approved and student name
We can achieve the desired results using recursive but then again we will be wasting so much process time. In containable, we'll just have to declare what we want.

        $this->MyClass->contain( array( 
            'Teacher', 
            'Rating'     => array( 
                'Student', 
                'order' => array( 'created' => 'desc' ),
                'conditions' => array( 'approved' => 1 )
            ), 
            'Comment'    => array( 
                'Student', 
                'order' => array( 'RAND()' ),
                'limit' => 3 ,
                'conditions' => array( 'approved' => 1 )
            ), 
            'Course'     => array( 
                'Department' => array( 
                    'fields' => array( 
                        'Department.title', 
                        'Department.id' 
                    ) 
                ) 
            ) 
            )
        );

Can you see the format now? Play around with the codes and check their results to get more comfortable with it. Happy Baking!

Tags: ,

2 Responses to “Learn Containable Behavior by Example”

  1. links for 2008-09-18 « Richard@Home Says:
    [...] Promet CakePHP SourceĀ» Learn Containable Behavior by Example (tags: cakephp containable) Posted by Richard@Home Filed in 15 [...]
  2. Learn Containable Behavior by example in CakePHP « Myles Kadusale’s Blog Says:
    [...] Learn Containable Behavior by example in CakePHP Nice tutorial. Click here [...]

Add Comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>