How to edit multiple records with associations? - cakephp

I have 4 tables:
- albums
- images
- tags
- images_tags (id, image_id, tag_id)
I would like to edit multiple records. Everything works fine until I added tags table.
Now my $this->data looks like this: (124 is image id)
Array(
[124] => Array(
[Image] => Array
(
[id] => 124
...
)
[Album] => Array
(
[id] => 2
...
)
[Tag] => Array
(
[0] => Array
(
[id] => 2
....
)
)
[125] => Array( ...
)
This is my view edit file:
<?php foreach($this->data as $key => $value) {
echo $this->Form->input('Image.'.$key.'.id');
echo $this->Form->input('Image.'.$key.'.title');
echo $this->Form->input('Image.'.$key.'.Tag'); // multi select for tags
...
And edit action in Images controller:
$result = $this->Image->find('all', array(
'conditions' => array('Image.id' => $img_ids))
);
$this->data['Image'] = Set::combine($result, '{n}.Image.id', '{n}');
I don't know how can I bind $this->data array with multiple edit form. Previously I had only Image data:
Array(
[124] => Array(
[id] => 2,
...
),
[125] => Array(
...
);
But now I need also information about tags. I am using saveAll() function.

You will need to transform the [Tag] index. The proper format for saving hasAndBelongsToMany is [Tag][Tag] => array(id1,id2,id3,...). For example:
Array(
[124] => Array(
[Image] => Array
(
[id] => 124
...
)
[Album] => Array
(
[id] => 2
...
)
[Tag] => Array
(
[Tag] => Array
(
[0] => 2,
[1] => 16,
...
)
)
[125] => Array( ...
)
Where 2 and 16 are ids of associated tags.

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 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 contain association conditions issue

I have the folowing associations
post->primary->secondary
$results = $this->Post->find('all', array(
'conditions' => array(
'Post.post_id =' => 2,
'Primary.secondary_id !=' => null
),
'contain' => array(
'Primary' => array(
'Secondary' => array(
'conditions' => array('Secondary.short_code =' => 'code')
)
)
)
));
Returns this.
Array
(
[0] => Array
(
[Post] => Array
(
[id] => 2
[created] => 2012-10-29 09:48:29
[modified] => 2012-10-29 09:48:29
)
[Primary] => Array
(
[id] => 3
[secondary_id] => 6
[Secondary] => Array
(
[id] => 6
[short_code] => code
[created] => 2012-10-31 11:19:56
[modified] => 2012-10-31 11:20:03
)
)
)
However when I change
'conditions' => array('Secondary.short_code =' => 'code')
to
'conditions' => array('Secondary.short_code !=' => 'code')
it still returns the primary record, when I dont want it to.
Array
(
[0] => Array
(
[Post] => Array
(
[id] => 2
[created] => 2012-10-29 09:48:29
[modified] => 2012-10-29 09:48:29
)
[Primary] => Array
(
[id] => 3
[secondary_id] => 6
[Secondary] => Array
(
)
)
)
It's hard to know exactly what you're hoping to achieve, but I THINK it sounds like you're trying to limit the 'Primary' results based on conditions against the 'Secondary' model.
If that's the case, you're going to need to use joins() instead of contain().
The reason: When you use CakePHP's Containable Behavior, it actually does separate queries, then combines the results before returning the data to you. Doing it this way is great in many ways, but it does not allow you to limit parent results based on conditions against it's children.
To do that, just use joins(). (CakePHP syntax which creates MySQL JOIN)

HABTM find, how to filter the results

Ive a HABTM relationship where the output is like below, what i would like to do is have cakephp return a "list" with just the "friend.id" and "friend.company_name" and exclude the "User".
Ive spent quite a while researching how to do this and cant get it to work.
My "search method" in users controller; i think i need to use the containable behaviour but im not sure what to do. ive managed to get the "friend" results only show 2 fields but i need to get rid of the "User" results. How do i do this?
The relationship is defined as in the user model file;
var $hasAndBelongsToMany = array(
'Friend' => array(
'joinTable' => 'retailerrelationships',
'className' => 'User',
'foreignKey' => 'retailer_id',
'associationForeignKey' => 'supplier_id'
)
);
user action in user controller:
$this->User->Behaviors->attach('Containable');
$users=$this->User->find('all',array('conditions'=>array('User.id'=>$this->Auth->user('id')),'contain'=>array('Friend.id','Friend.company_name')));
$this->set('users' ,$users);
debug Output
Array
(
[0] => Array
(
[User] => Array
(
[id] => 104
[username] => admin
)
[Friend] => Array
(
[0] => Array
(
[id] => 107
[company_name] => carskitchens
[Retailerrelationship] => Array
(
[id] => 12
[retailer_id] => 104
[supplier_id] => 107
[created] => 2012-03-28 10:14:23
[modified] => 2012-03-28 10:14:23
)
)
[1] => Array
(
[id] => 112
[company_name] => mr manufacturer
[Retailerrelationship] => Array
(
[id] => 13
[retailer_id] => 104
[supplier_id] => 112
[created] => 2012-03-28 11:26:52
[modified] => 2012-03-28 11:26:52
)
)
)
)
)
You should look at the Set class.
Try this
Set::combine($results, '{n}.Friend.id', '{n}.Friend.company_name');

How do I format the output array in CakePHP

Let's say I have an index action where I want to get a list of projects:
$this->Project->find('all', array('order' => 'Project.modified DESC', 'conditions' => array('Project.user_id' => 1)));
It works well and returns the following array:
Array ( [0] => Array ( [Project] => Array ( [id] => 2 [title] => test project ) ) [1] => Array ( [Project] => Array ( [id] => 1 [title] => first project ) ) )
How do I modify the find function, so it returns the array in the following format:
Array ( [projects] => Array ( [0] => Array ( [id] => 2 [title] => test project ) [1] => Array ( [id] => 1 [title] => first project ) ) )
Thank you!
You could use the Set::combine() utility method to do this. I've used it for similar means as so:
public function groupByMenu() {
return Set::combine (
$this->find (
'all',
array (
'conditions' => array ( 'NavItem.active' => 1 ),
'order' => 'NavMenuItem.display_order'
)
),
'{n}.NavItem.title',
'{n}',
'{n}.NavMenu.id'
);
}
The code above takes a set of navigation items and reorganizes them so that they're grouped by the menu(s) they are displayed within.
It's not really clear if it's the fact that the result is under 'Project' rather than 'projects', but if you don't like that it's under [0] I believe you could use PHPs array_shift:
$result = $this->Project->find('all', array('order' => 'Project.modified DESC', 'conditions' => array('Project.user_id' => 1)));
$result = array_shift($result);
The result will be:
Array ( [Project] => Array ( [id] => 2 [title] => test project ) ) [1] => Array ( [Project] => Array ( [id] => 1 [title] => first project ) )

Resources