Problem with CakePHP model joins, missing fields from joined table. - cakephp

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

Related

Getting data by search filter from associated models

i have an question regarding search filter in cakephp. Without complicating my question, below are the structure of what i want....
1) I have a projects table.
2) another one is project_funder_names table which is associated with projects table. project_id is in project_funder_names table. i have made project_funder_names table because i need multiple funder names for a single project, thats why i have made this table.
3) now the main point is i want if i search multiple funders in search filter which is coming in dropdown with checkbox, i will get project details according to these values. so how it would happen.
here is my cakephp find all query....
$project_info = $this->Project->find('all', array(
'conditions' =>
array(
'Project.status' => 1,
'OR' => array($search)),
'fields' => array('id', 'title', 'short_description', 'budget_allocation', 'currency', 'total_comments', 'published_date'),
'contain' => array(
'ProjectFunderName' => array(
'conditions' => array($search_funder)),
'Currency' => array('currency_symbol'),
'ProjectBookmark' => array('project_id', 'user_id')
)
)
);
problem is in $search_funder.
please help me for this.. thanks.
Looks like you need to search results based on associated models. One drawback of using containable behavior is if you're trying to assign a condition to an associated model, the main model will be retrieved no matter what.
In situations where you'd want to retrieve the main as well as the associated records based on a condition for the associated model, I'd suggest you to use join.
$joins = array(
array('table' => 'project_funder_names',
'alias' => 'ProjectFunderName',
'type' => 'LEFT',
'conditions' => array('ProjectFunderName.project_id = Project.id')
),
array('table' => 'currencies',
'alias' => 'Currency',
'type' => 'LEFT',
// It's unclear how currencies is associated with the other tables. Use appropriate table join condition here
),
array('table' => 'project_bookmarks',
'alias' => 'ProjectBookmark',
'type' => 'LEFT',
'conditions' => array('ProjectBookmark.project_id = Project.id')
)
)
);
$project_info = $this->Project->find('all',
array(
"joins" => $joins,
"fields" => array(.........) // Specify all your desired fields here
"conditions" => array(....) // Specify all conditions for Project, ProjectFunderName models.
)
);
Hope this helps.
Peace! xD

Cakephp order by count of join results including not existing entries

my problem is, that i want to count the votes for a comment of an article.
So users can upvote good comments of an article and i want to list the comments with the most votes first. The approach that i'm following now is working, with the limitation, that only votes are listed, that already have been voted. those, that are not listed in the join table (comments_users) are ignored.
to make it a bit more clear my tables are users, comments and the HABTM join table comments_users (alias votes)
my current approach is:
public function commentsOfArticle($articleId){
$options['group'] = array('Comment.articleId');
$options['conditions'][] = array('Comment.article_id' => $articleId);
$options['joins'][] = array('table' => 'comments_users',
'alias' => 'Votes',
'type' => 'inner',
'conditions' => array(
'Votes.comment_id = Comment.id'
));
$options['fields'] = array('Comment.*','COUNT(Votes.user_id) AS votes');
$options['contain'] = array(.......);
$options[ 'order'] = array('votes DESC');
return $this->find('all',$options);
}
i think the key line is
$options['fields'] = array('Comment.*','COUNT(Votes.user_id) AS votes');
is it possible to receive those comments, that have no entry in the votes table at the end of my results, just with votes=0 ?
Try changing the JOIN from inner to left
$options['joins'][] = array('table' => 'comments_users',
'alias' => 'Votes',
'type' => 'LEFT',
'conditions' => array(
'Votes.comment_id = Comment.id'
));

inner join with containable cakephp

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')))

cakephp - difficulty to access a specific information in my controller

I have these tables and the relationships between them:
1 project hasmany configurationcontext 1 issuetype hasmany
optionconfiguration hasmany configurationcontext hasmany
optionconfiguration (does not exist intermediate table)
My goal is to get information like this query.
SELECT IT.id, IT.pname
FROM configurationcontext CC
LEFT OUTER JOIN optionconfiguration OC ON OC.fieldconfig = CC.fieldconfigscheme
LEFT OUTER JOIN issuetype IT ON IT.id = OC.optionid
WHERE CC.project = 10000
my doubts:
- which the controller to use to create a function that return me this information?
- How do I get this information?
thanks :)
Assuming I have your model names correct, this should do the trick:
$this->ConfigurationContext->find('all', array(
'joins' => array(
array(
'table' => 'optionconfiguration',
'alias' => 'OptionConfiguration',
'type' => 'LEFT OUTER JOIN',
'conditions' => array(
'OptionConfiguration.fieldconfig = ConfigurationContext.fieldconfigscheme'
)
),
array(
'table' => 'issuetype',
'alias' => 'IssueType',
'type' => 'LEFT OUTER JOIN',
'conditions' => array(
'IssueType.id = OptionConfiguration.optionid'
)
)
),
'conditions' => array(
'ConfigurationContext.project' => 10000
),
'fields' => array(
'IssueType.id',
'IssueType.pname'
)
));
I haven't tried type "LEFT OUTER JOIN" but I don't see why it wouldn't work, maybe look into using containable to avoid using joins if you can.

cakephp: using a join for search results

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'
)
);

Resources