I have two models User and Movie.. Where those are associated with UsersWatchlist..
public $hasAndBelongsToMany = array('User' => array(
'className' => 'User',
'joinTable' => 'users_watchlists',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
))
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'users_watchlists',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
))
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
))
I created 'watchlist' action in UsersController.. The code is below
public function watchlist($id = null) {
$userid = 3;
if (!$id && $userid != 3) {
$this->Session->setFlash('Invalid Movie');
$this->redirect($this->referer(array('action' => 'listing')));
}
$this->request->data['User']['id'] = $userid;
$this->User->UsersWatchlist->create();
debug($this->User->UsersWatchlist->saveAll(array('user_id' => '2', 'movie_id' => 3)));
if ($this->User->UsersWatchlist->saveAll($this->request->data)) {
$this->Session->setFlash('The movie has been added to your watchlist', 'admin/flash_success');
$this->redirect($this->referer(array('action' => 'listing')));
} else {
$this->Session->setFlash('The movie could not be added to your watchlist. Please, try again.', 'admin/flash_error');
$this->redirect($this->referer(array('action' => 'listing')));
}
}
So i am getting an error while saving.. Please tell me the solution
Firstly your data should look like this (provided you want to save it through the user Model):
$this->request->data = array(
'User' => array(
'id' => '2',
),
'Movie' => array(
'Movie' => array(
(int) 0 => '3',
),
),
);
The main mistake I see is that you're trying to save through the Join Model, where you should be saving through the User model. So in the controller use:
$this->User->saveAll($this->request->data)
If the data is as described above it should go fine. I thought I've answered your question here.
Hope this helps.
Cheers!
Your associations seem interesting. Is there a reason you've associated the HABTM join model with the two models (user, movie)? You can achieve the same effect by putting the first $HABTM in the Movie model, and the second $HABTM in the User model. You don't need to create the intermediate join model, cake will do that for you, you only need the table.
Related
I'm in trouble with a more complex situation of HABTM in Cakephp. Ina nutshel, the situation is: a have users and movies, the relationship between then is HABTM, but i also need a relationship types.
USERS - HABTM - MOVIES
|
RELATION_TYPES
The relationship between users and movies could be many different types: author type, public type, etc.
When i try to use the contain behavior, i get an error message that says:
Model "MoviesUser" is not associated with model "RelationType".
But all the models are associated.
These are the models:
User Model
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'movies_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => 'Movie.title',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Movie Model
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'movies_users',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
MoviesUser Model
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'RelationType' => array(
'className' => 'RelationType',
'foreignKey' => 'relation_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In the MoviesController, i'm trying to get some movies and the relation with users and the type of the relation. Here is where i call the Contain on Movies Controller:
$this->Movie->contain(array(
'Person' => array(
'order' => array(
'Person.name'=>'ASC'
),
'Activity'
),
'Country' => array(
'order'=>array(
'Country.name'=>'ASC'
)
),
'User'=>array(
'conditions'=>array(
'User.id'=>$this->Session->read('Auth.User.id')
),
'MoviesUser'=>array(
'RelationType'
)
)
));
When i try to run this i get the message Model "MoviesUser" is not associated with the model "RelationType".
The fields of movies_user are:
id, user_id, relation_type_id, rate, comment
The fields of relation_types are:
id, title
And here my $has_many property on RelationType Model:
public $hasMany = array(
'MoviesUser' => array(
'className' => 'MoviesUser',
'foreignKey' => 'relation_type_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
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 am using these three relations User, Movie and UsersWatchlist.. Where users_watchlists contains movie_id and user_id as attributes.. I have this structure
array(
'User' => array(
'id' => '3'
),
'UsersWatchlist' => array(
'UsersWatchlist' => array(
(int) 0 => '3'
)
)
)
public function watchlist($id = null) {
$userid = '3';
if (!$id && $userid != 3) {
$this->Session->setFlash('Invalid Movie');
$this->redirect($this->referer(array('action' => 'listing')));
}
$this->request->data['User']['User'][] = $userid;
$this->request->data['Movie']['Movie'][] = $id;
debug($this->request->data);
if ($this->User->saveAll($this->request->data)) {
debug("saved");
$this->Session->setFlash('The movie has been added to your watchlist', 'admin/flash_success');
//$this->redirect($this->referer(array('action' => 'listing')));
} else {
debug("saved bo");
$this->Session->setFlash('The movie could not be added to your watchlist. Please, try again.', 'admin/flash_error');
//$this->redirect($this->referer(array('action' => 'listing')));
}
}
I used saveAll method on User but its not saving.. Please provide me solution to save the data..
In Movie model,
public $hasAndBelongsToMany = array('User' => array(
'className' => 'User',
'joinTable' => 'users_watchlists',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In User model,
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'users_watchlists',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In UsersWatchlist model,
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
The data array you're trying to save is wrong.
If you're saving throung the User model your structure should be:
array(
'User' => array(
'id' => '3'
),
'Movie' => array(
'Movie' => array(
(int) 0 => '3'
)
)
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.
<?php
class Product extends AppModel {
var $name = 'Product';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Brand'
);
var $hasOne = array(
'PhotoSmall' => array(
'className' => 'Photo',
'foreignKey' => 'product_id',
'dependent' => true,
'conditions' => 'PhotoSmall.tipo = "small"',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
var $hasMany = array(
'PhotoBig' => array(
'className' => 'Photo',
'foreignKey' => 'product_id',
'dependent' => true,
'conditions' => 'PhotoBig.tipo = "big"',
'fields' => '',
'order' => 'PhotoBig.order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'Rating' => array(
'className' => 'Rating',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
I need all my finds (except in the admin area) to retrieve only products with images.
In the case of PhotoSmall is easy, I can do PhotoSmall.id IS NOT NULL in a condition because CakePhp generates a left join, but i can not find a way to require a least on PhotoBig because CakePhp does two queries to return its results.
The requirement is the following, I can only show products with a PhotoSmall and a least one PhotoBig system wide (except for the admin section of the site), the solution should work with CakePhp pagination
I've tried the following code without success, it only returns product data, not photo data:
$this->Product->recursive = -1;
$conditions = array('Product.category_id'=> $cats);
$joins = array(
array('table' => 'photos',
'alias' => 'PhotoBig',
'type' => 'INNER',
'conditions' => array(
'Product.id = PhotoBig.product_id',
)
),
array('table' => 'photos',
'alias' => 'PhotoSmall',
'type' => 'INNER',
'conditions' => array(
'Product.id = PhotoBig.product_id',
)
)
);
$this->paginate = array(
'limit' => 12,
'conditions' => $conditions,
'joins' => $joins,
);
you need to additionally use contain - at least that worked for me
(due to your recursive=-1):
'contain' => array('PhotoSmall', 'PhotoBig'),
the joins are only the setup configuration. without specifying your data you will only get the one model's data.
do you use the containable behavior? would be the easiest solution.
if not, try to set recursive to 0 or 1.
PS: and your second alias is wrong inside the 'conditions' (should be PhotoSmall there).
Well firstly you're setting recursive to -1 which should just give you Product data no matter what kind of find you do.
Why don't you do an AND condition in a find on the Product model like so:
$this->Product->find('all', array('recursive' => 1, 'conditions' => array(
"NOT" => array('PhotoSmall.id' => NULL, 'PhotoBig.id' => NULL))));
Note: recursive will need to be at least one because you want related data.