Pagination using joining multiple models - mysql

Each exam has one syllabus, each syllabus has one exam. So, I did this in the Exam model:
public $hasOne = 'Syllabuses'; //table: syllabuses, model: Syllabuses
From UsersController I did this:
public $uses = array('Setting', 'Exam', 'Syllabuses');
And in a method in UsersController I wanted to call paginate:
$options = array(
'fields' => array('Exam.id', 'Exam.name', 'Syllabuses.id', 'Syllabuses.name', 'Syllabuses.syllabus', 'Syllabuses.last_updated'),
'joins' => array(
'table' => 'syllabuses',
'conditions' => array('Exam.id = Syllabuses.exam_id')
)
);
$this->paginate = $options;
$this->set('syllabuses', $this->Paginator->paginate('Syllabuses'));
exams table:
---+------+
id | name |
---+------+
and syllabuses table:
---+---------+------+----------+--------------+
id | exam_id | name | syllabus | last_updated |
---+---------+------+----------+--------------+
So, I got some error. Like this:
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'syllabuses Array LEFT JOIN oes.syllabuses AS Syllabuses ON (Syllabuses.`' at line 1
And my SQL that CakePHP prepared is:
SELECT `Exam`.`id`, `Exam`.`name`, `Syllabuses`.`id`, `Syllabuses`.`name`, `Syllabuses`.`syllabus`, `Syllabuses`.`last_updated`
FROM `oes`.`exams` AS `Exam` syllabuses Array
LEFT JOIN `oes`.`syllabuses` AS `Syllabuses` ON (`Syllabuses`.`exam_id` = `Exam`.`id`)
WHERE 1 = 1 LIMIT 20
But what I want is something like the query bellow. I have tested it in mysql:
SELECT `Exam`.`id` AS eid, `Exam`.`name` AS ename, `Syllabuses`.`id` AS sid, `Syllabuses`.`name` AS sname, `Syllabuses`.`syllabus` , `Syllabuses`.`last_updated`
FROM `oes`.`syllabuses` AS `Syllabuses` , exams AS Exam
WHERE Exam.id = Syllabuses.exam_id
ORDER BY Exam.id
LIMIT 20
Now anybody please help me achieve this. What kind of change can make CakePHP to prepare query like that(what I've tasted) to make my Pagination done.

Ok, I think this can be helpful for many programmers. That's why I want to share what I did finally:
$options = array(
'fields' => array(
'Exam.id',
'Exam.name',
'Syllabuses.id',
'Syllabuses.name',
'Syllabuses.exam_id',
'Syllabuses.syllabus',
'Syllabuses.last_updated'
),
'recursive' => 0,
'conditions' => array('Exam.id = Syllabuses.exam_id'),
'limit' => 3
);
$this->paginate = $options;
$syllabuses = $this->Paginator->paginate('Exam');

Related

I do not understand joining tables

I'm using Cake version 2.5.4
I have two tables.
A call arbols which consists of the following fields:
id (int 11)
nombre (varchar (255)
especie:id (int 11)
The second table called fotos consists of the following fields:
id (int 11)
foto (varchar 255)
foto_dir (varchar 255)
arbol_id (int 11)
Although the Arbol model is related to the Especie model,
I leave it aside to the latter because it is not a reason for consultation.
The Arbol Model has a hasMany relationship with the Foto model.
In the Arbol model I have the following:
public $hasMany = array(
'Foto'=> array(
'className' => 'Foto',
'foreignKey' => 'arbol_id',
'dependent' => true
)
);
In the Foto model I have the following:
public $belongsTo = array(
'Arbol'=> array(
'className'=>'Arbol',
'foreign_key'=>'arbol_id'
)
);
Now, inside ArbolsController in public function view ($ id = null)
I want to do the following SQL query:
SELECT * FROM arboles as a join fotos as f on a.id=f.arbol_id
So I return all the photos related to an id of a particular tree passed as parameter in view
If this query is done using MySQL
$registros=mysqli_query($conexion," select * from arboles as a join fotos as f on a.id=f.arbol_id")
it works.
But if I want to do it using the query method in such ways:
$registros = $this->Arbol->query("select * from arboles as a INNER JOIN fotos as f ON a.id=f.arbol_id");
$registros = $this->Arbol->query("select * from arboles as a INNER JOIN fotos as f ON a.id=f.arbol_id");
It does not work
Reading the Cookbook I see there is a way to make joins.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
I dont understand her
I would appreciate it if you can explain it to me.
From already thank you very much!
You shouldn't be using the query method directly if you can avoid it.
What you can do is using a standard find, joining your tables with containable (or linkable).
Something like this should work:
$registros = $this->Arbol->find('all', array(
'contain' => 'Foto'
));
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
There is another way by you can join the tables in cakephp i.e customized joins
Create an array of tables whom you want to join, such as
$joins = array(
array(
'table' => 'fotos',//Table name
'alias' => 'Foto', //Model name
'type' => 'INNER', // type of join
'conditions' => array(
'Arbol.id = Foto.arbol_id'
) //Condition for join
)
);
$this->Arbol->find('all', array(
'joins' => $joins,
'conditions'=> array(Arbol.id => $id),
'fields' => array()
))
This will return all the photos information related to an id

hasMany relation without table having id column

I am using CakePHP 2.5. I am having following table
CompanyMaster:
company_master_id [PK]
Name and other columns
CompanySignatoryDetails: (has many owners for single company)
company_signatory_details_id [PK]
company_master_id [FK]
Name and other columns
Now, I want to get company details with all owners of that company. Here is what I have tried.
$this->CompanyMaster->bindModel(
array(
'hasMany' => array(
'CompanySignatoryDetails' => array(
'className' => 'CompanySignatoryDetails',
'foreignKey' => false,
'conditions' => array(
'CompanySignatoryDetails.company_master_id = CompanyMaster.company_master_id'
),
),
)
)
);
$this->CompanyMaster->recursive = 2;
$company = $this->CompanyMaster->find('first', array(
'fields' => array('CompanyMaster.*'),
'conditions' => $conditions, //company id in condition
));
I am getting following error:
Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'CompanyMaster.id' in 'field list'
SQL Query:
SELECT `CompanyMaster`.*, `CompanyMaster`.`id` FROM `crawler_output`.`company_master` AS `CompanyMaster` WHERE `CompanyMaster`.`company_master_id` = 1 LIMIT 1
Please let me know how can I bind model without id as column name.
CakePHP will produce a separate query when dealing with hasMany relationships, and therefore you won't be able to reference a field from another table. Only belongsTo and hasOne relationships produce a JOIN.
However, you don't need to add conditions to the relationship. The following should just work fine:
$this->CompanyMaster->bindModel(array(
'hasMany' => array(
'CompanySignatoryDetails' => array(
'className' => 'CompanySignatoryDetails',
'foreignKey' => 'company_master_id',
),
)
));
Don't forget to define your primary keys for CompanyMaster:
class CompanyMaster extends AppModel
{
public $primaryKey = 'company_master_id';
}
and for CompanySignatoryDetails:
class CompanySignatoryDetails extends AppModel
{
public $primaryKey = 'company_signatory_details_id';
}
Well, for instance, let your query looks like this:
select CompanyMaster.*,CompanySignatoryDetails.* from
CompanyMaster as cm inner join CompanySignatoryDetails as cd on
cm.company_master_id=cd.company_master_id
order by cm.company_master_id;
You will get all fields from two tables, ordered by company_master_id field. You may reduce number of fields, displayed by this query, by explicitly designate them like this:
select cm.company_master_id, cd.name from....
HNY!(Happy New Year!!)

Cakephp find joining two columns

I have a BD that contains people with day and month fields, like so:
person1 (day = 5; month = 3)
person2 (day = 2; month = 12)
I have to perform a find between 2 dates, for example, I need all people between 01/03 and 01/06 (day/month) but I don't know how to perform that.
I tried using separate conditions, like this:
$conditions['People.day >='] = dayA;
$conditions['People.month >='] = monthA;
$conditions['People.day <='] = dayB;
$conditions['People.month <='] = monthB;
But, that's not correct because it finds day and month, I mean, it finds People between monthA and monthB and People between dayA and dayB, instead, what I need is people between dayA/monthA and dayB/monthB
I suppose I must do some kind of a JOIN, but I'm lost here, I looked some information but I don't know where to start.
updated info:
ok, I'm using this
Array
(
[People.month_day BETWEEN ? AND ?] => Array
(
[0] => 01/02
[1] => 28/02
)
)
but I get people like this:
1/1
2/1
10/1
11/1
12/1
13/1
20/1
21/1
1/2
what's wrong? do you need more code? I'm using this to retrieve results:
A paginate:
public $paginate = array('People'=>array(
'limit' => 16,
'order' => 'People.month, People.day ASC'
));
In your People model
public $virtualFields = array(
'month_day' => 'CONCAT(People.month, "-", People.day)'
// 'month_day' => 'CONCAT(People.day, "/", People.month)'
);
then add in your controller
$options = array(
'conditions' => array(
'Post.month_day BETWEEN ? AND ?' => array('01-03','01-06')
// 'Post.month_day BETWEEN ? AND ?' => array('03/01','06/01')
)
);
$posts = $this->Post->find('all',$options);
It would be best to alter your table. Use DATE field and your SQL query would be:
SELECT *
FROM dbname.People
WHERE People.date BETWEEN '1999-03-01' AND '1999-06-01';

Message list: order by and group by query on cakephp and mysql

I want to change my message list page/inbox. Currently it shows all the messages from the DB like if someone send me a message 3 times, it will all appear in my inbox. Now i want to make it simple like every sender will appear only once in the list and will show the latest message that he/she sent.
This is my code in cakephp:
$this->paginate = array(
'Message'=> array(
'conditions'=>array('Message.recipient_id'=>$this->user_id),
'group' => array('Message.sender_id'),
'order'=>'message_sent_date DESC',
'limit'=> 20,
)
);
The problem with this code is it shows the oldest message content. I think it's because group by always first before order by.
I was able to do it on mysql query but i don't know how to make it on cakephp.
Here's my query:
SELECT *
FROM(
SELECT *
FROM messages WHERE recipient_id = 114
ORDER BY message_viewed_date DESC
) AS messages
GROUP BY sender_id
ORDER BY message_viewed_date DESC
Please help me with this.. Thanks.
This should do the trick (make sure your models are set up correctly):
$results = $this->Message->find('all', array(
'conditions' => array(
'recipient_id' => 114
),
'group' => 'sender_id',
'order' => 'message_viewed_date DESC'
));
No need for the sub query there, it's not doing anything fancy. The manual will help you with queries like this.
I've solve this problem using the Model::query() http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-query
here's my code:
$messages = $this->Message->query("SELECT id FROM(SELECT * FROM messages WHERE recepient_id = ". $this->user_id ." ORDER BY message_sent_date DESC) AS Message GROUP BY sender_id ORDER BY message_sent_date DESC");
for($i=0; $i<count($messages); $i++){
$message_id[$i] = $messages[$i]['Message']['id'];
}
$this->paginate = array(
'Message'=> array(
'conditions'=>array('Message.id' => $message_id, 'Message.recepient_id'=>$this->user_id, 'Message.hidden_on_to'=>false),
'limit'=>20,
'order'=>array('Message.message_sent_date' => 'DESC'),
'recursive'=>0,
'fields'=>array('Message.id', 'Message.message_content', 'Message.message_sent_date', 'Message.message_viewed_date', 'Sender.id', 'Sender.username')
)
);

hasMany join in cakephp error

I have a table jobs whose structure is similar to below :
id desc
1 Job Description
And a table job_categories to save the categories of the jobs:
id job_id category_id
1 1 2
2 1 3
3 1 4
So to get the categories gor the job with id 1 , in JobsController.php, I wrote:
$similar_conditions['JobCategory.job_id'] = 1;
$similar_jobs = $this->Job->find('all',array('conditions' => $similar_conditions));
And my job model Job.php is:
class Job extends AppModel {
var $name = 'Job';
var $belongsTo = array('Qualification');
var $hasMany = array('JobCategory');
}
But it is showing an error SQLSTATE[42S22]: Column not found: 1054 Unknown column 'JobCategory.job_id' in 'where clause'. The query it is generating is:
SQL Query: SELECT Job.id, Job.job_title,
Job.job_description, Job.job_skills, Job.contact_number,
Job.contact_email, Job.qualification_id, Job.experience,
Job.categories, Job.remarks, Job.support_image,
Job.freshers_apply, Job.added_on, Job.status,
Qualification.id, Qualification.name FROM cakead.jobs AS
Job LEFT JOIN cakead.qualifications AS Qualification ON
(Job.qualification_id = Qualification.id) WHERE
JobCategory.job_id = 1
Why my table job_categories is not joining ?
From Cakephp Documentation
Foreign keys in hasMany, belongsTo or hasOne relationships are
recognized by default as the (singular) name of the related table
followed by _id. So if a Baker hasMany Cake, the cakes table will
refer to the bakers table via a baker_id foreign key. For a multiple
worded table like category_types, the foreign key would be
category_type_id.
try this
var $hasMany = array(
'JobCategory' => array(
'className' => 'JobCategories',
'foreignKey' => 'job_id',
'dependent' => true,
)
);
I think the problem is here $similar_conditions['JobCategory.job_id'] = 1;.
You cann't use ['JobCategory.job_id'] in your Job model.
Try this
$similar_jobs = $this->Job->find('all',array(
'contain' => array(
'JobCategory' => array(
'conditions' => array(
$similar_conditions
)
)
)
)
);
And add containable behavior to your AppModel