> Since the 'movies' table doesn't contain the genre_id I want to filter
> on, how can I do a find on movies on a certain genre. As far as I can
> see, I can't. Not without writing manual queries. Or am I wrong here?
>
> Any suggestions?
>
> Thanks, Dax.

I've been tackling a similar scenario myself. Hope the following will
help you.

I'm using CakePHP 1.1, so I wasn't able to use the new paginator
introduced in 1.2. Here is a linik to the wonderful Paginator
component by Andy Dawson:
http://bakery.cakephp.org/articles/view/pagination
Examine the article, download the code and play with it - works like a
charm.

When you've got it working for regular Model::findAll() queries (no
HABTM filtering) read on to see how I managed to adapt it to work with
HABTM filterings.

For the HABTM filtering I found these threads in the google groups
EXTREMELY useful:
http://groups.google.com/group/cake-php/browse_thread/thread/8cbf01f7a9acda57/9e84f7aacbf3cd85?lnk=gst&q=tag+conditions&rnum=4#9e84f7aacbf3cd85
http://groups.google.com/group/cake-php/browse_thread/thread/f23b1825050ad543/014092749592de70

Andy Dawson and Jon Bennett are giving detailed explanations backed
with some example code blocks

At first it may look like it's too complicated, but it's not once you
manage to grasp it. I must admit just reading the articles wasn't
enough, but Andy was more than helpful providing additional hints on
IRC.

Long story short - you can't use offset and paged filterings, because
HABTM associated models are not pulled from DB with JOINs. Joins are
used for hasOne and belongsTo associations only. The solutions is to
bind an additional hasOne association using a dummy (fake) model for
the join table. Note: implementing this wouldn't in any way prevent
your application's code based on your HABTM associated models to
function normally. You'd just bind the extra model on the fly for the
current action.

Here's some example code from my case:

Note, that I didn't use bindModel() on the fly, because I couldn't
find a way to make the binding persistent. The pagination component
makes a cuple of sql queries to get the pages, etc. so the
associations gets reset to the ones defined in the models after the
first query.

The API for Cake 1.2 has a second parameter for
Model::bindModel(array(), $reset = true) which can be passed as FALSE
to make the bindings persistent. However, the API for Cake 1.1 doesn't
have such a parameter, so I've associated the fake modek in the
Bookmark's model definition.

### Models

# bookmark.php

class Bookmark extends AppModel
{
    var $name = 'Bookmark';

    var $hasAndBelongsToMany =  array('Tag' =>
                                    array('className'    => 'Tag',
                                            'joinTable'    =>
'bookmarks_tags',
                                            'foreignKey'   =>
'bookmark_id',
                                            'associationForeignKey'=>
'tag_id',
                                            'conditions'   => '',
                                            'order'        => '',
                                            'limit'        => '',
                                            'unique'       => true,
                                            'finderQuery'  => '',
                                            'deleteQuery'  => '',
                                    )
                                );

    // NOTE: the fake association
    var $hasOne = array(
                    'BookmarkTagAssoc' =>
array('className'=>'BookmarkTag')
                  );
}

# tag.php

class Tag extends AppModel
{
    var $name = 'Tag';
    var $recursive = 2;

    var $hasAndBelongsToMany =  array(
                                    'Image' => array('className'    =>
'Image',
                                            'joinTable'    =>
'images_tags',
                                            'foreignKey'   =>
'tag_id',
                                            'associationForeignKey'=>
'image_id',
                                            'conditions'   => '',
                                            'order'        => '',
                                            'limit'        => '',
                                            'unique'       => true,
                                            'finderQuery'  => '',
                                            'deleteQuery'  => '',
                                    ),
                                    'Bookmark' => array('className'
=> 'Bookmark',
                                            'joinTable'    =>
'bookmarks_tags',
                                            'foreignKey'   =>
'tag_id',
                                            'associationForeignKey'=>
'bookmark_id',
                                            'conditions'   => '',
                                            'order'        => '',
                                            'limit'        => '',
                                            'unique'       => true,
                                            'finderQuery'  => '',
                                            'deleteQuery'  => '',
                                    ),

                                );
}

# bookmark_tag.php (the fake model)

class BookmarkTag extends AppModel
{
   // doesn't need anything else
    var $name = 'BookmarkTag';
    var $useTable = 'bookmarks_tags';
}

### Controllers
 # bookmarks_controller.php

class BookmarksController extends AppController {
    var $name = 'Bookmarks';
    var $components = array ('othAuth', 'Pagination', 'Tagging');
    var $uses = array('Bookmark','Tag');

    // the action I'm using to get the bookmarks tagged with $id
    function admin_tag($id) {

        $this->uses[] = 'BookmarkTag';
        $constraint['BookmarkTagAssoc.tag_id'] = $id;
        list($order,$limit,$page) = $this->Pagination-
>init($constraint, null, $this->pagerSettings);

        $tempBookmarks = $this->Bookmark->findAll($constraint, NULL,
$order, $limit, $page);

        foreach($tempBookmarks as $key => $row) {
            $tempBookmarks[$key]['Bookmark']['tagString'] = $this-
>Tagging->getString($row['Tag'], $id);
        }
        $this->set('bookmarks', $tempBookmarks);
        $this->set('currentTagId', $id);

        foreach($_all_tags = $this->Tag->findAll() as $tag) {
            if($id === $tag['Tag']['id']) {
                $this->set('tagName', $tag['Tag']['name']);
                break;
            }
        }

        $this->pageTitle = 'Bookmarks';
        $this->layout = 'admin';
    }

 }

I know how frustrated I felt when I was digging into this matter, so
hopefully this will get you going. I'm copy/pasting this from my
working copy so it is working :-)

Credits go to Andy, Jon and the rest of the guys who keep on answering
questions and making learning Cake a pleasant experience.

Regards, Nasko


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Cake 
PHP" group.
To post to this group, send email to cake-php@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to