I have 3 tables, restaurants, orders, users. orders table has fields restaurant_id, status and user_id.
restaurant -> hasMany orders
orders belogsTo Restaurant
orders belongsTo users
I need to find only those restaurants that have order with status = 1, and at the same time need to fetch user's info.
So, I am making inner join with orders table,
$options['joins'] = array(
array('table' => 'orders',
'alias' => 'Order',
'type' => 'INNER',
'conditions' => array(
'Restaurant.id = Order.restaurant_id',
)
)
);
But how Can I also get users' information along with this, because according to cake documentation http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables, allowed params here are table, alias, type, conditions. Is there a some way that I can embed the sql query of getting user's info in the final query? Yes, the alternative will be to write the custom query, but is not there a way to do with cake.
Thanks
update
The best solution in this case was to write custom sql query.
Have you just tried an additional Join to get the Users as well?
Something like this:
$this->Restaurant->find('all', array(
'joins' => array(
array('table' => 'orders',
'alias' => 'Order',
'type' => 'INNER',
'conditions' => array(
'Restaurant.id = Order.restaurant_id',
'Order.status = 1'
)
),
array('table' => 'users',
'alias' => 'User',
'type' => 'RIGHT',
'conditions' => array(
'Order.user_id = User.id'
)
),
));
Note: What I usually find easiest (with complicated queries that you're having trouble figuring out) is to build the query 100% in SQL and get it working to your liking, then just re-build it in CakePHP.
List of orders with status 1 and with restaurant and user info:
$this->Restaurant->Order->find('all', array('conditions'=>array('Order.status'=>1), 'contain'=>array('Restaurant', 'User')))
I have two tables topics and posts. Relation: topics hasmany posts. In both table, there is a status field (Y, N) to moderate the content. In my page, I want to list all not moderated topics for which at least one post status is N or topic status itself is N. Is it possible to do with find function in cakephp2.0. Im using Containable behavior.
I need to apply pagination too.
This is one solution:
Search on the Post model for (Posts with N status) OR (Posts which belong to Topics with N status) and store the topic_id
Now search on the Topic model for topics with ID on the list
Something like this:
# TopicsController.php
$ids = $this->Topic->Post->find('list', array(
'fields' => array('Post.topic_id')
'conditions' => array(
'OR' => array(
'Post.status' => 'N',
'Topic.status' => 'N',
)
)
));
$this->paginate = array(
'conditions' => array('Topic.id' => (array)$ids),
'order' => array('Topic.created' => 'DESC')
);
$topics = $this->paginate('Topic');
Since you're searching on the Posts model, CakePHP will join the parent Topic data and you can filter by both statuses.
If i understand correctly you can use:
$conditions => array ('OR' => array ('Topic.status' => 'N', 'Post.status' => 'N'));
Well I haven't tested it but following should work
$this->recursive = -1; //necessary to use joins
$options['joins'] = array(
'table' => 'posts',
'alias' => 'Post',
'type' => 'left',
'conditions' => array('Topic.id = Post.topic_id', 'Post.status = N') //updated code
);
$options['group'] = array('Topic.id HAVING count('Topic.id') >= 1 OR Topic.status = N');
$this->Topic->find('all', $options);
Im probably missing something painfully obvious here. Im trying to join multiple tables together in Cake, but Im only getting the fields from the first table. Consider the following code..
$joins = array();
$joins[] = array(
'table' => 'products',
'alias' => 'Product',
'type' => 'LEFT',
'conditions' => array(
'Device.id = Product.device_id'
)
);
$joins[] = array(
'table' => 'pricepoints',
'alias' => 'Pricepoints',
'type' => 'LEFT',
'conditions' => array(
'Pricepoints.product_id = Product.id'
)
);
$all_products = $this->Device->find('all', array("joins" => $joins);
And this returns the following SQL
SELECT `Device`.`id`, `Device`.`manufacturer_id`, `Device`.`name`, `Device`.`type_id`, `Manufacturer`.`id`, `Manufacturer`.`name` FROM `devices` AS `Device` LEFT JOIN products AS `Product` ON (`Device`.`id` = `Product`.`device_id`) LEFT JOIN pricepoints AS `Pricepoints` ON (`Pricepoints`.`product_id` = `Product`.`id`) LEFT JOIN `manufacturers` AS `Manufacturer` ON (`Device`.`manufacturer_id` = `Manufacturer`.`id`)
ie. it only returns the fields from the parent Model ie. Device. How do I get it to select ALL fields from the join? Im presuming its to do with the way I have my Model relationships set up, but I think I have these set up correctly.
Anyone any advice?
you can specify the fields in the find query:
$all_products = $this->Device->find('all', array("fields" => array('Device.*','Product.*','Pricepoints.*')
"joins" => $joins
);
Hope this helps
Do your join by calling bindModel() instead of manually specifying the join. See the cookbook for the details on creating and destroying associations on the fly
Here is my complex (atleast i think it is complex) condition to find competitors from matches schedules and relating to events.
Now I have HTBTM relations with events_competitors table, where multiple events have multiple competitors users entries.
Here, I have used joins condition for joining and getting related events with competitors which works fine, but I also want to apply additional conditions, for is_black (check for black belt) and is_adult (check for adult person)
'EventCompetitor.is_black' => 0,
'EventCompetitor.is_adult' => 0,
Here I want only those competitors which have both conditions (is_black / is_adult) 0, means not eligible, but it does not applying the same, which is resulting in wrong competitors results.
Below is my whole find condition:
$matchdivisions = $this->Competitor->find("all" ,
array(
'conditions' =>
array(
'Competitor.status' => 1,
'Competitor.payment_completed' => 1,
'Competitor.weightgroup_id' => $current_matchsc['Matchschedule']['weightgroup_id'],
'Competitor.rank_id' => $current_matchsc['Matchschedule']['rank_id'],
'Competitor.degree_id' => $current_matchsc['Matchschedule']['degree_id'],
'Competitor.gender' => $current_matchsc['Matchschedule']['gender'],
),
'joins' =>
array(
array(
'table' => 'event_competitors',
'alias' => 'EventCompetitor',
'type' => 'left',
'conditions'=> array(
"AND" =>array(
'EventCompetitor.event_id = '.$current_matchsc['Event']['id'],
'EventCompetitor.is_black' => 0,
'EventCompetitor.is_adult' => 0,
)
),
)
),
'group' => 'Competitor.id'
)
);
Any idea, how can i get those things applied into JOIN conditions, so it is applied into results.
Thanks !
Below is SQL Dump for your ref:
SELECT Competitor.id, Competitor.first_name, Competitor.last_name, Competitor.parent_name, Competitor.gender, Competitor.date_of_birth, Competitor.email_address, Competitor.weight, Competitor.weightgroup_id, Competitor.height, Competitor.rank_id, Competitor.degree_id, Competitor.photo, Competitor.school_id, Competitor.years_of_experience, Competitor.age, Competitor.tournament_id, Competitor.total_registration_fees, Competitor.address1, Competitor.address2, Competitor.city, Competitor.zip_code, Competitor.country_id, Competitor.state_id, Competitor.phone_number, Competitor.mobile_number, Competitor.payment_mode, Competitor.email_sent, Competitor.payment_completed, Competitor.status, Competitor.created, Competitor.modified, Rank.id, Rank.name, Rank.status, Rank.created, Rank.modified, Tournament.id, Tournament.tournament_name, Tournament.tournament_type, Tournament.tournament_date, Tournament.venue_name, Tournament.address1, Tournament.address2, Tournament.city, Tournament.zip_code, Tournament.country_id, Tournament.state_id, Tournament.created, Tournament.modified, Country.id, Country.name, Country.status, Country.created, Country.modified, State.id, State.country_id, State.name, State.short_name, State.status, State.created, State.modified, Degree.id, Degree.rank_id, Degree.name, Degree.status, Degree.created, School.id, School.name, School.address1, School.address2, School.city, School.zip_code, School.country_id, School.state_id, School.phone_number, School.owner_name, School.establishment_date, School.total_competitors, School.status, School.created, School.modified, Transaction.id, Transaction.competitor_id, Transaction.noncompetitor_id, Transaction.created, Transaction.modified, Transaction.mc_gross, Transaction.address_status, Transaction.payer_id, Transaction.address_street, Transaction.payment_date, Transaction.payment_status, Transaction.address_zip, Transaction.first_name, Transaction.address_country_code, Transaction.address_name, Transaction.custom, Transaction.payer_status, Transaction.address_country, Transaction.address_city, Transaction.payer_email, Transaction.verify_sign, Transaction.txn_id, Transaction.payment_type, Transaction.last_name, Transaction.address_state, Transaction.receiver_email, Transaction.item_name, Transaction.mc_currency, Transaction.item_number, Transaction.residence_country, Transaction.transaction_subject, Transaction.payment_gross, Transaction.shipping, Transaction.test_ipn, Transaction.pending_reason FROM competitors AS Competitor left JOIN event_competitors AS EventCompetitor ON (EventCompetitor.event_id = 3 AND EventCompetitor.is_black = 0 AND EventCompetitor.is_adult = 0) LEFT JOIN ranks AS Rank ON (Competitor.rank_id = Rank.id) LEFT JOIN tournaments AS Tournament ON (Competitor.tournament_id = Tournament.id) LEFT JOIN countries AS Country ON (Competitor.country_id = Country.id) LEFT JOIN states AS State ON (Competitor.state_id = State.id) LEFT JOIN degrees AS Degree ON (Competitor.degree_id = Degree.id) LEFT JOIN schools AS School ON (Competitor.school_id = School.id) LEFT JOIN transactions AS Transaction ON (Transaction.competitor_id = Competitor.id) WHERE Competitor.status = 1 AND Competitor.payment_completed = 1 AND Competitor.weightgroup_id = 13 AND Competitor.rank_id = 11 AND Competitor.degree_id = '0' AND Competitor.gender = 'Female' GROUP BY Competitor.id
Here is the left join condition from above query for ref:
left JOIN event_competitors AS EventCompetitor ON (EventCompetitor.event_id = 3 AND EventCompetitor.is_black = 0 AND EventCompetitor.is_adult = 0)
You should be using the containable behavior for this. More at: http://book.cakephp.org/view/1323/Containable
Add it to your Competitor model.
var $actsAs = array('Containable');
Update your model relationships in your Competitor model to include the is_black and is_adult conditions:
var $hasAndBelongsToMany = array(
'Competitor' => array(
'className' => 'Competitor',
'joinTable' => 'event_competitors',
'alias' => 'EventCompetitor',
'conditions' => array(
'EventCompetitor.is_black' => 0,
'EventCompetitor.is_adult' => 0
)
)
);
3) To inject the event id, pass a contain array to your find operation:
$contain = array(
'EventCompetitor' => array(
'conditions' => array('EventCompetitor.event_id' => $current_matchsc['Event']['id'])
)
);
$matchdivisions = $this->Competitor->find("all" ,
array(
'contain' => $contain,
'conditions' => array(
'Competitor.status' => 1,
'Competitor.payment_completed' => 1,
'Competitor.weightgroup_id' => $current_matchsc['Matchschedule']['weightgroup_id'],
'Competitor.rank_id' => $current_matchsc['Matchschedule']['rank_id'],
'Competitor.degree_id' => $current_matchsc['Matchschedule']['degree_id'],
'Competitor.gender' => $current_matchsc['Matchschedule']['gender']
)
)
);
If is_black and is_adult are not always required for the relationship, you would want to move those conditions from the model and pass them in via the contain parameter of the find operation as needed.
I've completely confused myself now.
I have three tables: applicants, applicants_qualifications, and qualifications.
In the index view for applicants, I have a form with a dropdown of qualifications. The results should be a list of applicants with that qualification.
So I need the table of applicants on the index view to be based on a join, right?
If I add this to my applicants_controller:
$options['joins'] = array(
array(
'table' => 'applicants_qualifications',
'alias' => 'q',
'type' => 'left outer', // so that I get applicants with no qualifications too
'conditions' => array('Applicant.id = q.applicant_id',)
)
);
$this->Applicant->find('all', $options);
I get an additional sql statement at the bottom of the page, with the left outer join but the sql without the join is there too.
I think this line:
$this->set('applicants', $this->paginate());
calls the sql statement without the join.
Looks like I need to combine the join $options with the paginate call. Is that right?
If I use the search form, I get: Unknown column 'Qualifications.qualification_id' in 'where clause'
So the page is obviously not yet 'using' my sql with the join.
Sorry - I'm still a noob. Any help appreciated...
In order to set conditions, joins, etc for your model's pagination, you must do it as follows:
function admin_index() {
$this->Applicant->recursive = 0;
$this->paginate = array(
'Applicant' => array(
// 'conditions' => array('Applicant.approved' => true),
'joins' => array(
array(
'table' => 'applicants_qualifications',
'alias' => 'ApplicationsQualification',
'type' => 'left outer',
'conditions' => array('Applicant.id = ApplicationsQualification.applicant_id')
)
)
// 'order' => array('Applicant.joined DESC')
)
);
$this->set('applicants', $this->paginate());
}
I've commented out some sample keys that you can include later on - just to give you an idea of how it works.
Hope that helps!
You can use inner join instead of left outer join.For eg.
in cource controller
$cond = array(
array(
'table' => 'colleges',
'alias' => 'Colleges',
'type' => 'inner',
'conditions'=> array('Colleges.college_id = Courses.college_id')
)
) ;
$courses = $this->Courses->find('all',
array('joins' =>$cond,'conditions' => array("Courses.status ='1' AND Colleges.status='1' "),
'order'=>array('course_name'),
'fields' => array('course_id','course_name'),'group'=>'Courses.course_id'
)
);