cakephp HABTM association saveAll? - cakephp

I have two tables and a join table. I tried using the $hasAndBelongsToMany but it didnt work, so instead i create a model for the join table and used.
User hasMany Membership
Membership belongsTo User, Club
Club hasMany Membership.
I have a form that saves to both tables.
function dashboard_add(){
$user = $this->Session->read('User');
$register = false;
if (!empty($this->data)) {
if($this->Club->saveAll($this->data)){
$this->Session->setFlash(__('You have registered your club. You will be contacted soon!', true), 'default', array('class' => 'success'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('There was a problem with your registration. Please, try again.', true), 'default', array('class' => 'warning'));
}
}
if (empty($this->data)) {
$this->data = $this->User->read(null, $user['User']['id']);
}
$this->set(compact('register'));
}
The User model has
var $hasMany = array(
'Membership' => array(
'className' => 'Membership',
'foreignKey' => 'user_id'
)
);
The Membership Model has
var $belongsTo = array('User','Membership');
The Club Model has
var $hasMany = array(
'Membership' => array(
'className' => 'Membership',
'foreignKey' => 'club_id'
),
'Upload' => array(
'className' => 'Upload',
'foreignKey' => 'club_id'
)
);
I don't get any errors. The club table populates, but the membership and user table doesnt insert/update.
UPDATE: debug($this->Club->save($this->data));
Array
(
[User] => Array
(
[id] => 1
[first_name] => this
[last_name] => that
[company_name] => other
[city] => this
[state] => that
[zip] => other
[telephone] => that
[email_address] => this
)
[Club] => Array
(
[address] => fvdfvx
[title] => xcvxcv
[category] => xcvxcv
[modified] => 2012-05-03 06:31:12
)
)

I presume you are using cakePHP 1.3.x. See the documentation to understand how cake saves many models at the same time, you need to generate an array with all models to save.. for example:
Array
(
[Article] => Array
(
[title] => My first article
)
[Comment] => Array
(
[0] => Array
(
[comment] => Comment 1
[user_id] => 1
)
[1] => Array
(
[comment] => Comment 2
[user_id] => 2
)
)
)
http://book.cakephp.org/1.3/view/1031/Saving-Your-Data
Apparently in your $this->data you only have a simple array [User]. and not multiple arrays to save as in the Example.
I hope I have helped.
Regards.

Related

How to use saveAll with associated datas?

I have a attributes_products and a products table, i don't know why but my data are saved twice (for the attributes_products_table). so if i go to the product page i will insert one row, i will get one data but if there is one data for example, cake will save this data twice plus the new one. Thanks
if($this->request->is('post') || $this->request->is('put') ){
$d = $this->request->data;
if($this->Product->saveall($d, array('deep' => 'true'))){
$this->Session->setFlash("Le produit a bien été enregistré","notif");
}
}
Product Model ;
public $hasMany = array(
'AttributsProduct' => array(
'className' => 'AttributsProduct',
'foreignKey' => 'product_id',
'dependent' => false
),
'ImagesProduct' => array(
'className' => 'ImagesProduct',
'foreignKey' => 'product_id',
'dependent' => false
)
);
Array
(
[Product] => Array
(
[company_id] => 18
[name] => iWatch
[category_id] => 1
[description] => iWatch
[id] => 4
[main_image_file] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[AttributsProduct] => Array
(
[1] => Array
(
[attribut_id] => 2
[description] => sceen
)
[2] => Array
(
[attribut_id] => 1
[description] => monitor
)
)
)
The new generated array for the HABTM record needs to know the existent id if it already exists, or a null if it's supposed to create a new record. In any case, it should have the belongsTo id as well for both tables in the relationship.

CakePHP HABTM add tags to post - won't update join table

I have Cakephp 2.x app. It is simple photo gallery app. I want to add one or more new tags to existing photos. Ideally, I want to be able to remove tags from a photo too.
Cakephp HABTM seems to be made for this and promises to do all of this.
I used a standard baked Edit Photo Form view and controller action, with the addition of a tag list as checkboxes that is populated by controller list.
This works well to view all existing tags for that photo. When I navigate to /app/photos/addtags/id the Edit Photo Form populates with that photo id's photo details, and a full list of available tags each with checkbox, and any previously selected tags are checked.
So far so good, but my problem is if I check a new tag and then click submit, it doesn't update photos_tag join table and instead it just adds a new record to photo table.
This is completely unexpected behaviour. I would expect it to only add new record(s) with photo_id and tag_id for new tags to photos_tag join table.
I know there are a bunch of similar SO questions and I've been to all of them here SO and elsewhere and from what I can tell my tables, models, controller and view are set up properly.
I need help with suggestions on why it isn't working as desired.
Photos table:
id
filename
account_id
created
Tags table:
id
tagname
account_id
category
created
Photos_Tags table:
photo_id
tag_id
Photo.php
public $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'photos_tags',
'foreignKey' => 'photo_id',
'associationForeignKey' => 'tag_id',
'unique' => 'keepExisting',
//'with' => 'PhotosTag',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
Tag.php
public $hasAndBelongsToMany = array(
'Photo' => array(
'className' => 'Photo',
'joinTable' => 'photos_tags',
'foreignKey' => 'tag_id',
'associationForeignKey' => 'photo_id',
'unique' => 'keepExisting',
//'with' => 'PhotosTag',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
PhotosController.php
public function addtags($id = null) {
$this->loadModel('Photo');
if ($this->request->is(array('post', 'put'))) {
//$this->Photo->id = $id;
if ($this->Photo->saveAll($this->request->data)) {
$this->Session->setFlash(__('The photo has been saved.'));
return $this->redirect(array('action' => 'view', $id));
} else {
$this->Session->setFlash(__('The photo could not be saved. Please, try again.'));
}
} else {
$options = array('conditions' => array('Photo.' . $this->Photo->primaryKey => $id));
$this->request->data = $this->Photo->find('first', $options);
}
//$this->request->data = $photo;
$this->set('tags', $this->Photo->Tag->find('list'));
}
Photo edit form:
<div class="photos form">
<?php echo $this->Form->create('Photo'); ?>
<fieldset>
<legend><?php echo __('Edit Photo'); ?></legend>
<?php
echo $this->Form->input('id');
echo $this->Form->input('account_id', array('type'=>'hidden'));
echo $this->Form->input('filename');
echo $this->Form->input('filename_th');
echo $this->Form->input('desc');
echo $this->Form->input('Photo.Tag' , array('label'=>'Tags', 'multiple'=>'checkbox'));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
print_r($this->request->data) :
Array
(
[Photo] => Array
(
[id] => 156
[filename] => front_door_1
[desc] => 0
[account_id] => 1
[user_id] =>
[created] =>
)
[Account] => Array
(
[id] => 1
[account] => ABC Bank
[created] => 2014-06-17
[modified] => 2014-06-17
)
[User] => Array
(
[id] =>
[username] =>
[password] =>
[first_name] =>
[last_name] =>
[role] =>
[email] =>
[ip_address] =>
[activation_code] =>
[account_id] =>
[created] =>
[modified] =>
)
[Comment] => Array
(
)
[Tag] => Array
(
[0] => Array
(
[id] => 27
[tagname] => front_door
[keyname] =>
[category] => feature
[account_id] => 1
[user_id] => 3557
[created] => 2014-07-12 16:58:44
[modified] =>
[PhotosTag] => Array
(
[id] => 1
[photo_id] => 156
[tag_id] => 27
[account_id] => 1
[user_id] =>
[created] =>
)
)
[1] => Array
(
[id] => 65
[tagname] => Surrey_Branch
[keyname] =>
[category] => location
[account_id] => 1
[user_id] => 3557
[created] => 2014-07-12 16:58:44
[modified] =>
[PhotosTag] => Array
(
[id] => 32
[photo_id] => 156
[tag_id] => 65
[account_id] => 1
[user_id] =>
[created] =>
)
)
)
)
1
So after a few days fiddling with this app I created brand new CakePHP app based on same database. This was same CakePHP version. But voila the newly created CakePHP HABTM was working perfectly.
I could view photo tags in photo view and edit forms. I could add/remove tags from photos.
I have done a quick review of differences in code between these CakePHP apps and I just can't see any obvious differences.
I copied and pasted code and files from old app to new app folders including entire views, specialized controller and model code.
Can't say what the difference between them was.
The takeaway here is that a) the CakePHP HABTM worked perfectly with newly baked app, and b) if anyone else encounters similar problems, suggest you try quickly re-baking app.

CakePHP: HABTM relationship returns join table as an object - how do I get rid of it?

I have a 2 CakePHP models, Articles and Categories, attached using a hasAndBelongsToMany relationship, like so:
$category = new Category();
$category->bindModel(array('hasAndBelongsToMany' => array(
'Article' => array(
'className' => 'Article',
'joinTable' => 'articles_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'article_id',
'fields' => 'id,name'
))));
$this->set('categories', $category->find('all',
array(
'fields' => 'id,name'
)));
...but then, when I print out $categories, I get the following:
Array
(
[0] => Array
(
[Category] => Array
(
[id] => 31
[name] => category name
[article_count] => 1
)
[Article] => Array
(
[0] => Array
(
[id] => 1445
[name] => article name
[teaser] =>
[author_id] => 3
[ArticlesCategory] => Array
(
[id] => 6634
[article_id] => 1445
[category_id] => 31
[author_id] => 3
[created] => 2014-03-10 12:27:26
[modified] => 2014-03-10 12:27:26
)
)
)
)
I really don't need the [ArticlesCategory] member of [Article]. This just leads me back to information I already have. I tried limiting recursion but that didn't help.
How would I get rid of this?
You have two options:
[1] Reduce recursive value to 0 (CakePHP default: 1)
$category->recursive = 0;
$category->find('all',
array(
'fields' => 'id,name'
))
[2] Start using ContainableBehaviour (my own preference), which gives you more control over model data retrieved
Add following to AppModel for App-wide coverage:
public $actsAs = array('Containable');
The find method becomes:
$category->find('all',
array(
'fields' => 'id, name',
'contain' => 'Article'
))
That should do it!

Cakephp many to many recursive

Hy i am trying to create a follow feature to my website so user can follow each other , I am using Cakephp what kind of relation should i use , what should i name the tables.
NB: I created a user table + follow table containing user_id and follower_id !
If you don't need to save any information about the relation, then hasAndBelongsToMany is the natural relation to use in this case.
Try this:
// User Model
var $hasAndBelonsToMany = array(
'Follower' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'associationForeignKey' => 'follower_id'
'joinTable' => 'followers_users'
)
)
then you must create the users table as normal, and a table 'followers_users' with columns: 'id', 'user_id', 'follower_id' (and 'created' and 'updated' if you need them).
EDIT :
To retrieve your data (read here) you do it as usual:
$this->User->find('all', array('conditions' => array('id' => 1)));
Then you'll get an array like:
Array(
[User] => array(
[id] => 1
[name] => xxxx
)
[Follower] => array(
[0] => array(
[id] => 2
[name] => yyyy
)
[1] => array(
[id] => 3
[name] => zzzz
)
)
)
To save your data (read here and here), you need to create an array like:
array(
[User] => array(
[id] => 1
[name] => xxx
)
[Follower] => array(
[0] => array(
[id] => 2
)
[1] => array(
[id] => 3
)
)
)
Explanation of what you are looking / example is right in the book:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#multiple-relations-to-the-same-model
Similar example per the book:
"It is also possible to create self associations as shown below:"
<?php
class Post extends AppModel {
public $name = 'Post';
public $belongsTo = array(
'Parent' => array(
'className' => 'Post',
'foreignKey' => 'parent_id'
)
);
public $hasMany = array(
'Children' => array(
'className' => 'Post',
'foreignKey' => 'parent_id'
)
);
}

How to display results from a HABTM relationship in a view?

I have a HABTM relationship between a books table and an authors table, joined with an authors_books table.
However, I can't find a solution to display the fields firstname, lastname and fullname in my view.
book-model:
class Book extends AppModel {
var $name = 'Book';
var $hasAndBelongsToMany = array(
'Author' => array(
'className' => 'Author',
'joinTable' => 'authors_books',
'foreignkey' => 'book_id',
'associatioanForeignKey' => 'author_id'
)
);
author-model:
class Author extends AppModel {
var $name = 'Author';
var $virtualFields = array(
'fullname' => "CONCAT(firstname,' ',lastname)"
);
var $fullname = 'fullname';
var $hasAndBelongsToMany = array(
'Book' => array(
'className' => 'Book',
'joinTable' => 'authors_books',
'foreignkey' => 'author_id',
'associatioanForeignKey' => 'book_id'
)
);
books_controller:
function view($id) {
$this->Book->id = $id;
$this->set('book', $this->Book->read());
}
debug($book) in my wiev.ctp give these results:
Array
(
[Book] => Array
(
[id] => 8
[title] => A Forest of Kings: The Untold Story of the Ancient Maya
)
[Author] => Array
(
[0] => Array
(
[id] => 6
[firstname] => Linda
[lastname] => Schele
[fullname] => Linda Schele
)
[1] => Array
(
[id] => 7
[firstname] => David
[lastname] => Freidel
[fullname] => David Freidel
)
)
)
I belive the [0][1] index in the array are the problem.
I've searched the problem, and found some articles on the subject, but can't get any of the solutions to work.
Any help is greatly appreciated. I am using cakephp 1.3.3
Thanks
You would normally loop over the Author array, since you can have a varying number of authors.
<ul>
<?php foreach($book['Author'] as $author){ ?>
<li><?php print($author['fullname']); ?></li>
<?php } ?>
</ul>

Resources