CakePHP 2.x HABTM join table with extra fields - cakephp

In a CakePHP 2.3.1 project, I have a typical HABTM relationship between two classes, but I want to add an extra field to the join table. in the Cakephp docs http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-habtm. It says that's possible but it doesn't say how :
Also note that if you want to add more fields to the join (when it was created or meta information) this is possible with HABTM join tables...
(I don't wanna use the hasmany solution it's not suitable for my case, as I need to have the multiselection possibility in my form).

Yes definitely you can add fields in HABTM Relation ship in CakePHP 2.X
Check out the below sample HABTM Relationship:
var $hasAndBelongsToMany = array(
'Category' => array(
'className' => 'Category',
'joinTable' => 'user_categories',
'foreignKey' => 'user_id',
'associationForeignKey' => 'category_id',
'with' => 'UserCategory',
'unique' => 'true',
'fields' => 'User.name',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In the above "fields" option u can mention your join fields if any and it will work.

Related

HABTM accessing array value in condition

Hey my problem is to define a condition for a HABTM Model
(int) 0 => array(
'Article' => array(
'id' => '',
'title' => '',
'body' => '',
'created' => null,
'modified' => null
),
'Channel' => array(
'id' => '',
'channelname' => '',
'created' => null,
'modified' => null
),
'Tag' => array(
(int) 0 => array(
'id' => '1',
'value' => 'example',
),
(int) 1 => array(
[maximum depth reached]
),
(int) 2 => array(
[maximum depth reached]
)
),
),
I want to define a condition that searches the Tag values for specific values .. like that:
$this -> Article -> find('all', array('conditions' => array('Tag.0.value' => 'test'))
So does someone knows how to "foreach" that array in this condition? thanks (:
You either need to:
Run your find from the other direction (using CakePHPs awesome Containable Behavior to get the Articles):
$this->Tag->find('all', array(
'conditions' => array(
'Tag.value' => 'test'
),
'contain' => array(
'Article'
)
));
Or, use JOINs. Run your find like you're doing, but do an INNER JOIN on tags where the tag value='test'
You cannot limit the main Model's results based on an associated model's conditions. The reason is, when you rely on recursive, or use Contain, CakePHP actually creates separate queries to pull in your different models' data. Therefore, you can't have a condition in one query affect the other query.
See similar question/answers:
How do I restrict query results based on sub-results in CakePHP?
Conditions in JOINed tables shows error CakePHP
cakephp contain filtering by parent model value
cakephp contain association conditions issue
Adding conditions to Containable in CakePHP

CakePHP containable HABTM limit

According to the second sentence on the Containable Behavior section of the Cookbook, contain() supports the limit clause.
A new addition to the CakePHP 1.2 core is the ContainableBehavior. This model behavior allows you to filter and limit model find operations.
I'm Using CakePHP 2.5.
I have two models: Product and Category (HABTM relation).
The relations for Product:
public $hasAndBelongsToMany = array(
'Category' => array(
'className' => 'Category',
'joinTable' => 'categories_products',
'foreignKey' => 'product_id',
'associationForeignKey' => 'category_id',
),
);
The relations for Category:
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'categories_products',
'foreignKey' => 'category_id',
'associationForeignKey' => 'product_id',
),
);
I’m trying do use limit as follows:
$cats = $this->Category->find('all', array(
'fields' => array(
'id',
'parent_id'
),
'contain' => array(
'Product' => array(
'fields' => array(
'id',
'name',
),
'limit' => 3,
'order' => array('created DESC'),
),
),
));
The result is that overall only 3 products are selected. Not 3 product per category. The containable behavior is properly loaded. How do I get 3 products per category?
Unfortunately you cannot use 'limit' on HABTM relationships. For performance reasons, CakePHP builds a single query to fetch all the HABTM records, which are later recursively assigned to the parent record key in the output array.
If you apply a LIMIT clause, it will result in CakePHP only fetching a limited number of associated Products, as you have noticed.
The HABTM section in the Cookbook should probably be amended to remove 'limit' as an option, or clarify its intended use.
See this answer for further information:
CakePHP and HABTM Model Limit Error

Associate different column name to one Model + cakephp

how to get name of (UserTransactionType.name) with Transaction.who_pay_fee_1,2,3 fields.
'user_transaction_type_id' works well but how to get the rest of fields work :(
//Transaction Model
public $belongsTo = array(
'UserTransactionType' => array(
'className' => 'UserTransactionType',
'foreignKey' => 'user_transaction_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
//UserTransactionType Model
public $hasMany = array(
'Transaction' => array(
'className' => 'Transaction',
'foreignKey' => 'user_transaction_type_id',
'dependent' => false,
))
This is the sample code for your controller:
$this->UserTransactionType->find('all',array(
'fields' => array('name'),
'contain' => array('Transaction')
)
);
If Models are associated you can specify in 'contain' which of them you want to get in the result.
If you want to have only some fields of related Model, you can determine them after 'Transaction' in 'contain' just like in the regular find() query:
'contain' => array('Transaction' => array('fields' => array('field_1',
'field_2') ))
But in your case, you don't need to specify fields, because by default you get all fields.
So no matter if you define or not fields "who_pay_fee_1,2,3" because if you use 'contain' by default you will get foreing_key - user_transaction_type_id.
I hope it's helpful
For people they like CakePhp :)
in Controller ->
get the list of 'UserTransactionType'
in View ->
after looping trough all the transactions; in Transaction Status column simply load the 'UserTransactionType'array and assign the number of array to $userTransactionTypes.
$userTransactionTypes[$transaction['Who_pay_fee_1']];
To be honest it was straight forward but needed a bit concentration :)

cakePHP saving entries to join table of existing records

first a short description. I have to models: accounts and users and a join table of it accounts_users. the models have a habtm associasions on each model:
User Model:
'Account' => array(
'className' => 'Account',
'joinTable' => 'accounts_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'account_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
Account Model:
'User' => array(
'className' => 'User',
'joinTable' => 'accounts_users',
'foreignKey' => 'account_id',
'associationForeignKey' => 'user_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
Now im trying to save manually relations between this two just to the join table acccounts_users from allready existing entries, here my code
$account = base64_decode($this->params['pass']['0']);
$token = $this->params['pass']['1'];
if($user = $this->User->findByToken($token))
{
// ZUr test zwecken
# $this->User->query(" INSERT INTO accounts_users (account_id ,user_id) VALUES (222, 223); ");
$aId = $this->Account->findById($account);
$this->data['User'][0]['user_id'] = $user['User']['id'];
$this->data['Account'][0]['account_id'] = $aId['Account']['id'];
$this->User->bindModel(array(
'hasMany' => array('AccountsUser')
));
$this->User->saveAll($this->data, array('validate' => false));
print_r('gefunden'); die;
$this->Redirect->flashSuccess('Account Invitation successfull. Log In!', array('controller' => 'users', 'action' => 'login'));
}
else
{
print_r('nicht gefunden'); die;
// user nicht gefunden zum login umleiten
$this->Redirect->flashWarning('Account Invitation error. Please try again!', array('controller' => 'users', 'action' => 'login'));
}
the results are a new entry on the accounts_users table but the user_id is 0. I don't understand why is missing the user id because its passed corectly. even if i pass in the data array some ids manually its writting just the account_id without the user id.
UPDATE
I played a little bit with the models and saved the data to the accounts_users thru the account model see the updated code:
$this->data['User']['id'] = $user['User']['id'];
$this->data['Account']['id'] = 33; #$aId['Account']['id'];
$this->Account->AccountsUser->create();
$this->Account->saveAll($this->data, array('validate' => false));
so now the script inserts both ids, BUT, if there is an entry form another user with the same account id the the user gets overwritten. anything else works. Any idears of how to create a new entry with an axisting account id for new user?
This are the mysql queries i get:
UPDATE accounts SET id = 33 WHERE accounts.id = 33
SELECT AccountsUser.user_id FROM accounts_users AS AccountsUser WHERE AccountsUser.account_id = 33
DELETE AccountsUser FROM accounts_users AS AccountsUser WHERE AccountsUser.account_id = 33 AND
INSERT INTO accounts_users (account_id,user_id) VALUES (33,'32')
Any idears why? Thanks in advance
CakePHP 1.x treats HABTM join tables quite 'dumb'; it will remove all existing records and insert new records to replace them. This is a major PITA if your join-table also contains additional data. (It's possible to prevent this from happening by adding some code in your beforeSave() callbacks)
CakePHP 2.1 has an option keepExisting for HABTM relations. This option prevents CakePHP from deleting the records in the JOIN table. If this is a new project I would really advise to use CakePHP 2.x as a lot has improved since CakePHP 1.x.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany-through-the-join-model
Some hints on saving data in the join table can be found here;
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-hasmany-through-data
For CakePHP 1.3 (look below 'when HABTM becomes complicated)
http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Models.html#saving-related-model-data-habtm

Join two tables using specified fields in CakePHP

I have two tables called Siteaddress and Jobsheet. In the Jobsheet table there is a field called siteaddress that contains the ID of the site address stored in the Siteaddress table.
The problem I am having is that while I'm doing the join in the controller, CakePHP is joining the Siteaddress table to the Jobsheet table using the id fields in both tables. This causes a problem as there is only one record (so far) in the Siteaddress table, and multiple records in the Jobsheet table.
What I need to do is tell CakePHP to join Jobsheet.siteaddress to Siteaddress.id instead of the way it's working at the moment.
How am I able to do this?
Below is the relationship code from the Jobsheet model file:
public $hasOne = array(
'Company' => array(
'className' => 'Company',
'foreignKey' => 'id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Siteaddress' => array(
'className' => 'Siteaddress',
'foreignKey' => 'id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Cheers!
You've set the foreignKey to id so Cake uses this for making the join. This key can be set to any table field you want in the table you want joined. If I understand you correctly you should set the foreignKey to siteaddress:
'Siteaddress' => array(
'className' => 'Siteaddress',
'foreignKey' => 'siteaddress',
'conditions' => '',
'fields' => '',
'order' => ''
)
See the manual entry for hasOne as well.
EDIT:
In this case $belongsTo might be a better fit as an association.

Resources