CakePHP - Find conditions for related model - cakephp

I have SubjectGroup, which hasMany Subject.
class SubjectGroup extends AppModel {
public $hasMany = array(
'Subject' => array('order' => 'Subject.name')
);
}
class Subject extends AppModel {
public $belongsTo = array('SubjectGroup');
}
I want to get all SubjectGroups, and recursively retrieve their Subjects, but only the Subjects that have a status of 2. I can't figure out how to do this.
$subjectGroups = $this->SubjectGroup->find('all', array(
'conditions' => array('Subject.status !=' => 2),
'order' => 'SubjectGroup.name'
));
Warning (512): SQL Error: 1054: Unknown column 'Subject.status' in 'where clause'
Note: I have read that I can add a conditions array to the model relationship definition, but I don't want the relationship to always use the condition. Sometimes I will want to just retrieve the SubjectGroups and Subjects with status 2, and sometimes the SubjectGroups with all Subjects, regardless of their status.
PROGRESS
With some help from Ross, I now am trying to use the Containable behaviour. I have this so far:
$this->SubjectGroup->find('all', array(
'contain' => 'Subject.status != 2',
'order' => 'SubjectGroup.name'
));
There are no errors, but it returns all Subjects, even the ones with status = 2.

What you're doing is asking Cake to look for the field status in the SubjectGroup table. It doesn't exist.
What you really want to do is use containable behaviour, and access the status field this way.
Try this:
$this->SubjectGroup->Behaviors->attach('Containable');
$subjectGroups = $this->SubjectGroup->find('all', array(
'contain'=>array('Subject'=>array(
'conditions' => array('Subject.status !=' => 2))
),
'order' => 'SubjectGroup.name'
));

Related

cakephp group on assosiated model / table

Short background: I have orders that contains products called 'Komplexes'. Komplexes have different sizes (height and width) if there are multiple Komplexes with the same measures in an order they have to be grouped and a counter must be added to create jobs for the workers.
My Models:
class Order extends AppModel {
public $hasMany = 'Komplex';
public $belongsTo = array(
'Customer' => array(
'counterCache' => true
)
);
}
class Komplex extends AppModel {
public $belongsTo = array(
'Order' => array(
'counterCache' => true
)
);
...<validation and calculations>
}
In my OrdersController I'm starting with
public function orderproductionjob($id = NULL) {
if (!$id) {
throw new NotFoundException(__('Invalid ID'));
}
$order = $this->Order->find('all', array(
'conditions' => array('Order.id =' => $id),
'group' => array('Komplex.height')
));
die(debug($order));
This gives me a database error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Komplex.height' in 'group statement'
The same 'find' without the 'group' gives me the right result (exept the grouping ;-)
So it's pretty obvious that I'm doing something wrong with the group. I could find examples for assosiations and examples for grouping on the web and in the cookbook but this combination wasn't mentioned or likely I haven't found it. As this is my first project with cakephp I'm hoping, that sombody with more experience can help me out.
What I'm trying to archive in SQL:
SELECT orders.id, orders.name, komplexes.width, komplexes.height, count(komplexes.id) as Count
FROM orders, komplexes
WHERE orders.id = 1 AND komplexes.order_id = orders.id
group by komplexes.width, komplexes.height;
Try changing your code to Group on the Komplex model.
$komplex = $this->Order->Komplex->find('all', array(
'fields' => array('Komplex.height', 'Komplex.width', 'Count(*) as `Count`')
'conditions' => array('Komplex.order_id =' => $id),
'group' => array('Komplex.height', 'Komplex.width')
));
FYI
Your SQL statement works because you are guaranteed to only have 1 orders row. It can and most likely will return wrong results if you try to join to more than 1 orders row.
You need to be careful using SQL reserved words in your statement. In your case Count as the aliased column name. You may want to change that. Please note that my code sample has COUNT surrounded by backticks.

AND / OR conditions cakephp FIND for has many association

I have a model Post that has many association with the model Comment.
Post has a primary key post_id which is Comment s foreign key.
Both of these have a visible column.
I have a working query on Post.visible options, and I need to add the AND to find all Posts that have one of Post.visible values.
For these posts I need all Comments that have a Comment.visible value = 1.
My code:
$conditions = array(
"OR" => array(
"Post.visible" => array(
1,
2,
3,
4
),
),
"AND" => array (
"Comment.visible" => 1
)
);
$result = $this->Post->find('all', array(
'order' => 'Post.created DESC',
'conditions' => $conditions
));
The result without the AND is OK (but I get also the Comments with visible = 0).
When I put the condition "Comment.visible" => 1 in the has manyassociation, it works well (but I can not do this, because I need to get the Comment with visibility 0 elsewhere).
With the and it shows this Error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Comment.visible' in 'where clause'
When I dump the SQL, the comments table is not even matched in the SELECT clause (nor in the LEFT JOIN).
You can limit another model's results using CakePHP's Containable Behavior with something like this (this should work, but feel free to tweak per your needs):
//Post model
public $recursive = -1;
public $actsAs = array('Containable');
public function getPosts() {
$posts = $this->find('all',
array(
'conditions' => array(
'Post.visible' => 1
),
'contain' => array(
'Comment' => array(
'conditions' => array('Comment.visible' => 1)
)
)
)
);
return $posts;
}
Or, you can set up your association to only ever pull comments that are visible (even WITH this way, I still recommend using 'contain' like above - you just wouldn't need to specify the condition each time):
//Post model
public $hasMany = array(
'Comment' => array(
'conditions' => array('Comment.visible' => 1)
)
);

Cake PHP foreignkey issues

So I am using cakephp and I am a little new to this and I am facing certain issues.
1) I have two tables, report and issues.
cakephp:
report{id, type, details}
issue{id,report_id, details}
So now I am trying to get the report id in issues table. I have defined my hasmany and belongsto relationships as follows:
class Report extends AppModel {
var $name = 'Report';
var $hasMany = array(
'AtneIssue' => array(
'className' => 'Issue',
'foreignKey' => 'report_id',
'dependent' => true,
)
);
}
class Issue extends AppModel {
var $name = 'Issue';
var $belongsTo = array(
'Report' => array(
'className' => 'Report',
'foreignKey' => 'report_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
But this results in a sql error and the data not being saved to the table. I have set index to report_id to get id from Report.
Data is getting saved to reports but not to issues table.
Can someone tell me how to go about this?
Thanks in advance.
The first letter is replace by number here. dunno why... I figured how to post data But now I am not able to get the ID of the report and the data is getting corrupted like below:
Query: INSERT INTO `atne_issues` (`status`, `issue_owner`, `issue_reason`, `problem`) VALUES ('2nhold', '2ricsson', '2IQ - IP address incorrect', '2sdfasdf')

CakePHP $hasMany not pulling the data from the $belongsTo model. Join is not created

I have two tables: internet_access_codes and radacct.
The internet_access_codes hasMany radacct records.
The join is internet_access_codes.code = radacct.username AND internet_access_codes.fk_ship_id = radacct.fk_ship_id
I created 2 models and wanted to use $hasMany and $belongsTo respectively so that the related radacct records would be pulled when getting and internet_access_codes record.
Here's the code:
class InternetAccessCode extends AppModel{
var $name = 'InternetAccessCode';
var $hasMany = array(
'Radacct' => array(
'className' => 'Radacct',
'foreignKey'=> false,
'conditions'=> array(
'InternetAccessCode.code = Radacct.username',
'InternetAccessCode.fk_ship_id = Radacct.fk_ship_id'
),
)
);
}
class Radacct extends AppModel{
var $name = 'Radacct';
var $useTable = 'radacct';
var $belongsTo = array(
'InternetAccessCode' => array(
'className' => 'InternetAccessCode',
'foreignKey' => false,
'conditions'=> array(
'InternetAccessCode.code = Radacct.username',
'InternetAccessCode.fk_ship_id = Radacct.fk_ship_id'
)
),
);
}
When I find() a record from internet_access_codes I expect it to give me all the relevant radacct records as well. However I got an error because it didnt do the join.
Here's the outcome and error:
Array
(
[InternetAccessCode] => Array
(
[id] => 1
[code] => 1344444440
[bandwidth_allowed] => 20000
[time_allowed] => 30000
[expires_at] => 31536000
[cost_price] => 0.00
[sell_price] => 0.00
[enabled] => 1
[deleted] => 0
[deleted_date] =>
[fk_ship_id] => 1
[downloaded_at] => 2011-09-10 22:18:14
)
[Radacct] => Array
(
)
)
Error: Warning (512): SQL Error: 1054: Unknown column
'InternetAccessCode.code' in 'where clause'
[CORE/cake/libs/model/datasources/dbo_source.php, line 684]
Query: SELECT Radacct.id, Radacct.fk_ship_id,
Radacct.radacctid, Radacct.acctsessionid,
Radacct.acctuniqueid, Radacct.username, Radacct.groupname,
Radacct.realm, Radacct.nasipaddress, Radacct.nasportid,
Radacct.nasporttype, Radacct.acctstarttime,
Radacct.acctstoptime, Radacct.acctsessiontime,
Radacct.acctauthentic, Radacct.connectinfo_start,
Radacct.connectinfo_stop, Radacct.acctinputoctets,
Radacct.acctoutputoctets, Radacct.calledstationid,
Radacct.callingstationid, Radacct.acctterminatecause,
Radacct.servicetype, Radacct.framedprotocol,
Radacct.framedipaddress, Radacct.acctstartdelay,
Radacct.acctstopdelay, Radacct.xascendsessionsvrkey FROM
radacct AS Radacct WHERE InternetAccessCode.code =
Radacct.username AND InternetAccessCode.fk_ship_id =
Radacct.fk_ship_id AND Radacct.deleted <> 1
In the app_model I also added the containable behaviour just in case but it made no difference.
Sadly cakephp doesn't work too well with the associations with foreign key =false and conditions. Conditions in associations are expected to be things like Model.field = 1 or any other constant.
The has many association first find all the current model results, then it finds all the other model results that have the current model results foreignKey... meaning it does 2 queries. If you put the conditions it will try to do it anyway but since it didn't do a join your query will not find a column of another table.
Solution
use joins instead of contain or association to force the join you can find more here
an example of how to use join
$options['joins'] = array(
array(
'table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
));
$this->Model->find('all', $options);
Possible solution #2
BelongsTo perform automatic joins (not always) and you could do a find from radaact, the bad thing of this solution, is that it will list all radacct and put its internetAccesCode asociated instead of the internetAccesCode and all the radaact associated.... The join solution will give you something similar though...
You will need to do a nice foreach that organizes your results :S it won't be to hard though....
Hope this solves your problem.

post habtm postlover : how to order posts by number of postlovers?

please help me, i'm really struggling with this...
Authors can write post, and authors can love other authors' posts...
So posts belong to author (when authors write them), but posts habtm
authors (when authors love them).
For example i'd like to get posts ordered by number of postlovers and
created in the last 24 hours. Here's my models and join table:
TABLE: lovedposts_postlovers
id: INT
lovedpost_id: INT
postlover_id: INT
POST MODEL
<?php
class Post extends AppModel {
var $name = 'Post';
var $belongsTo = 'Author';
var $hasAndBelongsToMany = array(
'Postlover' =>
array(
'className' => 'Author',
'joinTable' => 'lovedposts_postlovers',
'foreignKey' => 'lovedpost_id',
'associationForeignKey' => 'postlover_id',
'unique' => true
)
);
var $displayField = 'title';
}
?>
AUTHOR MODEL
<?php
class Author extends AppModel {
var $name = 'Author';
var $hasMany = 'Post';
var $hasAndBelongsToMany = array(
'Lovedpost' =>
array(
'className' => 'Post',
'joinTable' => 'lovedposts_postlovers',
'foreignKey' => 'postlover_id',
'associationForeignKey' => 'lovedpost_id',
'unique' => true
)
);
var $displayField = 'username';
}
?>
Your best option is to query on the joinModel. Usually that would be:
$this->Author->AuthorsLovedpost->find(...);
But since you're not sticking to the Cake naming conventions for the table that may or may not be different. The joinModel is automatically created BTW, but you can also explicitly specify it in the HABTM declaration.
var $hasAndBelongsToMany = array(
'Postlover' => array(
...,
'with' => 'joinModelName'
)
);
For the find options you can do whatever you need, 'group' => 'post_id' and 'order' => 'COUNT(post_id)' or something to that extend. What you're looking for is getting the right set of 'post_ids' back.
Since from the point of view of the joinModel the Author and Post models are both belongsTo relationships, Cake will find related results accordingly and you can use the usual 'contain' options etc to filter results.
Hope that helps.
I think you should take a step back and try to read the documentation (book.cakephp.org). Try to make a demo using their examples.
lovedposts_postlovers table is very confusing and maybe should be called something else, maybe authors_posts or even favorites. well, it can be anything as long as you specify it in 'joinTable'.
lovedposts_postlovers should have the fields author_id, post_id
//POST MODEL
var $hasAndBelongsToMany = array(
'Author' =>
array(
'className' => 'Author',
'joinTable' => 'lovedposts_postlovers',
'foreignKey' => 'author_id',
'associationForeignKey' => 'post_id',
'unique' => true
)
);
For example i'd like to get posts ordered by number of postlovers and created in the last 24 hours. Here's my models and join table:
$this->Post->LovedPosts->find('all', array('fields'=>array('Post.title', 'count(LovedPosts.*) as favorited'), 'group'=>'LovedPosts.post_id');
Basically you want to do a select count query and group by the post_id and this code should get you on the right track. Note: I didn't test this code. You also need an order clause in that find operation but I will leave that to you.

Resources