CakePHP find() conditions for association entries - php

I have following command, getting me entries from my DB with associated hasMany entries:
$teasers = $this->Teaser->find('all', array(
'conditions' => array(
'Teaser.published' => 1
),
));
Now also the posts entries will be fetched, due the hasMany relation.
The output looks like this:
array(
0 => array(
'Teaser' => array(
'id' => '1',
'user_id' => '63',
'token' => '56d455bc20cfb56d455bc20d08',
// this goes on
),
'Post' => array(
0 => array(
'id' => '1',
'teaser_id' => '1',
'title' => 'blabla',
'text' => 'blabla',
'published' => 1,
// this goes on
)
)
)
)
Now my question is, how can I include something in the conditions, to filter also the Post-entries?
When I enter it like this, I get an error:
$teasers = $this->Teaser->find('all', array(
'conditions' => array(
'Teaser.published' => 1,
'Post.published' => 1
)
));

The reason you're getting an error is that your relationship is a hasMany so when Cake does the contain it is actually doing more than one query for your find. As a result you can't specify 'Post.published' => 1 in the conditions as the Post alias won't exist in the primary query (the one retrieving your teasers).
Instead you need to pass the extra condition as part of the contain:-
$teasers = $this->Teaser->find('all', [
'contain' => [
'Post' => [
'conditions' => [
'Post.published' => 1
]
]
],
'conditions' => [
'Teaser.published' => 1,
]
]);
This will let Cake know the conditions you want to use when building the query for the posts.

You should read the documentation for containable and retrieving data. These are basics.
$teasers = $this->Teaser->find('all', array(
'contain' => [
'Post' => [
'conditions' => [
'published' => 1
]
]
],
'conditions' => array(
'Teaser.published' => 1,
)
));

You can write condition in your model Teaser.php like
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'conditions' => array('Post.published' => 1)
)
);

Related

Cakephp: How to get data with specific fields on associated model

I'm using cakephp framework. I have two tables on my DB, courses and modules table. Those tables are related, courses has many modules. Basically I want to get data on courses and on modules but with specific fields. I want to get just the id and the title of the course and the id and the title of the module.
This code:
$courses_taken = $this->Course->find('all', array(
'conditions' => array('Course.id' => $course_id_list),
'fields' => array('Course.id', 'Course.title')
));
gives me:
array(
(int) 0 => array(
'Course' => array(
'id' => '1',
'title' => 'course 1'
),
'Module' => array(
(int) 0 => array(
'id' => '1',
'course_id' => '1',
'title' => 'module 1',
'image' => null,
'content' => 'Lorem ipsum',
'voice_over' => null,
'created' => '2014-09-03 14:02:25',
'modified' => '2014-09-03 14:02:28'
),
(int) 1 => array(
'id' => '2',
'course_id' => '1',
'title' => 'module 2',
'image' => null,
'content' => 'Sasdas',
'voice_over' => null,
'created' => null,
'modified' => null
)
)
),
(int) 1 => array(
'Course' => array(
'id' => '2',
'title' => 'course 2'
),
'Module' => array()
)
)
But I wanna select a specific field for module as well so I tried this code:
$courses_taken = $this->Course->find('all', array(
'conditions' => array('Course.id' => $course_id_list),
'fields' => array('Course.id', 'Course.title', 'Module.id', 'Module.title')
));
but gives me an error: Column not found: 1054 Unknown column 'Module.id' in 'field list'.
Please help me guys thanks.
Got the answer, To make sgt's answer work, $actsAs property should be added in Course model. Reference : http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
Either you use some behavior like Containable and your find() will look like this :
$courses_taken = $this->Course->find('all', array(
'conditions' => array('Course.id' => $course_id_list),
'fields' => array('Course.id', 'Course.title'),
'contain' => array(
'Module' => array(
'fields' => array('Module.id', 'Module.title'),
),
),
));
try this -
$courses_taken = $this->Course->find('all', array(
'conditions' => array('Course.id' => $course_id_list),
'fields' => array('Course.id', 'Course.title'),
'contain' => array('Module.id', 'Module.title')
));

CakePHP 2.x HABTM returning is no matching results

I have a problem with habtm with cakephp and i dont know how to solve yet. I've got three tables: setores, veiculos e setores_veiculos.
Setor model:
public $hasAndBelongsToMany = array(
'Veiculo' => array(
'className' => 'Veiculo',
'joinTable' => 'setores_veiculos',
'foreignKey' => 'setor_id',
'associationForeignKey' => 'veiculo_id',
'unique' => 'keepExisting'
)
);
Veiculo model:
public $hasAndBelongsToMany = array(
'Setor' => array(
'className' => 'Setor',
'joinTable' => 'setores_veiculos',
'foreignKey' => 'veiculo_id',
'associationForeignKey' => 'setor_id',
'unique' => 'keepExisting'
)
);
In my setores controller i have:
$options = array('conditions' => array('Setor.' . $this->Setor->primaryKey => $id));
$setores = $this->Setor->find('first', $options);
then in my debug:
array(
'Setor' => array(
'id' => (int) 5,
'nome' => '2º Batalhão',
'secretaria_id' => (int) 6,
'sigla' => '2º BPM',
'status_id' => (int) 1
),
'Veiculo' => array()
)
I can not understand why the Veiculo (vehicle) are not being listed. The insertion is working perfectly.
I expected:
'Veiculo' => array(
0 => array(
'id' => 1,
'name' => 'Corolla'
),
1 => array(
'id' => 2,
'name' => 'Hillux'
)
);
In my veiculos controller the setores are being listed. Any suggestion?
Thank you in advance and sorry about my english.
Looks fine to me. Try changing
'unique' => 'keepExisting'
to
'unique' => true
At present, I go by the simple rules as explained in the documentation that if I am using a simple link table, i.e. not storing any data in it, I use HABTM and unique set to true, otherwise I use hasMany through (The Join Model) and unique set to keepExisting so as not to lose extra stored data.
Post a data dump of setores_veiculos.

CakePHP - multiple hasAndBelongsToMany relationships not working

New to CakePHP etc and I'm massively confused with following problem so any guidance would be greatly appreciated. Essentially I'm having problems with hasAndBelongsToMany relationships and I don’t know if I’m going about it correctly as I’m doing most of the work inside one controller and one model.
I have a client’s pages, clients have many jobs (this works), clients belong to a client type (this works), clients also have many case studies (also works) and clients have jobs (fine).
Jobs have and belong to many disciplines – this doesn’t work, however, it appears as though the queries are being run (the SQL output in debug mode shows this, so I ran the SQL directly into MySQL - it queries fine) but Cake is not providing me the data into the clients array.
Here is the code for my Client Model and Controller.
Client.php (Model)
public $belongsTo = array(
'ClientType' => array(
'className' => 'ClientType',
'foreignKey' => 'type_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
public $hasMany = array(
'CaseStudy' => array(
'className' => 'CaseStudy',
'foreignKey' => 'main_contractor',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Job' => array(
'className' => 'Job',
'foreignKey' => 'client_id',
'conditions' => '',
'fields' => '',
'order' => 'Job.id desc'
)
);
ClientsController.php (Controller)
$options['joins'] = array(
array('table' => 'case_studies',
'alias' => 'CaseStudy',
'type' => 'LEFT',
'conditions' => array(
'CaseStudy.client_id = Client.id',
)
),
array('table' => 'jobs',
'alias' => 'Job',
'type' => 'LEFT',
'conditions' => array(
'Job.client_id = Client.id',
)
),
array('table' => 'sectors',
'alias' => 'Sector',
'type' => 'LEFT',
'conditions' => array(
'Job.sector_id = Sector.id',
)
),
array('table' => 'disciplines_jobs',
'alias' => 'DisciplinesJobs',
'type' => 'LEFT',
'conditions' => array(
'Job.id = DisciplinesJobs.job_id',
)
),
array(
'table' => 'disciplines',
'alias' => 'Discipline',
'type' => 'LEFT',
'conditions' => array(
'DisciplinesJobs.discipline_id = Discipline.id'
)
)
);
$options['conditions'] = array('Client.id' => $client_id);
$clients = $this->Client->find('all', $options);
Output of $clients array above:
array(
(int) 0 => array(
'Client' => array(
'id' => '47',
'type_id' => '2',
'name' => 'Balfour Beatty',
'logo' => '1361786198_thumbnail_balfour beatty.jpg',
'website_url' => 'http://www.google.com',
'date_added' => '2013-02-25 10:56:38',
'date_modified' => '2013-02-25 10:56:38'
),
'ClientType' => array(
'id' => '2',
'name' => 'Constructors'
),
'CaseStudy' => array(
(int) 0 => array(
'id' => '23',
'client_id' => '47',
'sector_id' => '1',
'name' => 'Shoreham Academy',
'header_image' => '1365088787_thumbnail_1365088787_header copy.jpg',
'main_contractor' => '47',
'architect' => 'Architecture PLB',
'project_value' => '565000',
'scope_of_works' => '<table></table>',
'text' => '<p><</p>',
'type' => 'flooring',
'date_added' => '2013-04-04 11:19:47',
'date_modified' => '2013-04-04 11:19:47'
)
),
'Job' => array(
(int) 0 => array(
'id' => '1',
'client_id' => '47',
'sector_id' => '2',
'project' => 'Shoreham Academy (Project not case study)',
'date' => '2012-10-19',
'cost' => '£416k',
'quantity_of_flooring' => '7000m',
'date_added' => '2013-08-06 21:46:59',
'date_modified' => '2013-08-06 21:47:01'
)
)
)
Notice the above $clients array doesn’t have any disciplines data from the discipline_jobs table but the SQL output is which runs successfully:
SELECT `Client`.`id`, `Client`.`type_id`, `Client`.`name`, `Client`.`logo`, `Client`.`website_url`, `Client`.`date_added`, `Client`.`date_modified`, `ClientType`.`id`, `ClientType`.`name`
FROM `ar_flooring`.`clients` AS `Client`
LEFT JOIN `ar_flooring`.`case_studies` AS `CaseStudy` ON (`CaseStudy`.`client_id` = `Client`.`id`)
LEFT JOIN `ar_flooring`.`jobs` AS `Job` ON (`Job`.`client_id` = `Client`.`id`)
LEFT JOIN `ar_flooring`.`sectors` AS `Sector` ON (`Job`.`sector_id` = `Sector`.`id`)
LEFT JOIN `ar_flooring`.`disciplines_jobs` AS `DisciplinesJobs` ON (`Job`.`id` = `DisciplinesJobs`.`job_id`) LEFT JOIN `ar_flooring`.`disciplines` AS `Discipline` ON (`DisciplinesJobs`.`discipline_id` = `Discipline`.`id`)
LEFT JOIN `ar_flooring`.`client_types` AS `ClientType` ON (`Client`.`type_id` = `ClientType`.`id`)
WHERE `Client`.`id` = 47
I don’t have a discipline model or controller. I don’t have a jobs model or controller because I’m trying to do everything with the clients model and controller – is this correct?
Does anyone know why this is happening?
Hope this makes sense.
Cheers!
It appears that you want to run a
$this->Client->find('all')
at your ClientsController.
In that find all, you want to retrieve a list of Clients, the ClientType each Client belongsTo, the CaseStudy list each Client has, the Job list each Client has, and the Discipline each Job hasAndBelongsTo.
First, as a practitioner of CakePHP, I almost always avoid using the habtm relationship.
The reason is that it is almost always the case that I have extra fields in the join table. In this case, jobs_disciplines is likely to have more than just job_id and discipline_id. Maybe it will also have another field called status.
What I would do is that I will bake the JobsDiscipline model and the Discipline Model.
JobsDiscipline will belong to both Discipline and Job.
Both Discipline and Job will have many JobsDiscipline.
After this, the query to construct is basically just
$this->Client->find('all', array(
'contain' => array('ClientType', 'CaseStudy', 'Job' => array('JobsDiscipline'=>array('Discipline')))
));
This should work even if you set the recursive at your AppModel to be -1.
If this does not work, let me know again.

Using Containable behavior to filter results in Cakephp 2.2.4

I'm using containable behavior and the result of my find('all') is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
(int) 0 => array(
'lead_id' => '6',
'Estimate' => array(
(int) 0 => array(
'TOT_count' => '2'
)
)
)
)
)
)
I need to to count how many estimates there are in the lead.
The total (2) is correct, but i see nested 'Estimated' array, why ?
The result i would like to get is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
'TOT_count' => '2'
)
)
)
This is the find:
$options = array(
'contain' => array(
'User',
'Estimate' => array(
'fields' => 'COUNT(*) AS TOT_count'
)
),
'conditions' => array('Lead.id' => 6),
'fields' => 'User.*',
'limit' => 1
);
debug($this->Lead->find('all', $options));
How can i do it?
Thanks!
When you use a "custom" AS statement, in your case TOT_count, Cake will always put this in a result key called 0. You can avoid this by defining TOT_count as a virtualField in your model. That way it will be nested directly under the model name in your resultset.
Secondly, the lead_id is forcedly retrieved, because it is "needed" to make the join with the Lead model. It can not properly retrieve all the data without that piece of information there.

CakePHP: joins inside contain

As the title says, I'm having troubles with joins in my find-query, with errors appearing like:
preg_match() expects parameter 2 to be string, array given [CORE/cake/libs/model/behaviors/containable.php, line 301]
I've tried adding joins to the array over there, but it didn't change anything.
These are the options I'm passing to the find method.
$options = array(
'contain' => array(
'Answer' => array(
'conditions' => array('Answer.type' => 'answer'),
'joins' => array(
$this->votesJoin()
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'joins' => array(
$this->votesJoin()
)
)
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'joins' => array(
$this->votesJoin()
)
),
'User',
'Tag' => array()
),
'joins' => array(
$this->votesJoin()
),
'conditions' => array(
'Question.id' => $id
)
);
return $this->find('first', $options);
with votesJoin() returning the following array.
(
[table] => (SELECT Vote.node_id, SUM(value) as total FROM votes AS `Vote` WHERE 1 = 1 GROUP BY `Vote`.`node_id` )
[alias] => Vote
[conditions] => Vote.node_id = Question.id
)
What I'm trying to do:
Each user can up/downvote a node (question/answer/comment). With the join I'm trying to add the sum of those votes.
database http://github.com/navale/QA/wiki/img/datamodel.png
You should use "joins" only for things that can't be done with Cake model relationship and Containable. I don't know the details of your database, but I think the find operation can be simplified. Why don't you post the schema for these tables on here?
try this:
$options = array(
'contain' => array(
'Answer' => array(
'conditions' => array('Answer.type' => 'answer'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
)
)
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
)
),
'User',
'Tag' => array()
),
'conditions' => array(
'Question.id' => $id
)
);
You get the Vote sum value for each answer, comment, and comment for answer. (You might need to add 'hasMany' Vote in the Node model if you haven't done that yet)
If instead you want to get one single total sum of Vote for the question, then I'd suggest:
get the list of the answers and comments of the question:
$lvl1 = find('list','fields'=>array('id'),'conditions'=>array('Node.parent_id'=>$id))
then get list of the comments of the answers
$lvl2 = find('list','fields'=>array('id'),'conditions'=>array('Node.parent_id'=>$lvl1))
then just combine the 2 array then do a sum over that.

Categories