I have the problem in Cakephp that when I define
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'groups_users',
'foreignKey' => 'group_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => 'User.active=1',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
with the conditions field set, so that only users that are active are fetched from the DB, that I get the error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'User.active' in 'where clause'
for the SQL Query:
SELECT `GroupsUser`.`user_id` FROM `groups_users` AS `GroupsUser` WHERE `GroupsUser`.`group_id` = 123 AND `User`.`active`=1
Because obviously it only fetches the results from the join table. So I found here: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm in the description for conditions.
conditions: an array of find() compatible conditions or SQL string. If
you have conditions on an associated table, you should use a ‘with’
model, and define the necessary belongsTo associations on it.
What is a 'with' model and how would I implement it?
Thanks a lot in advance!
Although this question is quite old I've recently encountered the same problem and wanted to document my solution. In the above example instead of referencing the User I've had to do a simple sub query to get the associated field like this:
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'groups_users',
'foreignKey' => 'group_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
//'conditions' => 'User.active=1',
'conditions' => array('(SELECT active FROM users WHERE users.id = GroupsUser.user_id)'=>1),
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In my similar example finds & saves now work.
Related
Suppose I have a table/model Products.
Suppose I have a table/model Equivalencies which has among its columns this 2:
original_id
equivalent_id
Both original_id and equivalent_id have as foreign keys the primary key of Products. So, I can't follow the convention of naming original_id as product_id, because I also have to deal with equivalent_id (which would also be product_id).
What should I do?
Currently, I have the Product model configured as this:
public $hasMany = array(
'Original' => array(
'className' => 'Equivalency',
'foreignKey' => 'original_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => '',
'table' => 'products',
),
'Equivalent' => array(
'className' => 'Equivalency',
'foreignKey' => 'equivalent_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
Could anyone tell me if this is how it's supposed to be done?
What I Want
I want to be able to find all the equivalencies of a given product, but with conditions over the relation (the one with original_id, equivalent_id).
This doesn't work:
$original = $this->Product->find('all',
array(
'contain' => 'Product.Original.deleted_equivalent = false',
'conditions' => array('Product.id' => $id)
));
Your model is fine, that's the way you should do it.
Your call to find is not.
Try this
$original = $this->Product->find('all',
array(
'contain' => array('Equivalent'),
'conditions' => array('Product.id' => $id)
));
I have 3 tables:
- users
- posts
- Subscriptions (which should be by default posts_users (n-n))
The subscriptions table is the n-n table needed for this relation. I didnt want to call it "posts_users" as it is very confusing for my system because i have more relations between users and posts.
The, to create the hasAndBelongsToMany relation, i did this:
Post (model):
public $hasAndBelongsToMany = array(
'Subscriptions' => array(
'className' => 'User',
'joinTable' => 'subscriptions',
'foreignKey' => 'post_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
User (model):
public $hasAndBelongsToMany = array(
'Post' => array(
'className' => 'Post',
'joinTable' => 'subscriptions',
'foreignKey' => 'user_id',
'associationForeignKey' => 'post_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Lets say i want to find the subscribed posts for the user with id 3.
Is there any way to do a find to retrieve data of subscribed Posts for a user?
In which model should i do the query? How??
Thanks.
Ok. Finally i got it.
You can do the query from any of the two related models. In this case Post or User.
$this->Post->User->find('all', array(
'conditions' => array('User.id' => $this->Session->read('Auth.User.id')),
'contain' => array('Subscriptions')
));
This would return the subscribed tickets (in the subscriptions array) for the current user.
I have following relationships
Users(id, name, email, ...)
movies(id, name, ...)
users_watchlists(id, user_id, movie_id)
Its a HABTM relationship.
Error
Error: SQLSTATE[42000]: Syntax error or access violation: 1066 Not
unique table/alias: 'UsersWatchlist'
SQL Query: SELECT UsersWatchlist.id,
UsersWatchlist.first_name, UsersWatchlist.last_name,
UsersWatchlist.display_image, UsersWatchlist.email,
UsersWatchlist.password, UsersWatchlist.birthday,
UsersWatchlist.gender, UsersWatchlist.group_id,
UsersWatchlist.banned, UsersWatchlist.created,
UsersWatchlist.modified, UsersWatchlist.id,
UsersWatchlist.first_name, UsersWatchlist.last_name,
UsersWatchlist.display_image, UsersWatchlist.email,
UsersWatchlist.password, UsersWatchlist.birthday,
UsersWatchlist.gender, UsersWatchlist.group_id,
UsersWatchlist.banned, UsersWatchlist.created,
UsersWatchlist.modified FROM reelstubs.users AS
UsersWatchlist JOIN reelstubs.users AS UsersWatchlist ON
(UsersWatchlist.movie_id = 4 AND UsersWatchlist.user_id =
UsersWatchlist.id)
Notice: If you want to customize this error message, create
app\View\Errors\pdo_error.ctp
Users Model
public $hasAndBelongsToMany = array(
'UsersWatchlist' => array(
'className' => 'Movie',
'joinTable' => 'users_watchlists',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Movie Model
public $hasAndBelongsToMany = array(
'UsersWatchlist' => array(
'className' => 'User',
'joinTable' => 'users_watchlists',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
UsersWatchlist
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Not sure why its trying to fetch name etc from UsersWatchlist
Not sure why its trying to fetch name etc from UsersWatchlist
Because you have a model for the relation datatable called UsersWatchlist and you named the relations between User and Movie with the same name.
Try to update those names:
User Model
public $hasAndBelongsToMany = array(
'Movie' => array(
...
Movie Model
public $hasAndBelongsToMany = array(
'User' => array(
...
These keys are used as aliases in the SQL query, making it fail in this case.
By the way, if you use the users_watchlists datatable only to maintain a link between Users and Movies (for example if you don't store any properties about the relation), you can probably just get rid of the UsersWatchlist model.
I have a Goal model that HasAndBelongsToMany Users. This HABTM is named Participant. When I try to find all the Participants of a goal, the join table for this HABTM is not being used. Here is the related code in the goal model.
class Goal extends AppModel {
var $hasAndBelongsToMany = array(
'Participant' => array(
'className' => 'User',
'joinTable' => 'goal_participants',
'foreignKey' => 'goal_id',
'associationForeignKey' => 'user_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
));
function getParticipantIDs($goalID) {
$this->bindModel(array('hasOne' => array('Participant')));
return $this->find('list', array(
'fields' => array('Participant.user_id'),
'conditions' => array('Participant.goal_id' => $goalID)
));
}
}
I am binding the Participant as hasOne so that it will create a join in the query, but I get the following error:
Warning (512): SQL Error: 1054: Unknown column 'Participant.user_id' in 'field list' [CORE\cake\libs\model\datasources\dbo_source.php, line 525]
Query: SELECT `Participant`.`id`, `Participant`.`user_id` FROM `users` AS `Participant` WHERE `Participant`.`goal_id` = '19' AND `Participant`.`status` != 2
I edited the answer after OP's comment.
If i understand well what you intend to do, this piece of code might help :
function getParticipantIDs($goalID) {
$participants = $this->GoalParticipant->find('list', array(
'fields' => array('user_id'),
'conditions' => array('goal_id' => $goalID)
));
return array_values($participants);
}
I'm not 100% sure GoalParticipant is the correct syntax. I'm pretty sure that if the join table was named goals_participants, the correct syntax would be GoalsParticipant but as it's named goal_participants I guess it might be GoalParticipant.
I am trying to query a hasAndBelongsToMany relationship in Cakephp 1.3, but it looks like the SQL query being run is not doing a Join on the many to many table.
I have a users table, projects table, and users_projects table. I want to get a list of all projects a user is associated with in a separate Allocations controller.
I have been reading the cakephp book on the topic: http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM
So I have been trying this:
var_dump($this->Allocation->User->Project->find('list',array('conditions'=>array('Project.user_id'=>'21'))));
However that does not work, It returns nothing and this error:
Warning (512): SQL Error: 1054: Unknown column 'Projects.user_id' in 'where clause' [CORE/cake/libs/model/datasources/dbo_source.php, line 681]
Query: SELECT `Project`.`id`, `Project`.`name` FROM `projects` AS `Project` WHERE `Projects`.`user_id` = '21'
It looks like cakephp is not doing the required join.
This is in my projects model:
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'users_projects',
'foreignKey' => 'project_id',
'associationForeignKey' => 'user_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
And this is in my users model:
var $hasAndBelongsToMany = array(
'Project' => array(
'className' => 'Project',
'joinTable' => 'users_projects',
'foreignKey' => 'user_id',
'associationForeignKey' => 'project_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
So, what is the correct syntax to get the list of projects for a given user on a many to many relationship in cakephp?
Perhaps that's because you didn't make the two table names connected in alphabetical order.users_projects should be projects_users.
You are getting this error because you are using the find type 'list'. Cake's default behaviour is to select the ID and NAME fields when using this find type.
Change your find type to 'all' to retrieve the results you are expecting:
var_dump($this->Allocation->User->Project->find('list',array('conditions'=>array('Project.user_id'=>'21'))));