4

I am new to CakePHP and have a fairly basic question. I have two tables : books and users. books and users have a habtm relationship. I have created the MVC for the above. Now when a user logs into the system, I want the user to be able to reserve a book (ie an entry in books_users), by looking at the results of the 'index' action. What is the API to be used?

$this->Book->save() does not seem appropriate as we aren't creating a book. We only want an association between an existing book and the logged-in user.

I am trying to avoid, retrieving $this->Book, iterating manually through the sub-array User, creating a new sub-array and saving the whole thing back. I am sure there must be a simpler way.

Chuck Burgess
  • 11,600
  • 5
  • 41
  • 74
Ajay K
  • 354
  • 1
  • 4
  • 14
  • You are saying you have two tables: **books** and **users**, are you? Is there third table **books_users** which you just mentioned as an example but not a _real table_, didn't you? And if you have the third table, why not use its model to **save books against to the right user**? – tech_me Jan 10 '13 at 14:55
  • save() wont create a new row if you set an id beforehand. For example, you can have `$data['id'] = 3; $this->User->save($data);`. This will save your data in User with id = 3 and the system will automatically update your books_users tables where users = 3 – gerl Jan 11 '13 at 15:51

3 Answers3

2

Adapted from Chuck's answer, unsure why edit was pushed back.


In app/Model/Book.php

class Book extends AppModel {

    /************************************************************************
     * If you want your multiple assoc. to work you must set unique to      *
     * false, otherwise when you save an entry it will enforce unique       *
     * on book ID and subsequently your associations will delete previously *
     * saved associations, acting more like "User HasMany Books".           *
     ************************************************************************/

    var $hasAndBelongsToMany = array(
        'User' => array(
            'className' => 'User',
            'unique' => false                    
    ));

    public function addUser($bid, $uid) {
        $this->data['User']['id'] = $uid;
        $this->data['Book']['id'] = $bid;

        $this->save($this->data);
    }

}

In app/Controller/BooksController.php (or UsersController)

$this->Book->addUser($bid, $uid);

Fat Models / Skinny Controllers. Allows duplicate entries (you need to constrain limits and check for duplicates, otherwise default behaviour makes HMBTM difficult). Does exactly what you want it to, you just need to supply book and user id.

CakePHP doesn't tend to encourage complex associations, and the reason this is because HMBTM is just a convenience and care should be taken when mixing it with other associations, as per the link provided below, self defined associations are more predictable than HMBTM in CakePHP

http://book.cakephp.org/2.0/en/models/saving-your-data.html#what-to-do-when-habtm-becomes-complicated

Christos Hrousis
  • 707
  • 4
  • 16
  • The edit was rejected because it completely changed my answer. While your answer is good, edits are intended to make minor changes without completely changing the response of the original poster. Use edits to fix misspellings, adjust syntax, or minor revisions. Your edit was a complete rewrite. Make sense? – Chuck Burgess Jan 06 '14 at 04:54
  • No worries, was just trying to be helpful because your answer helped me. :) – Christos Hrousis Jan 07 '14 at 04:44
1

You simply need to save a record to Book or User that contains the ids of both and it will insert it into the HABTM table.

$this->data['User']['id'] = {USER_ID};
$this->data['Book']['id'] = {BOOK_ID};

$this->Book->save($this->data);

Look at the HABTM table and you will find the record.

Chuck Burgess
  • 11,600
  • 5
  • 41
  • 74
  • What happens if a similar row (same USER_ID, BOOK_ID) already exists? Is a duplicate row created? – Ajay K Jan 22 '13 at 05:32
  • 1
    Depends on the constraints in the table. If you make the USER_ID & BOOK_ID UNIQUE, then no, you will get an error. If not, then yes. You can always right code to check for the record first and insert only if it is not found. That is a good use for the `beforeSave()` method. – Chuck Burgess Jan 22 '13 at 06:10
0

did you bake your application? This (basic) functionality will be provided to you for you to adapt.

In short - take the id of the book and the id of the user. Save it to your books_users table.

id | book_id | user_id
 1         1         1
 2         2         2
 3         2         3

If you have set your associations up correctly, when you request a user, all their books will be returned from the join table.

Your logic will need to deal with - number of books available,if a person can reserve more than one book at once...

http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm

Has an example.

Ross
  • 18,117
  • 7
  • 44
  • 64
  • I have done the bake and have the index/add/edit/del actions and views and this portion works fine. However, in my case, I want to know the API to be used to add an individual book to a user from the BooksController. The flow is 1) User views the index view, 2) selects a book 3) clicks on submit/add and that particular item is added to the `books_users` table. – Ajay K Jan 10 '13 at 14:13
  • You should watch out for the structure of the array you're passing to `Model::save()`. HATBM has been widely discussed - [Here](http://stackoverflow.com/questions/10428233/cakephp-2-1-saving-habtm-fields/10447063#10447063) and [Here](http://stackoverflow.com/questions/10429812/cakephp-saving-data-in-habtm-fields/10431118#10431118) and [Here but with additional functionality](http://stackoverflow.com/questions/5795615/saving-habtm-with-extra-fields/10348655#10348655). Notice that in the first and second examples the other model has two levels in the array being passed to `save()`. – Borislav Sabev Jan 11 '13 at 09:14
  • I get the following error with habtmAdd "Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'habtmAdd' at line 1" I have used both the original and the 2.x versions of extend_associations.php. – Ajay K Jan 22 '13 at 05:33