I know the title doesn't describe the best what I want to achieve, but I couldn't think of anything else.
Let's say I have the following array:
[Sender] => Array
(
[0] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 1
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 3
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
[1] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 3
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 2
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
)
I am using the ContainableBehaviour to cut off extra data.
My problem is: how do I filter out the Senders after a key which is present in PrivateMessagesUser? Say I need only the Sender where PrivateMessagesUser.recipient_id = 3.
I tried with
'Sender' => array(
'PrivateMessagesUser' => array(
)
),
but it didn't work. Looks like I have to get over the [0], [1]... keys somehow and I don't know how.
Any help would be appreciated!
EDIT
Here's how I obtain the array posted above:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()
),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
'PrivateMessagesUser' => array(
'fields' => array('PrivateMessagesUser.id')
//'conditions' => array('PrivateMessagesUser.recipient_id' => $this->Auth->user('id'))
)
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
);
How can I edit these lines in order to achieve the desired result?
EDIT 2
I am calling the paginate() from the PrivateMessagesController.
Associations:
User Model:
var $hasAndBelongsToMany = array(
'PrivateMessageSent' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'sender_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'PrivateMessageReceived' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'recipient_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
PrivateMessage Model:
var $hasAndBelongsToMany = array(
'Sender' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'sender_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Recipient' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'recipient_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
);
PrivateMessagesUser Model:
var $belongsTo = array(
'PrivateMessage' => array(
'className' => 'PrivateMessage',
'foreignKey' => 'private_message_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Sender' => array(
'className' => 'User',
'foreignKey' => 'sender_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
And the database tables look like:
users: id, username, ...
private_messages: id, subject, ...
private_messages_users: id, private_message_id, sender_id, recipient_id, status, ...
There are three ways to achieve this.
Looking at your returned data array, I'm guessing PrivateMessagesUser belongsTo Sender.
1. Querying the PrivateMessagesUser model
Sometimes, all it takes is querying the right model. You can apply the conditions directly to the model you want to apply your restrictions on.
$this->Sender->PrivateMessagesUser->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender')
));
2. Applying conditions to related models
This doesn't work all the time, because CakePHP's SQL generation doesn't always work the way you want it to. But in simple cases like a hasMany relationship, you can use this:
$this->Sender->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('PrivateMessagesUser')
));
Again, this will work only if Cake executes a JOIN for the Containable parameters AND uses the conditions right.
3. Using joins
This method is foolproof but a little messy since it's highly customizable.
$this->Sender->find('all', array(
'joins' => array(
array(
'table' => 'private_messages_users',
'alias' => 'PrivateMessagesUser',
'type' => 'inner',
'conditions' => array(
'PrivateMessagesUser.sender_id = Sender.id',
'PrivateMessagesUser.recipient_id' => 3
)
)
)
));
My last piece of advice for you is to place this code into the Model. Follow the principle of "fat models, skinny controllers" whenever possible.
In the Sender model:
function fetchByRecipientId($recipientId) {
...
}
Good luck!
EDIT: In order to make this work for pagination, follow the methods above but use the following format:
$this->paginate = array(
'PrivateMessagesUser' => array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender'),
// 'order' => ... other keys if you wish
)
);
$this->set('senders', $this->paginate());
You can put conditions inside Containable, like so:
$this->Sender->find('all', array(
'contain' => array(
'PrivateMessagesUser' => array('conditions' => array('recipient_id' => 3))
)
));
EDIT:
Try modifying your $this->paginate as follow:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()//array of message id's
),
'fields' => array('PrivateMessagesUser.id'),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
)
Then call your paginate $this->paginate($this->PrivateMessage)
Related
I have 5 tables: tournaments, rounds, videos, rounds_tournaments, rounds_videos
Relations:
Tournament hasMany Video
Video belongsTo a Tournament
Tournament HABTM Round
Round HABTM Tournament
Video HABTM Round
Round HABTM Video
What I want to achieve:
Now I only want the videos that belong to a specific Tournament and Round.
So when clicking on a Tournament I only want the rounds associated with the clicked Tournament. And when clicking on a Round I only want the get the videos associated with the clicked Round and the Tournament.
I've tried everything but can't get it to work. I've played with several views as well (the index, view actions of Round/Tournament/Video). I'm not sure where to put the the JOIN statement, but I think it's inside the controller.
The Problem I've got atm is that when clicking on a Round it gives me the videos of that Round but for all the Tournaments and not for one Tournament.
Also looked here:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
CakePHP find HABTM
Round Model:
public $hasAndBelongsToMany = array(
'Tournament' => array(
'className' => 'Tournament',
'joinTable' => 'rounds_tournaments',
'foreignKey' => 'round_id',
'associationForeignKey' => 'tournament_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
'Video' => array(
'className' => 'Video',
'joinTable' => 'rounds_videos',
'foreignKey' => 'round_id',
'associationForeignKey' => 'video_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
Video Model:
public $belongsTo = array(
'Tournament' => array(
'className' => 'Tournament',
'foreignKey' => 'tournament_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
public $hasAndBelongsToMany = array(
'Round' => array(
'className' => 'Round',
'joinTable' => 'rounds_videos',
'foreignKey' => 'video_id',
'associationForeignKey' => 'round_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
Tournament Model:
public $hasMany = array(
'Video' => array(
'className' => 'Video',
'foreignKey' => 'tournament_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
public $hasAndBelongsToMany = array(
'Round' => array(
'className' => 'Round',
'joinTable' => 'rounds_tournaments',
'foreignKey' => 'tournament_id',
'associationForeignKey' => 'round_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
);
RoundsVideo model:
public $belongsTo = array(
'Round' => array(
'className' => 'Round',
'foreignKey' => 'round_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Video' => array(
'className' => 'Video',
'foreignKey' => 'video_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
RoundsTournament model:
public $belongsTo = array(
'Round' => array(
'className' => 'Round',
'foreignKey' => 'round_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Tournament' => array(
'className' => 'Tournament',
'foreignKey' => 'tournament_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
What I have tried:
index action of VideosController
$this->Video->recursive = -1;
$options['joins'] = array(
array('table' => 'rounds_videos',
'alias' => 'RoundsVideo',
'type' => 'inner',
'conditions' => array(
'Video.video_id = RoundsVideo.video_id'
)
),
array('table' => 'rounds',
'alias' => 'Round',
'type' => 'inner',
'conditions' => array(
'RoundsVideo.round_id = Round.round_id'
)
)
);
$this->set('videos', $this->Paginator->paginate());
index action of TournamentsController
$this->Tournament->recursive = -1;
$options['joins'] = array(
array('table' => 'rounds_tournaments',
'alias' => 'RoundsTournament',
'type' => 'inner',
'conditions' => array(
'Tournament.tournament_id = RoundsTournament.tournament_id'
)
),
array('table' => 'rounds',
'alias' => 'Round',
'type' => 'inner',
'conditions' => array(
'RoundsTournament.round_id = Round.round_id'
)
)
);
$this->set('tournaments', $this->Paginator->paginate());
I have code working search related models using the Search Plugin, but it forces me to break the structure of my model associations. As a result, my save and edit functions do not work properly.
Here is the structure of my data.
Model:
public $belongsTo = array(
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'MovieStarRecurrance' => array(
'className' => 'MovieStarRecurrance',
'foreignKey' => 'movie_star_recurrance_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'MovieStarType' => array(
'className' => 'MovieStarType',
'foreignKey' => 'movie_star_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
public $hasMany = array(
'MovieStarLine' => array(
'className' => 'MovieStarLine',
'foreignKey' => 'movie_star_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => 'status_date',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
I am searching and filtering within the related model Movie and the User that Movie belongsTo.
public $filterArgs = array(
'parent_user_id' => array('type' => 'like', 'field' => 'User.parent_user_id'),
'initials' => array('type' => 'value', 'field' => 'User.id'),
'trace' => array('type' => 'like', 'field' => 'MovieStar.trace'),
'movie' => array('type' => 'query', 'method' => 'orConditionsMovie'),
'star_type' => array('type' => 'value', 'field' => 'MovieStar.movie_star_type_id'),
'code' => array('type' => 'value', 'field' => 'MovieStar.code'),
'status' => array('type' => 'value', 'field' => 'MovieStarLine.movie_star_status_id'),
'open' => array('type' => 'value', 'field' => 'MovieStar.open'),
'from_date' => array('type' => 'query', 'method' => 'orConditionsFromDate'),
'end_date' => array('type' => 'query', 'method' => 'orConditionsEndDate'),
);
In order to access these models at the top level of my search, I unbind the Movie model belongsTo association and rebind it as hasOne. I do the same for MovieStarLine and MovieStarStatus.
Controller:
$this->MovieStar->recursive = 0;
$this->MovieStar->unbindModel( array(
'belongsTo' => array('Movie')
)
);
// MovieStarStatus to be top level json element
$this->MovieStar->bindModel( array(
'hasOne' => array(
'Movie' => array(
'foreignKey' => false,
'conditions' => array('Movie.id = MovieStar.movie_id'),
'fields' => array('Movie.id', 'Movie.movie_id', 'Movie.user_id', 'Movie.movie_mid', 'Movie.movie_dba')
),
'User' => array(
'foreignKey' => false,
'conditions' => array('Movie.user_id = User.id'),
'fields' => array('User.id', 'User.initials', 'User.user_first_name', 'User.user_last_name', 'User.name', 'User.parent_user_id', 'User.secondary_parent_user_id')
),
'MovieStarLine' => array(
'foreignKey' => false,
'conditions' => array('MovieStarLine.movie_star_id = MovieStar.id',
'MovieStarLine.id = (SELECT id FROM "public"."movie_star_lines" AS "MovieStarLine" WHERE movie_star_id = MovieStar.id ORDER BY status_date DESC NULLS LAST, id DESC LIMIT 1)' // Get only most recent line
),
'order' => array( 'MovieStarLine.status_date' => 'DESC NULLS LAST')
),
'MovieStarStatus' => array(
'foreignKey' => false,
'conditions' => array('MovieStarLine.movie_star_status_id = MovieStarStatus.id'),
),
),
));
$this->MovieStar->contain(array(
'Movie',
'MovieStarLine' => array('MovieStarStatus'),
'MovieStarType',
'MovieStarRecurrance',
'User',
'MovieStarStatus'
));
// This is where the search filter occurs
$this->Prg->commonProcess();
$this->paginate = array( 'conditions' => $this->MovieStar->parseCriteria($this->Prg->parsedParams()), 'limit' => 100);
$movieStars = $this->paginate();
$this->set(compact('movieStars'));
}
The problem is when I try to search by parent_user_id or initials, I get an ERROR: missing FROM-clause entry for table "User".
It seems like the dynamic binding doesn't work. I have to remove Movie from belongsTo
Model:
public $belongsTo = array(
//'Movie' => array(
// 'className' => 'Movie',
// 'foreignKey' => 'movie_id',
// 'conditions' => '',
// 'fields' => '',
// 'order' => ''
//),
'MovieStarRecurrance' => array(
'className' => 'MovieStarRecurrance',
'foreignKey' => 'movie_star_recurrance_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'MovieStarType' => array(
'className' => 'MovieStarType',
'foreignKey' => 'movie_star_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
and add hasOne for Movie and User for the search to work.
public $hasOne = array(
'Movie' => array(
'foreignKey' => false,
'conditions' => array('Movie.id = MovieStar.movie_id'),
'fields' => array('Movie.id', 'Movie.movie_id', 'Movie.user_id', 'Movie.movie_mid', 'Movie.movie_dba')
),
'User' => array(
'foreignKey' => false,
'conditions' => array('Movie.user_id = User.id'),
'fields' => array('User.id', 'User.initials', 'User.user_first_name', 'User.user_last_name', 'User.name', 'User.parent_user_id', 'User.secondary_parent_user_id')
),
'MovieStarLine' => array(
'foreignKey' => false,
'conditions' => array('MovieStarLine.movie_star_id = MovieStar.id',
'MovieStarLine.id = (SELECT id FROM "public"."movie_star_lines" AS "MovieStarLine" WHERE movie_star_id = MovieStar.id ORDER BY status_date DESC NULLS LAST, id DESC LIMIT 1)' // Get only most recent line
),
//'order' => array( 'MovieStarLine.status_date' => 'DESC NULLS LAST')
),
);
I can't do this though because it breaks all of my save and edit functionality. Does anyone know how to properly rebind the associations?
##################### UPDATE
I found a partial solution that seemingly gets me past the User model not showing up.
"Passing false as a second parameter of your Model::bindModel call. This will make your on-the-fly binding last the duration of the request." from this answer..
This might have fixed my bindings, still not sure because now I have an error with count and group by.
ERROR: column "MovieStarLine.status_date" must appear in the GROUP BY clause or be used in an aggregate
SQL Query: SELECT COUNT(*) AS "count"
$this->MovieStar->unbindModel( array(
'belongsTo' => array('Movie')
), false
);
// MovieStarStatus to be top level json element
$this->MovieStar->bindModel( array(
'hasOne' => array(
'Movie' => array(
'foreignKey' => false,
'conditions' => array('Movie.id = MovieStar.movie_id'),
'fields' => array('Movie.id', 'Movie.movie_id', 'Movie.user_id', 'Movie.movie_mid', 'Movie.movie_dba')
),
'User' => array(
'foreignKey' => false,
'conditions' => array('Movie.user_id = User.id'),
'fields' => array('User.id', 'User.initials', 'User.user_first_name', 'User.user_last_name', 'User.name', 'User.parent_user_id', 'User.secondary_parent_user_id')
),
'MovieStarLine' => array(
'foreignKey' => false,
'conditions' => array('MovieStarLine.movie_star_id = MovieStar.id',
'MovieStarLine.id = (SELECT id FROM "public"."movie_star_lines" AS "MovieStarLine" WHERE movie_star_id = MovieStar.id ORDER BY status_date DESC NULLS LAST, id DESC LIMIT 1)' // Get only most recent line
),
'order' => array( 'MovieStarLine.status_date' => 'DESC NULLS LAST')
),
'MovieStarStatus' => array(
'foreignKey' => false,
'conditions' => array('MovieStarLine.movie_star_status_id = MovieStarStatus.id'),
),
),
), false);
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.
edit - the code that uses contain.
$this->paginate = array(
'limit' => 20,
'order' => array(
'Individual.last_name' => 'asc',
'Individual.first_name' => 'asc'
),
'contain' => array(
'AccountsTrailersIndividual' => array(
'fields' => array('id', 'accounts_trailer_id', 'individual_id', 'account_holder_id'),
'AccountsTrailer' => array(
'fields' => array('id', 'account_id', 'trailer_id', 'charge_off_date', 'closed_date'),
'Balance' => array(
'fields' => array('id', 'accounts_trailer_id', 'balance')
),
'Account' => array(
'fields' => array('id', 'account_number'),
'conditions' => array('account_number' => $search)
),
),
'AccountHolder' => array(
'fields' => array('id', 'name')
)
),
),
'fields' => array('id', 'first_name', 'middle_initial', 'last_name', 'suffix'),
);
I am trying to contain my data to only pull what I need and it is not working. I have everything set up correctly I believe but it is giving me errors. What I have is in my appModel.php file
public $actsAs = array('Containable');
the errors I am getting are as follows:
Model "AccountsTrailersIndividual" is not associated with model "AccountsTrailer" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 339]
Model "AccountsTrailersIndividual" is not associated with model "AccountHolder" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 339]
I have checked the associations in the stated models and the associations are there.
for AccountsTrailersIndividual it looks like this
public $belongsTo = array(
'Individual' => array(
'className' => 'Individual',
'foreignKey' => 'individual_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'AccountsTrailer' => array(
'className' => 'AccountsTrailer',
'foreignKey' => 'accounts_trailer_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'AccountHolder' => array(
'className' => 'AccountHolder',
'foreignKey' => 'account_holder_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
for AccountsTrailer
public $hasAndBelongsToMany = array(
'Individual' => array(
'className' => 'Individual',
'joinTable' => 'accounts_trailers_individuals',
'foreignKey' => 'accounts_trailer_id',
'associationForeignKey' => 'individual_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
and for the AccountHolder
public $hasMany = array(
'AccountsTrailersIndividual' => array(
'className' => 'AccountsTrailersIndividual',
'foreignKey' => 'account_holder_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
I know that I must be missing something but I can't find it.
Any help is greatly appreciated.
<?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.