CakePHP relational models - cakephp

Basically i have 3 tables users , jobs and users_jobs.
users_jobs is id,job_id,user_id and is basically used for keeping track of what jobs a user has assigned.
Jobs can be assigned.unassigned by adding/removing entries in the users_jobs tables.
In terms of cakephp im struggling to understand how to model this.
So for i have a Job model that has the attribute
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'users_jobs',
'foreignKey' => 'job_id',
'associationForeignKey' => 'user_id'
)
);
My User model has the attribute
public $hasAndBelongsToMany = array(
'Job' => array(
'className' => 'Job',
'joinTable' => 'users_jobs',
'foreignKey' => 'user_id',
'associationForeignKey' => 'job_id'
)
);
In my JobsController.php i have the function unassign which is designed to unassign a user from a job. how can i modify the users_jobs table a remove the relation without remove the user or job ?

lets say you have three fields on user_jobs:
status, user_id and job_id
Assuming your table user_jobs has one field status which is defines assigned or unassigned
status=1 => Unassigned
status=0 => assigned
Step 1: Create one methods in JobsController.php
function userjobs($jobId, $userId, $assign = 1){
# $assign is 1 means true and 0 means unassigned
# if you want to assign a job to user
$data['UserJob']['user_id'] = $userId;
$data['UserJob']['job_id'] = $jobId;
App::import('model','UserJob');
$UserJob = new UserJob();
if($assign == 1){
$UserJob->save($data);
}else{
$UserJob->updateAll(
array('UserJob.status'=>1),
array('UserJob.user_id'=>$userId,'UserJob.job_id'=>$jobId));
}
}
Step 2: call this method on ajax.
It will do the desired thing.

Related

CakePhp: Find using Contain with condition

I have the following models:
Company(id, name)
Employee(id, name, company_id, isRemoved) [Company has many Employees]
In the association specified, the employee has a default condition, that
public $hasMany = array(
'Employee' => array(
'className' => 'Employee',
'foreignKey' => 'company_id',
'dependent' => true,
'conditions' => array(
'Employee.isRemoved' => 0
),
)
);
The association has a default condition of an employee being not removed. I am using the following Find Query on company to get only those employees whose name matches a string:
$this->Company->find('all', array(
'contain' => array(
'Employee' => array(
'conditions' => array(
'Employee.name LIKE' => '%'.$search_text.'%')
),
'fields' => array('Employee.id, Employee.name')
)
)
));
The problem I am facing is that, When I use conditions within contain, the default condition specified in the association is not applied and when the conditions key is not specified, the default condition specified in the association is applied.
Is this a default behaviour of Cakephp and How to proceed about it? I am using Cakephp 2.8.4
I can not tell you if the conditions in the model being overwritten is default behaviour of CakePHP. I can however offer you a possible alternative:
By using the beforeFind() callback in your model you could add your 'Employee.isRemoved' => 0 condition.
So in your Company model you could do something like:
function beforeFind(array $queryData) {
if(isset($queryData['contain']['Employee'])) {
//Notice the extra [] to not overwrite the conditions set in the controller
$queryData['contain']['Employee']['conditions'][]['Employee.isRemoved'] = 0;
}
return $queryData;
}
Disclaimer: I did not test this code.
Source: https://stackoverflow.com/a/17544106/6786476

Saving data with HABTM and HasMany looses foreignKey

I have a User model with two relations:
HasAndBelongsToMany
public $hasAndBelongsToMany = array(
'group' => array(
'className' => 'group',
'foreignKey' => 'user_id'
)
);
HasMany
public $hasMany = array(
'phonenumber' => array(
'className' => 'phonenumber',
'foreignKey' => 'user_id'
)
);
Phonenumber and Group have set
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
When I use
$this->saveAll(array(
'User' => $data,
'phonenumber' => $numbers, //array with data
'group' => $groups //array with data
)
);
The data gets saved in the tabels but User_id is "0" in phonenumber and group table.
How can I get the correct ID saved ? (CakePHP v 2.5)
FWIW saveAll() should work as advertised, populating the new user_id in the child tables in one fell swoop.
Have you paid attention to the relevant options: atomic & deep?
Especially if database does not support transactions, you'll need to pass in atomic:
$this->saveAll(array(
'User' => $data,
'phonenumber' => $numbers, //array with data
'group' => $groups //array with data
),
array('atomic' => false)
);
Considering the CakePHP documentation you will find this hint:
When working with associated models, it is important to realize that
saving model data should always be done by the corresponding CakePHP
model. If you are saving a new Post and its associated Comments, then
you would use both Post and Comment models during the save operation
(http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-hasone-hasmany-belongsto)
Based on that information I suggest you try the following:
$this->User->save($data); // first save the user
Assuming you have multiple numbers:
foreach($numbers as $key => $nbr) {
// set user_id related data
$numbers[ $key ]['Phonenumber']['user_id'] = $this->User->id;
}
Finally save your related data:
$this->User->Phonenumber->saveAll($numbers);
Since this code is untested you may need to take some adjustments. Always ensure to follow the Cake-Conventions and use CamelCase ModelNames.

An instance of a model cannot be created once relation has been added CakePHP

I have three models in question: Customer, Company and User. Customer and User both belong to Company and Company has many Customers as following:
Customer:
var $belongsTo = array(
'Company' => array(
'className' => 'Company',
'foreignKey' => 'company_id',
'dependent' => false,
),
);
Company:
var $hasMany = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'company_id',
'dependent' => false
),
'Customer'=>array(
'className' => 'Customer',
'foreignKey' => 'company_id',
'dependent' => false
)
);
User:
var $belongsTo = array(
'Company' => array(
'className' => 'Company',
'foreignKey' => 'company_id',
'dependent' => false,
),
);
I have a problem when creating/editing Customer objects. Here is how to create form looks like:
echo $this->Form->input('Customer.customer_nr');
echo $this->Form->input('Customer.name');
echo $this->Form->input('Customer.phone');
echo $this->Form->input('Customer.email');
echo $this->Form->input('Customer.address');
echo $this->Form->input('Customer.post_nr');
echo $this->Form->input('Customer.city');
echo $this->Form->input('Customer.company_id', array('value' => $current_user['company_id'], 'type'=>'hidden'));
What I do in the end of the form is I take company_id from a currently logged in user and insert it as a Customer.company_id. It used to work without any problems before the new relations have been introduced. But now as I try to create/edit Customer, I receive the following SQL error:
Error: SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'name' in where clause is ambiguous
Any help is much much appreciated.
Here is the controller add function:
function add() {
if (!empty($this->data) ) {
$this->Customer->create();
if ($this->Customer->save($this->data)) {
$this->Session->setFlash(__('Customer was saved'), 'positive_notification');
$this->redirect(array('controller'=>'events', 'action' => 'dashboard'));
} else {
$this->Session->setFlash(__('Customer has been saved. Please, try again'), 'negative_notification');
}
}
}
The error is definately not being cause by redirect as it was fully tested.
the problem is somewhere else.
It's in fact related to a find() call.
Try to locate the exact code that trigger the error and post it in your question.
Probably you set some conditions like
'conditions' => array(
'name' => 'john'
)
but you better do something like
'conditions' => array(
'User.name' => 'john'
)
after you created the relationship between User and Company (it's just an example, maybe the two tabler involved are others) Cake started to join the two tables. So when you search for a particular name mysql doesn't know if you want user name or company name because you have name column in both tables.
If you look at the generated query (the one that gives you that error) you'll see the two tables joined. If you don't want that join you have to specify recursive => -1
'conditions' => array(
'name' => 'john'
),
'recursive' => -1

CakePHP Model Relationship with Multiple Foreign Keys

In my CakePHP app I have models for Matches and Teams. Each Match has a home_team_id and an away_team_id, both of which reference a different Team.
In my team.php file, I am able to form the relationship for a Team's home matches:
var $hasMany = array(
'HomeMatch' => array('className' => 'Match', 'foreignKey' => 'home_team_id'),
'AwayMatch' => array('className' => 'Match', 'foreignKey' => 'away_team_id')
);
My problem is that I cannot automatically retrieve a Team's home and away Matches in a single array. That is, the retrieved Matches are returned in separate HomeMatch and AwayMatch arrays, which causes sorting difficulties.
I have tried the following:
var $hasMany = array(
'Match' => array('foreignKey' => array('home_team_id', 'away_team_id'))
);
...with no luck.
Any ideas on how to combine these two foreign keys into a single relationship?
Thanks, Ben
A custom finderQuery should do the trick:
public $hasMany = array(
'Match' => array(
'className' => 'Match',
'foreignKey' => false,
'finderQuery' => 'SELECT *
FROM `matches` as `Match`
WHERE `Match`.`home_team_id` = {$__cakeID__$}
OR `Match`.`away_team_id` = {$__cakeID__$}'
)
);
I was having a similar issue and instead of creating a finderQuery I used the conditions operator and it worked great!
public $hasMany = array(
'Match' => array(
'className' => 'Match',
'foreignKey' => false,
'conditions' => array(
'OR' => array(
array('Match.home_team_id' => '{$__cakeID__$}'),
array('Match.away_team_id' => '{$__cakeID__$}')
)
),
)
);
They are returned in seperate array's because the sort of represent different models (in this particular case the model is the same).
You should probably build a helper method to go over the retrieved data (in the model object or in a separate helper class) and "flatten" it. then you'd be able to sort it.
Ken.

CakePHP Relationships - How to setup relationship for message system?

I am trying to make a messages functionality similar to the facebook. Just the message thing and not facebook. A brief descriptions does like this.
1) There are a number of users ( user table)
2) One person can send a message to one or more than one person.
3) There can be multiple reply to the same message.
4) If its send to multiple people. All can reply and it is show to all of them.
Tables used
messages table
id
timestamp
sender_id
subject
message
due_date
urgent_flag
open_flag
reply_id
message_user (table)
id
timestamp
message_id
receiver_id
read_flag
The CakePHP relations are as follows :
Message Model
var $hasMany = array(
'MessageUser' => array(
'className' => 'MessageUser',
'foreignKey' => 'message_id',
)
);
var $belongsTo = array (
'User' => array (
'className' => 'User',
'foreignKey' => 'sender_id',
)
);
var $hasAndBelongsTo=array(
'Message' => array (
'className' => 'Message',
'foreignKey' => 'reply_id',
)
);
MessageUser Model
var $belongsTo = array (
'User' => array (
'className' => 'User',
'foreignKey' => 'receiver_id',
),
'Message' => array (
'className' => 'Message',
'foreignKey' => 'message_id'
)
);
Questions :
1) Is my approach correct ? Or the database schema needs to be revised.
2) If yes, How should I fetch the data for inbox ? This is a bit complex as I want to show the conversation for those messages which people has sent me.
For example, user 1 send message to user 2. User 2 adds 2 replies to the same. Then users 1's inbox should show only 1 message. and when I open it. it will show the previous msgs as well.. (this is similar to facebook)
One more problem which I see here is, How to delete messages ? Suppose user 1 deletes a message it should not show anything in his inbox. but user 2 can see the whole conversation which he had.
Seems like a good approach
As to your last problem. Add a tinyint / datetime column to message_user, ex. "deleted" (or something similar).
Then in your User-model do something like:
var $hasAndBelongsTo=array(
'Message' => array (
'joinTable' => 'message_user',
'className' => 'Message',
'foreignKey' => 'reciever_id',
'associationForeignKey' => 'message_id'
'conditions' => 'MessageUser.delete = 0'
)
);
You'll need to modify this, but it's a start...

Resources