0

Even after digging through "Specifying order parameter through a belongsTo table in CakePHP" I can't seem to order entries in a table that belong to entities stored in another table.

Essentially, I've got a Tutorial model which hasMany Exercise. Each Exercise belongsTo Tutorial (of course) and also belongsTo an ExerciseCategory. When I set recursive = 2 and find a given tutorial I'd like to get back a list of Exercise rows, ordered first by ExerciseCategory.title and then by Exercise.sequence_number.

So here's my question: My great/hackish idea was to order the results of the query based on the raw exercise_category_id, like so:

class Exercise extends AppModel {
    public $belongsTo = array( 
        'Tutorial', 
        'ExerciseCategory' 
    );

    public $order = array( 'exercise_category_id' => 'ASC',  // <=========
                           'sequence_number' => 'ASC');      // <=========

I don't understand why this doesn't work, either. It produces the following SQL query:

SELECT `Exercise`.`id`, `Exercise`.`exercise_category_id`, 
`Exercise`.`tutorial_id`, `Exercise`.`sequence_number`, 
`Exercise`.`body` 
FROM `Tutorial`.`exercises` AS `Exercise` 
WHERE `Exercise`.`tutorial_id` = (1)

Based on the CakePHP documentation it seems like there ought to be an ORDER BY clause in the query, but there isn't.

What do I need to do to get the Exercise rows ordered by the exercise_category_id number so that they'll be grouped up the way I want?

"Specifying order parameter through a belongsTo table in CakePHP" suggests setting up the Exercise.php model file like this:

class Exercise extends AppModel {
    public $belongsTo = array( 
        'Tutorial', 
        'ExerciseCategory' => 
            array(
                'order' => array('ExerciseCategory.title'=>'asc', 'Exercise.sequence_number' => 'asc'))
    );

but that produces an erroneous SQL query:

SELECT `ExerciseCategory`.`id`, `ExerciseCategory`.`explanation`, 
`ExerciseCategory`.`title` 
FROM `Tutorial`.`exercise_categories` AS `ExerciseCategory` 
WHERE `ExerciseCategory`.`id` = 2 
ORDER BY `ExerciseCategory`.`title` asc, `Exercise`.`sequence_number` asc

The problem (as CakePHP helpfully points out) is that CakePHP doesn't include the Exercises table in the query.

EDIT: Here's the code to actually generate the various queries:

$this->Tutorial->recursive = 2;
$this->Tutorial->Chapter->unbindModel(array('hasMany' => array('Tutorial')));
$this->Tutorial->Exercise->unbindModel(array('belongsTo' => array('Tutorial')));
$this->Tutorial->Section->unbindModel(array('belongsTo' => array('Tutorial')));
$tut = $this->Tutorial->findById($id);
4

2 に答える 2

1

When CakePHP generates queries to pull in associated models, it actually creates completely separate queries. So, when you use recursive *cringe* (or Containable *yay!*), you cannot order by associated models, because those tables won't even be IN the query.

If you need to order by associated models, you'll need to use JOINs. That way, you'll have a single query, and can order in any way with any tables you want...etc etc.

Other helpful things:

  1. Set $recursive = -1; in your AppModel and then forget you ever heard of it. I promise, you'll thank me in the long run. Use CakePHP's Containable Behavior instead. Recursive is cool when first learning ONLY to quickly understand that "cool - you can associate models with each other"... but beyond that, it will cause more problems than it helps. If Containable didn't fill that niche SO well, maybe we'd need to use recursive, but... it does, so we don't :)

  2. if you want help with a query problem, it's usually best to post the code you're actually using to generate it. :)

于 2013-03-25T05:16:12.507 に答える
0

So, er, as it turns out - I can do what I was hoping to do, but I need to put the order clause in the hasMany field of Tutorial instead of the belongsTo field of Exercise:

class Tutorial extends AppModel {
    public $belongsTo = array('Chapter');
    public $hasMany = array('Section', 
        'Exercise' => 
            array(
                'order' => array('Exercise.exercise_category_id'=>'asc', 'Exercise.sequence_number' => 'asc')));

This makes more sense, but seems to directly contradict Specifying order parameter through a belongsTo table in CakePHP (admittedly that was posted 4 years ago).

I'm going to give this a couple of days to see if someone else can post a better way of doing this before marking an answer (i.e., example code demonstrating how to order by a field in an associated model, rather than ordering by the id column of the associated model).

于 2013-03-25T07:04:42.800 に答える