views:

768

answers:

1

Hello,

I am relatively new to CakePHP, and I am writing a CakePHP application which currently has an Author model and a Book model. Author and Book both have a many-to-many relationship.
However, I would like to additionally, for every author-book relationship, have a corresponding link to that author's blog where they reflect upon their experiences writing that book.

If that was confusing, the following paragraphs try to elaborate to make my situation more clear:

For every author, there will be one article about their experiences for each book. To look at this relationship in reverse, this means that for every book, there will be one corresponding link, per author (given that books can have multiple authors), where that author describes his/her experience writing the book.

In other words, for every single (Author, Book) pair, I would like to be able to store a related URL.

In more fancy, abstracty math terms that I will use horribly and improperly: I have an undirected graph, where every vertex is an Author or a Book, and every edge has an Author for one vertex and a Book for the other. That sounds kind of confusing, but (I think) it describes my situation as precisely as I can make it.
Given the above description, I want to know if I can attach arbitrary data to any given edge of that relation, and retrieve it later.

Currently I have a third model, AuthorBook, which acts the graph edge.
Author has a hasMany relationship to AuthorBook.
Book has a hasMany relationship to AuthorBook.
AuthorBook has a belongsTo relationship with Author and Book, and additionally has a url field.

This solution works, but for some reason the fact that Book is not directly connected to Author is bothering me. Is there any way to achieve this same effect while also cutting the AuthorBook model out of the picture?

(Also, I realize I can have them directly related while keeping AuthorBook, but that seems ugly and also redundant.)

(Also, I realize that I would still have an author_book SQL table. This does not bother me in the slightest, I think it's impossible to do without anyway.)

Thank you for your time! And please don't flame me!!!

+1  A: 

Yes, you can model the AuthorBook relation (or the 'edge' as you envision it).

class Author extends AppModel {
    ...
    $hasAndBelongsToMany = array('Book', array('with' => 'AuthorBook'));
    ....
}

The "with" habtm option:

Defines the name of the model for the join table. By default CakePHP will auto-create a model for you. Using the example above it would be called RecipesTag. By using this key you can override this default name. The join table model can be used just like any "regular" model to access the join table directly.

This is the equivalent of RoR's "through", depicted quite nicely in this illustration

deizel
I believe you can access the 'with' model using model chaining (`$this->Book->AuthorBook` or `$this->Author->AuthorBook`) without the need for those extra relations. Also, you should be able to save to the join table by using saveAll with an `['AuthorBook']` key in your array (`$this->Book->saveAll()` or `$this->Author->saveAll()`).
deizel