CakePHP HABTM relationship table joins - cakephp

I have a 'patient_cases' table with a HABTM relationship with a 'procedures' table. This 'procedures' tables has a many to one relationship with 'consultants' table, which then has a many to one relationship with 'specialties' table.
The relationships are working fine and using cakephp debug tool bar i can see everything is coming through correctly when i look at 'patient_cases' index page, however i'm only getting consultant_id and specialty_id rather than all of the fields with that associated model.
which is what should be happening i believe -
In CakePHP some associations (belongsTo and hasOne) performs automatic
joins to retrieve data, so you can issue queries to retrieve models
based on data in the related one.
But this is not the case with hasMany and hasAndBelongsToMany
associations.
I want to be able to get the consultant name from 'consultants' table using procedures.consultant_id and get the specialty name from 'specialties' using consultant.specialty_id.
I have tried playing about with some table joins but with no success,
class PatientCase extends AppModel {
public $hasAndBelongsToMany = array(
'Procedure' => array(
'className' => 'Procedure',
'joinTable' => 'patient_cases_procedures',
'foreignKey' => 'patient_case_id',
'associationForeignKey' => 'procedure_id',
'unique' => true
)
);
}
class Procedure extends AppModel {
public $belongsTo = array(
'Consultant' => array(
'className' => 'Consultant'
)
);
}
class Consultant extends AppModel {
public $belongsTo = array(
'Specialty' => array(
'className' => 'Specialty',
'conditions' => array('Specialty.active' => 1)
)
);
public $hasMany = array(
'Procedure'
);
}
class Specialty extends AppModel {
public $hasOne = array(
'Consultant'
);
);
}
$this->set('patientCases', $this->PatientCase->find('all'));
Returns everything i need, each model array is returned (other relationships not mentioned here), however the model array 'Consultant' is not returned, which also means i can not get the 'Specialty' data which is linked to the 'Consultant' model
EDIT
I have managed to get the data i need by using this in my PatientCasesController
$this->set('patientCases', $this->PatientCase->find('all'));
$this->set('patientCaseProcedures', $this->PatientCase->Procedure->find('all'));
However, ideally i want to return everything in the one 'patientCases', is this possible?
EDIT
I have solved the problem using the recursive function
$this->PatientCase->recursive = 3;
$this->set('patientCases', $this->PatientCase->find('all'));

Related

Retrieving the associated model in a hasMany through association without recursive

I have set up a hasMany through association between two tables - Books and Authors. The associations work properly, except when attempting to retrieve all the authors that belongs to a book. If I do this
$book = $this->Book->findById($id)
The array returned will not have an array Authors; it will have the AuthorToBook join model information, but it won't automatically fetch the Author associated with it.
I have to set recursive to 2 in order to retrieve the join model, and the associated Author. I am also re-fetching the Book data for each AuthorToBook association there is.
'AuthorToBook' => array(
(int) 0 => array(
'id' => '1',
'author_id' => '1',
'book_id' => '2',
'Author' => array(
'id' => '1',
'name' => 'J.R.R Tolkien',
'date_of_birth' => '1892-01-03 00:00:00',
'bio' => 'Professor and inventor of the Elvish Language'
),
'Book' => array(
'id' => '2',
'title' => 'Return of the King',
'pagecount' => '1200',
'publisher_id' => '1'
)
)
)
Now the question is - how can I fetch the associated model formed with a hasMany Through relationship without setting the recursive parameter?
Here's the source
<?php
class Author extends AppModel
{
public $hasMany = array('AuthorToBook');
}
?>
<?php
class AuthorToBook extends AppModel
{
public $useTable = 'authors_to_books';
public $belongsTo = array('Author', 'Book');
}
?>
<?php
class Book extends AppModel {
public $hasMany = array('AuthorToBook');
}
?>
Containable Behavior is your friend and is THE replacement for recursive. It allows you to specify exactly which associated model(s) you want to retrieve with each query.
Recursive is a cool thing, but it's pretty much agreed that you shouldn't actually use it beyond doing the intro tutorial for CakePHP. Set public $recursive = -1; in your AppModel (which makes it off by default), and never look back.

How to use one table multiple times?

I have a table called flights in which I set the departure and arrival airport. The airports is just another table and I want just to use the airport id in the flights table. How can I do this?, normally I can only use one id (airport_id) how can I use the second one? something like airport_id_2 ?..
My Flight model looks like this:
class Flight extends AppModel{
public $hasOne = "Airport";
}
Or should I do this manually by using joins?
you can use two fields:
arrival_airport_id
departure_airport_id
and in your Model
public $belongsTo = array(
"DepartureAirport" => array(
'className' => 'Airport',
'foreignKey' => 'departure_airport_id'
),
"ArrivalAirport" => array(
'className' => 'Airport',
'foreignKey' => 'arrival_airport_id'
)
)
PS: I think the right relationships is belongsTo and not HasOne because one airport can be related to many flights

CakePHP Join virtualField as displayField

I'm trying to do one of two things, use a virtual field from a model as the display field in my join model, or use the virtual field as the display in a find('list') on my join model.
Here's the current layout:
MODELS
<?php
class Participant extends AppModel {
public $hasMany = array('Registration');
public $virtualFields = array(
'full_name' => 'CONCAT(last_name, ", ", first_name)'
);
public $displayField = 'full_name';
}
-----
class Contest extends AppModel {
public $hasMany = array('Registration');
}
-----
class Registration extends AppModel {
public $belongsTo = array('Participant', 'Contest');
public $hasMany = array('Assignment');
}
?>
Tables are as follows:
participants contests registrations
------------ --------- --------------
id id id
first_name name contest_id
last_name participant_id
In my contests controller I'm trying to develop a list to be viewed as checkboxes in the view.
Here is the excerpt from my contests controller:
$this->loadModel('Registration');
$this->set('registrations', $this->Registration->find(
'list',
array(
'conditions' => array('contest_id' => $contestId),
'recursive' => 1
)
)
);
//$contestId is defined previously, and I have verified such.
This all actually runs fine as it is, and in the view will display a column of checkboxes with the registration_id as the label next to the checkbox.
I would like to get a full_name as is defined in the Participant model to be the displayField of the Registration model. I've been searching and can't quite seem to find a good way of doing that. I hope I have been descriptive enough, and please let me know if you have any questions and I'll try to explain better. Thank you.
edit: I'm using CakePHP 2.4.
try to add the 'fields' parameter
$this->loadModel('Registration');
$this->set('registrations', $this->Registration->find(
'list',
array(
'fields' => array('Registration.id', 'Participant.full_name'),
'conditions' => array('contest_id' => $contestId),
'recursive' => 1
)
));
edit: apparently cake does not place virtual fields of associated models when using find() with 'fields' options.
So you have to build your array by yourself, hoping your models use the containable behavior
$registrations = $this->Registration->find(
'all',
array(
'contain' => array(
'Participant' => array('full_name')
),
'conditions' => array('contest_id' => $contestId),
)
);
$registrations = Hash::combine($registrations, '{n}.Registration.id', '{n}.Participant.full_name');
$this->set('registrations', $registrations);

Translate from two tables with i18n database tables (cakePHP)

I have four tables:
gallery_categories table:
id (int);
title (varchar);
gallery_pictures table:
id (int);
title (varchar);
gallery_categories_gallery_pictures table to joint above tables:
gallery_category_id (int);
gallery_picture_id (int);
and the i18n table:
id (int)
locale (varchar)
model (varchar)
foreign_key (int)
field (varchar)
content (text)
I tried:
$this->GalleryCategory->bindModel(array(
'hasOne' => array(
'GalleryCategoriesGalleryPicture',
'GalleryPicture' => array(
'className' => 'GalleryPicture',
'foreignKey' => false,
'conditions' => array('GalleryPicture.id = GalleryCategoriesGalleryPicture.gallery_picture_id')
))));
$galleryCategories = $this->GalleryCategory->find('all', array(
'fields' => array('GalleryCategory.*','GalleryPicture.*')
));
But all time it returns with the right Category table fields and wrong Pictures table fields...
The Category fields contain the right translated words.
The Pictrures fields contain the wrong translated words.
The Models:
class GalleryCategory extends AppModel
{
public $tablePrefix = 'ef_';
var $name = 'GalleryCategory';
public $actsAs = array('Translate' => array(
'title' => 'titleTranslation'
)
);
}
class GalleryPicture extends AppModel
{
public $tablePrefix = 'ef_';
var $name = 'GalleryPicture';
public $actsAs = array('Translate' => array(
'title' => 'titleTranslation'
)
);
}
How could I get the right translated words from both table?
ps: The translation with "i18n Database Tables" works right with only one table (exp: only GalleryCategory or only GalleryPicture).
Translation doesn't work with associated models, see the last couple of lines here:
Note that only fields of the model you are directly doing find on will be translated. Models attached via associations won’t be translated because triggering callbacks on associated models is currently not supported.
Update
It might be tricky, as you have a HABTM relationship - previously I have worked around this by adding a second data retrieval to the afterFind callback of a model, but this was with a simpler association. Hope this helps.

Add a friend feature in CakePHP

I need a simple add a friend feature in my application, through some research, I would need a join table linking back to users table ? something like this: (I already have a users table)
Users-Friendships-Users
Can anyone give more details about this?
The friendships table should have following columns:
id Integer
user_from (the user who requested friendship)
user_to (the user who accepted friendship)
created (optional to track when your friendship started)
Then you need to create proper Model relation.
class User extends AppModel {
...
var $hasMany = array(
'UserFrom'=>array(
'className'=>'Friendship',
'foreignKey'=>'user_from'
),
'UserTo'=>array(
'className'=>'Friendship',
'foreignKey'=>'user_to'
)
);
var $hasAndBelongsToMany = array(
'Friendship' => array(
'className' => 'User',
'joinTable' => 'friendships',
'foreignKey' => 'user_from',
'associationForeignKey' => 'user_to'
);
...
}
class Friendship extends AppModel {
...
var $belongsTo = array(
'UserFrom'=>array(
'className'=>'User',
'foreignKey'=>'user_from'
),
'UserTo'=>array(
'className'=>'User',
'foreignKey'=>'user_to'
)
)
...
}
This way you are defining 2 relation in each model. You can add HABTM relation too. Run bake script to build your controllers and views. Then in your code you can use something like this:
$this->User->UserFrom->find('all',
array(
'conditions'=>array('user_from'=>1),
'contain'=>array('UserTo')
)
);
This should return friends of user with ID 1 and all friends details.
Be careful with the recursive queries. :)

Resources