CakePHP save two models, second based on first - cakephp

I have the following association:
Group hasAndBelongsToMany User, with the groups_users join table.
When I create a new group, I want to add to the join table the founder of the group.
My $this->data array looks like:
Array
(
[Group] => Array
(
[name] => seyufgsduifsj
[access] => 2
[founder_id] => 3
[random_key] => I6XC7uMTelpTSdq8DbtLPjqubiF7s6Pn
)
[GroupsUser] => Array
(
[user_id] => 3
[group_role_id] => 1
[random_key] => PZsDZXcoCTHw1IuvqsfURVpPX6AcZ3r2
)
)
I tried with save() and saveAll(), but it would add only the group in the groups table and not the user-group association.
So, basically, I have an add form where the user fills in the group name and access. Then, if the data validates, I add a couple of more field values to the group array (like random_key) and to the join table array (like user_id and group_role_id). I want Cake to save the group first, take its id, update the join table array with the proper group_id, and then save this second array too.
Is this possible in a straight-forward way, or do I have to write two consequent save() methods, for the second one providing the last inserted id in the first one?
Thanks!

You can use saveAll() function, but you need to change the format of the GroupsUser array. According to documentation of saveAll() your data should look like this:
Array
(
[Group] => Array
(
[name] => seyufgsduifsj
[access] => 2
[founder_id] => 3
[random_key] => I6XC7uMTelpTSdq8DbtLPjqubiF7s6Pn
)
[GroupsUser] => Array
(
[0] => Array
(
[user_id] => 3
[group_role_id] => 1
[random_key] => PZsDZXcoCTHw1IuvqsfURVpPX6AcZ3r2
)
)
)
Your example would work if the relation is Group belongsTo GroupsUser, but I believe this is not your case

Perhaps the related models are not passing validation. Use the following piece of code to save only if all models validate:
$this->Group->saveAll($this->data, array('validate' => 'only'));
If you don't find your Group being saved this time around, then it's most probably validation rules in your Join Model that are failing. My guess is that you have a notEmpty validation for the group_id, which you would have to remove in order for saveAll() to work.
Hope this points you in the direction of solving your problem.
EDIT: Your associations are a little off. Here's what it should be:
Group hasMany GroupsUser
User hasMany GroupsUser
GroupRole hasMany GroupsUser
GroupsUser belongsTo Group
GroupsUser belongsTo User
GroupsUser belongsTo GroupRole
Remove the hasAndBelongsToMany association between Groups and User. It doesn't exist any more.

Related

CakePHP: HABTM relationship

I have tables: costumers, types and items, as follows:
items belongsTo types
customers HABTM types
customers HABTM items
To check for types ($ this-> Client-> Type-> find ( "all")) must Items are aligned with Types. For example:
type 1
-- item A
-- item B
type 2
-- item J
-- item K
Each type or item should be marked (checkbox) when it is registered to the client. Any idea how to do this properly?
To save a HABTM relation you just need send the id of the model that will be related, like this:
Array
(
[Client] => Array
(
[name] => my other Client
[Item] => Array
(
[0] => 2
[1] => 4
)
)
)
If you prefer you can check this post that is very clear about how to save HABTM relations http://www.pabloleanomartinet.com/cakephp-2-x-saving-validating-habtm-relation-example/
Thanks

Why is saveAll() only saving the last record?

I have a situation where, for external reasons, I have to directly save join records rather than saving them as part of a join. Here's what I mean:
I have a Firm model whose data is pulled from an external source.
I have a County model in my app database
I have a counties_firms join table that I use to associate those external firms to counties.
Because of what lives where, I'm not editing a Firm model nor am I editing a County model. I'm really just editing the associations. I have a Firm model to encapsulate anything I need to do with Firm data and one of these methods is Firm::saveCounties( $data ). It:
Accepts incoming data that includes the firm id and the county ids that should be associated.
Deletes all existing join records for that county
Attempts to save all of the new join records.
What I'm finding is that only the last county record is saved. Here's the incoming data:
Array
(
[0] => Array
(
[firm_id] => 13
[county_id] => 4fa16e24-a25c-4523-8a9e-7d1d147402e8
)
[1] => Array
(
[firm_id] => 13
[county_id] => 4fa16e27-ccd0-4f22-97da-7d1d147402e8
)
[2] => Array
(
[firm_id] => 13
[county_id] => 4fa16e4a-68f8-4fb1-95bb-7d1d147402e8
)
)
Given that data, I'm creating an on-the-fly association between Firm and CountiesFirm and attempting to $this->CountiesFirm->saveAll( $data ).
As I mentioned, only the last of the 3 county associations in this example is getting saved. Any idea what I might be missing?
Thanks.
Your array is fine. It seems the model is not clearing its id, you can try and add ['id'] => null to every record in your array to force model id clearing.
This worked for me.
I believe you are missing a level in your array... it should look something more like this...
Array(
'CountiesFirm' => array(
[0] => Array
(
[firm_id] => 13
[county_id] => 4fa16e24-a25c-4523-8a9e-7d1d147402e8
)
[1] => Array
(
[firm_id] => 13
[county_id] => 4fa16e27-ccd0-4f22-97da-7d1d147402e8
)
[2] => Array
(
[firm_id] => 13
[county_id] => 4fa16e4a-68f8-4fb1-95bb-7d1d147402e8
)
)
)
Try that and let me know you results

CakePHP update many to many resource

I have a category-product many to many relationship. When a product is created one or more categories are selected and then the product is saved. This works fine and the join table is correctly populated. The issue is when I go to edit the product, I can add more categories, change them etc... The issue comes when I try to save, it fails.
The line that I'm using to save is:
$this->Product->saveAll($this->data)
$this->Product->id is correctly populated and the debug of $this->data gives me an array like so :
Array(
[Product] => Array
(
[0] => 17
)
[Category] => Array
(
[0] => Array
(
[0] => 85
)
[1] => Array
(
[0] => 96
)
)
)
I don't know why it doesn't save as I can't find any detail on the error anywhere.
Any help much appreciated.
I think is this structure is wrong. If you are editing, where's the 'id' field of the product?
[Product] => Array
(
[id] => 17
)
I do that in an application. I will check it out tomorrow(today I cant view the source), but i think the id is the problem.
As raultm says, the structure was slightly wrong but it turned out to be validation in the model. The name and description fields were set to not allow empty and in the structure I wasn't passing these in (wasn't aware you had to on an update). By adding in the missing fields and naming the fields correctly in the array i.e. id, name and description, this worked.

What is the difference between save and saveAll function in cakephp?

can any one give example please
save is used to simply save a model:
Array
(
[ModelName] => Array
(
[fieldname1] => 'value'
[fieldname2] => 'value'
)
)
Assuming the above information was stored in an array called $data, one would call
$this->ModelName->save($data);
in order to INSERT a record into the model's table (if id field is not specified) or UPDATE a record of the model's table (if id field is specified).
saveAll is used to:
Save multiple records of a model
Array
(
[Article] => Array
(
[0] => Array
(
[title] => title 1
)
[1] => Array
(
[title] => title 2
)
)
)
So, you may save many models at the same time instead of looping and using save() each time.
Save related records of a model
Array
(
[User] => Array
(
[username] => billy
)
[Profile] => Array
(
[sex] => Male
[occupation] => Programmer
)
)
This would save both User and Profile models at the same time. Otherwise, you would have to call save() for User first, obtain the id of the newly saved user and then save Profile with user_id set to the obtained id.
Examples taken straight from the book.
saveAll saves all model data in a form, whereas save only saves one. So you would use save to save a single value, while saveAll basically saves you the trouble of using a loop for save.
As of Cake 2.0
save Saves model data (based on white-list, if supplied) to the
database. By default, validation occurs before save.
saveAll Saves multiple individual records for a single model; Also works with a single record, as well as all its associated records.

CakePHP array structure from a HABTM query

I have two tables linked via a HABTM. countries & networks. They are linked together by the countries_networks lookup table.
I need to get all of the countries and all of the associated network ids for each corresponding country. I don't need to go as far as getting the network names, simply getting the ids from the lookup table will suffice.
If I do a find(all) it gives me an array of countries but not in the structure that I need. I need to return something link this, but I only need Country.countryName and CountriesNetwork.network_id:
Array
(
[0] => Array
(
[Country] => Array
(
[countryName] => Aeroplane
)
[Network] => Array
(
[0] => Array
(
[id] => 1
[CountriesNetwork] => Array
(
[id] => 1
[country_id] => 1
[network_id] => 1
)
)
[1] => Array
(
[id] => 7
[CountriesNetwork] => Array
(
[id] => 2
[country_id] => 1
[network_id] => 7
)
)
)
)
)
Is there a way of doing this with a findall()? as if I pass fields as an array I always seem to get an unknown column names SQL error.
Or even a custom query? Many thanks in advance to anyone who may be able to help.
Pickledegg,
Sounds like you should investigate the Containable behavior. It will allow you to specify conditions on the joined models like you want, and will return the data formatted in the same manner as the normal find() call.
Check the manual for more information.
Since you have no model for network_countries it's not possible to get those values using find or findAll. I think the simpliest solution will be to run a custom query to retrieve the data you need.
$query = "SELECT country_id, network_id
FROM countries C LEFT JOIN network_countries NC ON (NC.country_id = C.id)"
$this->Country->query($query);
Unfortunately the result returned using that code will be formatted slightly different then find results.
Or you could add a model for network countries but I don't think this is a good idea.

Resources