I have an issue with using the find query in cakephp.
The problem is as follows :
I have to two models associated with each other..say MODEL 1 hasmany MODEL2.
Now I want to run a find query through model 1 in such a way that it has to fetch different number of results from Model2 Table as follows :
array(
0 => ( Model1 : { table contents }
Model2 : { array( 0 =>
1 =>
2 =>
3 =>
)
}
)
1 => ( Model1 : { table contents }
Model2 : { array( 0 =>
1 =>
2 =>
3 =>
4 =>
)
}
)
)
and so on. In other words Result of Model2 should vary but Model1 has fixed number of entries. I wanted to know what would be the most efficient ways to obtain the above mentioned result.
Further adding -
Consider the following table - Student (id, class, marks)
I want the following result:
There are 100 rows in the table. I want to fetch a total of 11 rows.
Condition => class is 'Computer'
First row should print details of student having id = 15;
Remaining rows should have any 10 ids ie. id != 15.
In total I need a total of 11 rows.
One more constraint is that user having id = 1 can be anywhere in the table.
This is a relation between two model. Hope it helps you....
Model-1:
var $hasMany = array(
'ProductOptionValue' => array(
'className' => 'ProductOptionValue',
'foreignKey' => 'product_option_id',
'conditions' => array('ProductOptionValue.is_active' => 1)
)
);
Model-2:
var $belongsTo = array(
'ProductOption' => array(
'className' => 'ProductOption',
'foreignKey' => 'product_option_id',
'fields' => array('id', 'product_option_name')
)
);
Related
Hi i have two table friends and galleries I want to use CakePHP model Association between two table which Friend.friend_id = 1 and Gallery.user_id = 1
friends
id friend_id
-------------
1 5
2 1
3 6
galleries
id user_id photo
------------------------
1 1 photo1.jpg
2 6 photo2.jpg
3 5 photo3.jpg
Above two table i want to join. But i am unable to join. Please help me.
After lots of research finally i got my answer. This code helps to other-
//$user_id=$this->Session->read('Auth.User.id');
$user_id=1;
$this->Friend->bindModel(
array('hasOne' => array(
'Gallery' => array(
'className' => 'Gallery',
'foreignKey' => FALSE,
'conditions' => array('Friend.friend_id=Gallery.user_id'),
'type' => 'LEFT'
)
)
)
);
$this->Friend->bindModel(array('belongsTo' => array('User' => array('className' => 'User', 'foreignKey' => 'friend_id', 'conditions'=>array('Friend.user_id'=>$user_id)))));
$data = $this->Friend->find('all');
pr($data);
I'm a cakephp newbie, and I was ordered to use the 1.3 version.
I can't understand (and both guides and api docs don't tell it) how I could create an HABTM association in a POST request.
I'm trying to create a wine, that could be made of many vines. For example I'm creating a "soave" whine, that is made of "garganega" and "chardonnay" vines.
How should the POST params should be?
Given theses models
class Wine extends AppModel{
var $hasAndBelongsToMany = array(
'Vine' => array(
'className' => 'Vine',
'joinTable' => 'wine_vines',
'foreignKey' => 'wine_id',
'associationForeignKey' => 'vine_id',
'with' => 'WineVine',
),
);
}
class Vine extends AppModel{
var $hasAndBelongsToMany = array(
'Wine' => array(
'className' => 'Wine',
'joinTable' => 'wine_vines',
'foreignKey' => 'vine_id',
'associationForeignKey' => 'wine_id',
'with' => 'WineVine',
),
);
}
class WineVine extends AppModel{
var $name = "WineVine";
public $belongsTo = array("Wine", "Vine");
}
I tried a POST like this:
Array
(
[Wine] => Array
(
[denomination] => Soave DOP
[fantasy_name] =>
[kind] => White
)
[Vine] => Array
(
[0] => Array
(
[name] => garganega
)
[2] => Array
(
[name] => chardonnay
)
)
)
but it does not perform any inserts in vine table, only in wine.
Here's the log:
2 INSERT INTO `wines` (`denomination`, `fantasy_name`, `kind`, `modified`, `created`) VALUES ('', '', '', '2013-10-25 17:27:14', '2013-10-25 17:27:14') 1 55
3 SELECT LAST_INSERT_ID() AS insertID 1 1 1
4 SELECT `WineVine`.`vine_id` FROM `wine_vines` AS `WineVine` WHERE `WineVine`.`wine_id` = 2 0 0 1
5 SELECT `Vine`.`id`, `Vine`.`name`, `Vine`.`created`, `Vine`.`modified` FROM `vines` AS `Vine` WHERE 1 = 1 5 5 0
6 SELECT `Wine`.`id`, `Wine`.`denomination`, `Wine`.`fantasy_name`, `Wine`.`kind`, `Wine`.`created`, `Wine`.`modified`, `Wine`.`producer_id`, `WineVine`.`id`, `WineVine`.`wine_id`, `WineVine`.`vine_id`, `WineVine`.`created`, `WineVine`.`modified` FROM `wines` AS `Wine` JOIN `wine_vines` AS `WineVine` ON (`WineVine`.`vine_id` IN (1, 2, 3, 4, 5) AND `WineVine`.`wine_id` = `Wine`.`id`)
after saving the wine, try injecting its id into the data array
$this->data['Wine']['id'] = $this->Wine->id;
and then call an overloaded Model::saveAssociated() that will save all vines and update the join table by itself.
this overloaded method is described at:
http://bakery.cakephp.org/articles/ccadere/2013/04/19/save_habtm_data_in_a_single_simple_format
edit: sorry, that's for cake 2.x
i just realized 1.3 has no saveAssociated method
edit 2: but it does work in cake 1.3 if you change the last line of the saveAssociated method to
return parent::saveAll($data, $options);
I am trying to save an array like this
$myData = array(
'User' => array('id' => 17),
'Group' => array(
array('group_id' => 2),
array('group_id' => 3),
array('group_id' => 4),
array('group_id' => 5),
array('group_id' => 6)
)
);
In my HABTM join table (groups_users). I tried the following save calls, but none of them worked.
$this->User->save($myData);
$this->User->saveAssociated($myData);
$this->User->saveAll($myData);
$this->User->GroupsUsers->save($myData);
$this->User->GroupsUsers->saveAll($myData);
Before you ask: Yes, my associations are set-up correctly and I was able to save data by calling:
$this->User->GroupsUsers->saveAll(array(
0 => array(
'GroupsUsers' => array('user_id' => $id, 'group_id' => 1)
),
1 => array(
'GroupsUsers' => array('user_id' => $id, 'group_id' => 2)
)
));
BUT only one of both records are saved, although I set unique to false in the model's HABTM relationship definition.
Where is the error? Is the structure of my array invalid?
The problem is that your data array is incorrectly formatted.
Your Group model will probably have an id field, and your join model GroupsUser will have a group_id field.
So you need to change your group_id to id
try
$myData = array(
'User' => array('id' => 17),
'Group' => array(
'Group' => array(
0 => 2,
1 => 3,
2 => 4,
3 => 5,
4 => 6
)
)
);
Just to answer your question even if it's old.
You doesn't have to call your 'GroupsUsers' model in your saveAll call, this is precisely the goal of associating Models, cakePHP does that for you.
You should pass this array to a saveAll function on your User/Group model:
array{
array{
'User' => array {
'id' => 25
},
'Group' => array {
'id' => 2
}
}
array{
'User' => array {
'id' => 47
},
'Group' => array {
'id' => 2
}
}
}
Both your User and Group Models should have and HABTM relation with each other, so that you just have to do that:
From the User/Group controller:
$this->User/Group->SaveAll($myData);
From the User/Group Model:
$this->SaveAll($myData);
And that's it, the GroupsUsers table will save 2 records, by saving by yourself in the HABTM relation table, you are not using the power of cakePHP.
And the records in both User and Group tables will be created if the ID doesn't exist, updated if not.
The only reason to save in an HABTM table is if you have some extra information you want to save in this table such as a 'validated' fields if you want to validate a member after he asked to join a group for example.
I have two tables: internet_access_codes and radacct.
The internet_access_codes hasMany radacct records.
The join is internet_access_codes.code = radacct.username AND internet_access_codes.fk_ship_id = radacct.fk_ship_id
I created 2 models and wanted to use $hasMany and $belongsTo respectively so that the related radacct records would be pulled when getting and internet_access_codes record.
Here's the code:
class InternetAccessCode extends AppModel{
var $name = 'InternetAccessCode';
var $hasMany = array(
'Radacct' => array(
'className' => 'Radacct',
'foreignKey'=> false,
'conditions'=> array(
'InternetAccessCode.code = Radacct.username',
'InternetAccessCode.fk_ship_id = Radacct.fk_ship_id'
),
)
);
}
class Radacct extends AppModel{
var $name = 'Radacct';
var $useTable = 'radacct';
var $belongsTo = array(
'InternetAccessCode' => array(
'className' => 'InternetAccessCode',
'foreignKey' => false,
'conditions'=> array(
'InternetAccessCode.code = Radacct.username',
'InternetAccessCode.fk_ship_id = Radacct.fk_ship_id'
)
),
);
}
When I find() a record from internet_access_codes I expect it to give me all the relevant radacct records as well. However I got an error because it didnt do the join.
Here's the outcome and error:
Array
(
[InternetAccessCode] => Array
(
[id] => 1
[code] => 1344444440
[bandwidth_allowed] => 20000
[time_allowed] => 30000
[expires_at] => 31536000
[cost_price] => 0.00
[sell_price] => 0.00
[enabled] => 1
[deleted] => 0
[deleted_date] =>
[fk_ship_id] => 1
[downloaded_at] => 2011-09-10 22:18:14
)
[Radacct] => Array
(
)
)
Error: Warning (512): SQL Error: 1054: Unknown column
'InternetAccessCode.code' in 'where clause'
[CORE/cake/libs/model/datasources/dbo_source.php, line 684]
Query: SELECT Radacct.id, Radacct.fk_ship_id,
Radacct.radacctid, Radacct.acctsessionid,
Radacct.acctuniqueid, Radacct.username, Radacct.groupname,
Radacct.realm, Radacct.nasipaddress, Radacct.nasportid,
Radacct.nasporttype, Radacct.acctstarttime,
Radacct.acctstoptime, Radacct.acctsessiontime,
Radacct.acctauthentic, Radacct.connectinfo_start,
Radacct.connectinfo_stop, Radacct.acctinputoctets,
Radacct.acctoutputoctets, Radacct.calledstationid,
Radacct.callingstationid, Radacct.acctterminatecause,
Radacct.servicetype, Radacct.framedprotocol,
Radacct.framedipaddress, Radacct.acctstartdelay,
Radacct.acctstopdelay, Radacct.xascendsessionsvrkey FROM
radacct AS Radacct WHERE InternetAccessCode.code =
Radacct.username AND InternetAccessCode.fk_ship_id =
Radacct.fk_ship_id AND Radacct.deleted <> 1
In the app_model I also added the containable behaviour just in case but it made no difference.
Sadly cakephp doesn't work too well with the associations with foreign key =false and conditions. Conditions in associations are expected to be things like Model.field = 1 or any other constant.
The has many association first find all the current model results, then it finds all the other model results that have the current model results foreignKey... meaning it does 2 queries. If you put the conditions it will try to do it anyway but since it didn't do a join your query will not find a column of another table.
Solution
use joins instead of contain or association to force the join you can find more here
an example of how to use join
$options['joins'] = array(
array(
'table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
));
$this->Model->find('all', $options);
Possible solution #2
BelongsTo perform automatic joins (not always) and you could do a find from radaact, the bad thing of this solution, is that it will list all radacct and put its internetAccesCode asociated instead of the internetAccesCode and all the radaact associated.... The join solution will give you something similar though...
You will need to do a nice foreach that organizes your results :S it won't be to hard though....
Hope this solves your problem.
I made one big form with many associations hasMany/HABTM. All is workin great on creating (!). When updating all is working nice too, but in tables where association is hasMany, data is not updated or replaced, but just inserted. This brings many rows with trash data. How can I make saveAll() do the update/replace in hasMany fields:
Model:
class MainModel extends AppModel {
var $hasAndBelongsToMany = array(
'HABTMModel1',
...
'HABTMModeln',
);
var $hasMany = array(
'Model1' => array(
'dependent' => true
),
...
'Modeln' => array(
'dependent' => true
),
);
}
One of the problematic hasMany models look like:
class Model1 extends AppModel {
var $belongsTo = array(
'MainModel'
);
}
And his table have:
id <- Primary key, auto increment, int (11)
main_model_id <- Foreign_key int (11)
name <- text field, string
The $this->data is looking like:
array(
[MainModel] => array(
'id' => 123
*** aditional data named identicaly to table fields (working great)***
),
[Model1] => array(
[0] => array(
[name] => Test1
),
[2] => array(
[name] => Test2
),
),
*** all other models ***
);
Model1 table results after first creating and after updating:
id main_model_id name
--------------------------------------------------------------
11 306 Test1
12 306 Test2
13 306 Test1 (Thease are dublicates)
14 306 Test2 (Thease are dublicates)
What can I do to update/replace data in hasMany and not insert new values un edit using saveAll ?
Thank you.
In the view, just put hidden input for all the Model1, Model2 ids
echo $form->create('MainModel');
echo $form->hidden('Model1.0.id');
// more stuffs...
echo $form->end('Save');
You probably specify the 'fields' for Model1, Model2 to have only 'name'. That's why $this->data looks like that. So just add 'id' to that.
So I made not so beautiful, but working:
// If edit, then delete data from hasMany tables based on main_model_id
if(isset($this->data['MainModel']['id']) && !empty($this->data['MainModel']['id'])) {
$conditions = array('main_model_id' => $this->data['MainModel']['id']);
// Delete Model1
$this->MainModel->Model1->deleteAll($conditions, false);
...
all other models
...
}
$this->MainModel->saveAll($this->data);
You need to set the id field for your hasMany model too e.g.
array(
[MainModel] => array(
[id] => 123
*** aditional data named identicaly to table fields (working great)*** ),
[Model1] => array(
[0] => array(
[id] => 1,
[name] => Test1
),
[2] => array(
[id] => 2
[name] => Test2
), ), *** all other models *** );