I am trying to link a HABTM model with joins but I dont get any records from the joined tables.
I have data for the tutor id =2 and also I have this id of 2 in the other tables of tutors-subjects and also a key in the subject. i should not get NULL in the other tables. I dont get an error.
I want all the subjects for tutor id =2.
Here is the controller and model with the relationship
array(
(int) 0 => array(
'Subject' => array(
'id' => null,
'name' => null
),
'TutorsSubject' => array(
'id' => null,
'tutor_id' => null,
'subject_id' => null
),
'Tutor' => array(
'id' => '2',
'tutor_inactive' => false,
'first_name' => 'fred2',
'last_name' => 'blah',..........
class TutorsController extends AppController {
public function tutordetails() {
$options2['joins'] = array(
array('table' => 'tutors_subjects',
'alias' => 'TutorsSubject',
'type' => 'LEFT',
'conditions' => array(
'Tutor.id = TutorsSubject.tutor_id', //fixed 'Tutor.id = TutorsSubject.id', //
)
),
array('table' => 'subjects',
'alias' => 'Subject',
'type' => 'LEFT',
'conditions' => array(
'TutorsSubject.subject_id=Subject.id',
)
)
));
$options2['fields'] = array('Subject.*','TutorsSubject.*','Tutor.*');
$this->Tutor->recursive = -1;
$options2['conditions'] = array('Tutor.id' => 2);
$subject=$this->Tutor->find('all',$options2);
$this->set('subject', $subject);
debug($subject);
class Subject extends AppModel {
public $hasAndBelongsToMany = array(
'Tutor' => array(
'className' => 'Tutor',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'subject_id',
'associationForeignKey' => 'tutor_id',
'unique' => 'keepExisting',
'conditions' => '',
)
);
}
class Tutor extends AppModel {
..
public $hasAndBelongsToMany = array(
'Subject' => array(
'className' => 'Subject',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'tutor_id',
'associationForeignKey' => 'subject_id',
'unique' => 'keepExisting',
'conditions' => '',
),
);
UPDATE=AgRIZZO solved it and changed made above
Agrizzo had the answer Using JOINs when you have properly defined model relations is huge mistake. Use the framework for what it was defined for (and you need is well supported without the JOINs.). That being said - your problem is most likely this: '
Tutor.id = TutorsSubject.id' in your first JOIN definition. Try
'Tutor.id = TutorsSubject.tutor_id
Related
I have 3 tables
students(id,name)
subjects(id, subject)
student_subjects(id,student_id,subject_id)
students table is related to subjects on many to many relation using student_subjects table
student model
public $hasMany = array(
'studentsSubject' => array(
'className' => 'studentsSubject',
'foreignKey' => 'students_id',
));
students_subjects model
public $belongsTo = array(
'Student' => array(
'className' => 'Student',
'foreignKey' => 'students_id',
));
when I query
$students = $this->Student->find('all');
debug($students);exit();
it returns like this
array(
'Student' => array(
'id' => '1',
'name' => 'smith',
),
'StudentSubject' => array(
0=>array(
'id' => '1',
'student_id'=>'1',
'subject_id'=>'1'
),
1=>array(
'id' => '2',
'student_id'=>'1',
'subject_id'=>'2'
),
)
)
while I want to have subject names instead of subjectID as below
I know I can make changes in find to have required result
but I mean, Is it possible like link students table with 'subjects' instead of 'student_subjects'
array(
'Student' => array(
'id' => '1',
'name' => 'smith',
),
'Subject' => array(
0=>array(
'id' => '1',
'subject'=>'maths',
),
1=>array(
'id' => '2',
'subject'=>'computer',
),
)
)
You made belongsTo with Student in students_subjects model. This is incorrect. Instead of that you need to make belongsTo with Subject.
For this, you should use a HABTM assosiation. With your three tables defined as you have, you need just two models and the HABTM relationship between them.
class Student extends AppModel {
public $hasAndBelongsToMany = array(
'Subject' =>
array(
'className' => 'Subject',
'joinTable' => 'student_subjects',
'foreignKey' => 'student_id',
'associationForeignKey' => 'subject_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => ''
)
);
}
This way, you would have access as you want to the Subject model, through the Student model without any workaround.
Change model class name
Class Subject extends App_Model{
public $useTable = 'student_subjects';
}
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.
I'm stuck in Cakephp insert, here is what I have
-Order HABTM Address
-Address model
Here is my association in Address model :
public $hasAndBelongsToMany = array(
'Address' => array(
'className' => 'Address',
'joinTable' => 'address_customers',
'foreignKey' => 'customer_id',
'associationForeignKey' => 'address_id'
)
);
I want to save/insert a new customer with one new address
So, I thought the array below would work :
array(
'Customer' => array(
'nom' => 'Khiami',
'prenom' => 'TEST',
'tel' => '0945454545',
'ptel' => '',
'commentaire' => '',
'email' => '',
'anniversaire' => array(
'day' => '08',
'month' => '12',
'year' => '2012'
),
'createdFrom' => 's'
),
'Address' => array(
(int) 0 => array(
'adresse' => 'ADDR TEST',
'cp_id' => '1',
'etage' => '',
'residence' => '',
'batiment' => '',
'appartement' => '',
'type' => 'l',
'code_sonette' => '',
'code_portail' => '',
'code_batiment' => '',
'code_asc' => ''
)
)
)
The only thing that is working is when I save the Customer first and then use the array below :
array(
(int) 0 => array(
'Customer' => array(
'customer_id' => '394'
),
'Address' => array(
'adresse' => 'ADDR TEST',
'cp_id' => '1',
'etage' => '',
'residence' => '',
'batiment' => '',
'appartement' => '',
'type' => 'l',
'code_sonette' => '',
'code_portail' => '',
'code_batiment' => '',
'code_asc' => ''
)
)
)
But, I still don't have the association table filled ! It only adds an entry in the Address table.
Yes you should specify it in both:
Address model:
public $hasAndBelongsToMany = array(
'Customer' => array(
'className' => 'Customer',
'joinTable' => 'address_customers',
'foreignKey' => 'address_id',
'associationForeignKey' => 'customer_id'
));
Customer Model:
public $hasAndBelongsToMany = array(
'Address' => array(
'className' => 'Address',
'joinTable' => 'address_customers',
'foreignKey' => 'customer_id',
'associationForeignKey' => 'address_id'
));
Since you specify the jointable in your HABTM relationship I doubt its a naming convention problem.
Are you saving in the Address or the Customer model ? Because if you are calling it from the Address model I suppose there should already be a customer, in that case you only have to set:
$this->request->data['Customer']['Customer'] = $customer_id;
And save the address data, it should create the HABTM association in the table.
I have below defined in my model:
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'GroupBuy' => array(
'className' => 'GroupBuy',
'foreignKey' => 'group_buy_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
This however does not pull details from GroupBuy nor User table but it fetches only user_id and group_buy_id which are defined in this GroupBuyUser model.
I've set recursive two with below:
$this->GroupBuyUser->recursive = 2;
Is there something wrong I'm doing here?
Try the following code in your GroupBuyUser Model:
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
),
'GroupBuy' => array(
'className' => 'GroupBuy',
'foreignKey' => 'group_buy_id'
)
);
You don't need to set the recursive property to 2. This is basically used while we want to fetch result from deeper associated models.
I have 3 tables structure as...
SONG(id, status)
TRACKLIST(id, song_id, artist_id, status)
ARTIST(id, status)
I wish to have HABTM so I mentioned as..
Song MODEL
var $hasAndBelongsToMany = array(
'Artist' => array(
'className' => 'Artist',
'joinTable' => 'tracklists',
'foreignKey' => 'song_id',
'associationForeignKey' => 'artist_id',
'conditions' => array('tracklist.status' => '1')
'with' => 'Tracklist',
//'unique' => true
),
);
Artist Model
var $hasAndBelongsToMany = array(
'Song' => array(
'className' => 'Song',
'joinTable' => 'tracklists',
'foreignKey' => 'artist_id',
'associationForeignKey' => 'song_id',
'with' => 'Tracklist',
//'unique' => true
),
);
Tracklist Model
var $belongsTo = array(
'Song' => array(
'className' => 'Song',
'foreignKey' => 'song_id',
'dependent' => true
),
'Artist' => array(
'className' => 'Artist',
'foreignKey' => 'artist_id',
'dependent' => true
)
);
This way but issue is when I tried to find records from the Artist table it find all the records without any condition.
$artist_conditions = array('Artist.status' => '1');
$artist_list = $this->Song->Artist->find('list', array('conditions' => $artist_conditions ));
I wish to fetch only those artist related to the tracklist and having tracklist.status as 1. Is the relationship is correct?? Or I simply use hasMany with (Song, Artist) and BelongsTo with (Tracklist).
You can try this:
/* for example in songs controller */
public $uses = array('Song','Tracklist');
$artist_conditions = array('Artist.status' => '1');
$this->Tracklist->recursive = 1;
$artist_list = $this->Tracklist->find('list', array('conditions' => $artist_conditions ));