CakePHP - model belongsTo 2 different model - cakephp

I'm making a Photo model, is it a good practice to make it belong to multiple models such as User, Place, etc?
Place also belongs to User
So here is my fields for Photos.
id
owner_id
type (an enum of the different models such as users and places)
Here is the belongsTo in PhotoModel that I have
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'owner_id',
'conditions' => array('Photo.type' => 'user'),
'fields' => '',
'order' => ''
),
'Place' => array(
'className' => 'place',
'foreignKey' => 'owner_id',
'conditions' => array('Photo.type' => 'place'),
'fields' => '',
'order' => ''
)
);
Or is it better to just create separate models such as UserPhoto, PlacePhoto etc?
Right now with this approach, I'm sometimes seeing dbo error when I set recursive to 2.
Thanks,
Tee

This approach can work, although if you set recursive to 2, the clearest solution is to create and/or destroy associations on the fly in such queries.

If in future you are going to use UserPhoto and PlacePhoto model, then it will be better to create separate models for them. So that you can customize those models later on. Or otherwise if you are using those models rarely then you can particularly bind those models in to your controller's method.
$this->User->bindModel(array('belongsTo' => array(
'User' => array(
'className' => 'User',
'foreignKey' => 'owner_id',
'conditions' => array('Photo.type' => 'user'),
'fields' => '',
'order' => ''
),
'Place' => array(
'className' => 'place',
'foreignKey' => 'owner_id',
'conditions' => array('Photo.type' => 'place'),
'fields' => '',
'order' => ''
)));

Related

CakePHP .find to return multiple HABTM relationships

I have a Model call Playlist.
Playlist has a HABTM with Track
public $hasAndBelongsToMany = array(
'Track' => array(
'className' => 'Track',
'joinTable' => 'tracklists_tracks',
'foreignKey' => 'tracklist_id',
'associationForeignKey' => 'track_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => array('id','title','version'),
'order' => 'TracklistsTrack.timing'
)
);
Track has an HABTM with AppUser
public $hasAndBelongsToMany = array(
'Artist' => array(
'className' => 'AppUser',
'joinTable' => 'artists_tracks',
'foreignKey' => 'track_id',
'associationForeignKey' => 'artist_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => array('id','username')
)
);
Now, i would like, when i write this
$tracklist = $this->Tracklist->findById($id);
to get for each tracklist all the tracks (and this does work as supposed to), and for every tracks all the AppUsers (cascading).
Mind that if i write $this->Track->findById($id);
i can actually get the AppUsers related to the track
Any idea to have this out of the box thanks to my diligent naming convention ?
Thank you
If you have define the correct relationship in your model, I would suggest using CakePHP containable behavior.
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
All you need to do is to include the behavior in your model and put the following in your controller
$this->TrackList->contain(array('AppUser','Artist'));

Cakephp HABTM issue retrieving multilevel data

I am creating an assessment database and using cakephp for the first time. I have gotten all the data entry and editing sorted but am having trouble retrieving some crucial data from a deep association:
The essence is
Course HABTM Units (table courses_units)
Unit hasMany Artefacts
Artefact hasOne AdminArtefact
Artefact belongsTo an Unit
The AdminArtefact model is used for each years dynamic data for an artefact (due_date, late_date and so on).
My problem is when I want to get all the due dates of artefacts for a particular course (which we need to check for hand in congestion)
If I do a findAll in the Artefacts controller with recursion set to '2' it gets all the data I need...but it overloads the page due to the amount of data returned. So I want to set the conditions for the findAll for the specific fields I need. However I cannot set the course in the query - From my understanding the course data is pulled from a 'separate' query as it appears in the results like this:
[Course] => Array
(
[0] => Array
(
[id] => 2
[course_code] => C0767S
[course_name] => BSc (hons) Entertainment Technology
[course_local_code] => ET
[course_leader] => 6
[colour] =>
[CoursesUnit] => Array
so as part of the query, I cannot set the course equal to a specific one, which I need to do so I can also specify the other data elements I want to pull and not the wealth of other data.
Ive tried loading the Unit model and changing the bind to a belongsTo instead of HABTM to the courses_units table but got the same dataset back again.
Ive tried going 'higher up the chain' to the CourseUnits controller and doing a '$uses' and specified all the relevant tables I want to pull data from but that didn't get anything useful.
Reading up on HABTM it doesn't automatically pull the data so I looked at joining the tables, but couldn't really see which model to make the join to get it to work.
I need to put this to bed now so hence I am asking the question: What is the most elegant way to get the due dates for all the artefacts for a specific course? (I need the course, the unit, the artefact and the due date...so something from all the tables)
QUERY String I want to use in Artefacts controller:
$data = $this->Artefact->find('all', array(
'fields' => array('Artefact.reference', 'AdminArtefact.due_date', 'ArtefactUnit.short_code', 'Course.course_code' )));
This gives the error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Course.course_code' in 'field list'
Thanks in advance!
Kevin
All relevant models:
class Course extends AppModel {
public $displayField = 'course_name';
public $hasAndBelongsToMany = array(
'Unit' =>
array(
'className' => 'Unit',
'joinTable' => 'courses_units',
'foreignKey' => 'course_id',
'associationForeignKey' => 'unit_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'CoursesUnit'
)
);
public $belongsTo = array(
'CourseLeader' => array(
'className' => 'User',
'foreignKey' => 'course_leader'
)
);
class Unit extends AppModel {
public $displayField = 'short_code';
public $hasMany = array(
'UnitArtefacts' => array(
'className' => 'Artefacts',
'foreignKey' => 'unit_id'
));
public $hasAndBelongsToMany = array(
'Course' =>
array(
'className' => 'Course',
'joinTable' => 'courses_units',
'foreignKey' => 'unit_id',
'associationForeignKey' => 'course_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'CoursesUnit'
)
);
public $belongsTo = array(
'External' => array(
'className' => 'User',
'foreignKey' => 'external_examiner'
),
'Coordinator' => array(
'className' => 'User',
'foreignKey' => 'coordinator'
),
'UnitLevel' => array(
'className' => 'Level',
'foreignKey' => 'level_id'
)
);
class Artefact extends AppModel {
public $displayField = 'reference';
public $hasOne = array(
'AdminArtefact' => array(
'className' => 'AdminArtefact',
'foreignKey' => 'artefact_id'
)
);
public $belongsTo = array(
'ArtefactUnit' => array(
'className' => 'Unit',
'foreignKey' => 'unit_id'
)
);
actually setting
'recursive' => 3,
should work.

CakePHP 2.4.2: Comments Model Relations-Get Original Post's Title

I have a pretty typical Comment model where Comment belongsto many other models such as Article, Review, Photo, etc and in turn each of those models hasmany Comment. Here is how I built the relationship on the Comment model...
<?php
App::uses('AppModel', 'Model');
class Comment extends AppModel {
var $name = "Comment";
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Article' => array(
'className' => 'Article',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Photo' => array(
'className' => 'Photo',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Review' => array(
'className' => 'Review',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
This works like a charm wherein if I'm viewing a particular article then I can retrieve all comments from that article and it works the same for the other models. What I'm trying to do is show ALL recent comments with the original post's title no matter what model the original post is coming from (Article, Review, Photo, etc) in the format of $comment['Original']['title']. I thought adding the below code within the belongsto of the Comment model would work but it does not....
'Original' => array(
'className' => 'Article',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 3),
'fields' => '',
'order' => ''
),
'Original' => array(
'className' => 'Review',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 2),
'fields' => '',
'order' => ''
),
'Original' => array(
'className' => 'Photo',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 8),
'fields' => '',
'order' => ''
),
Unfortunately this only shows the correct title if the recent comment was on a photo (Comment.module_id = 8).
You can use CakePHP's Containable Behavior and do this:
//within a method of the Comment model
$recentComments = $this->find('all', array(
'contain' => array(
'Article',
'Photo',
'Review',
'User'
),
'limit' => 10,
'order' => $this->alias . '.created DESC'
));
Then, you'll get back the comments and any of their parents, regardless of which model it's in. After that, as you repeat through each comment, you can either do a case statement, or an if(!empty()) kinda thing to determine which model has content that you want to display.
(side note: not a good idea to create multiple associations with the same name per your attempt with "Original")
It's not surprising that you got comments only with conditions Comment.module_id = 8. You have made a basic PHP mistake. By using the same key Original multiple times you are effectively overwriting it's value each time. Choose unique aliases (array keys) for each association.

Cakephp 2.x find first entry of releated model

I know that i can easily find related model-data through model associations, if I select a single entry. But what I want to do is to get the first image as a thumb for the galery, when I use find('all') for the index-page.
My relations (Galleries are named Albums) are:
//Album-Model
public $hasMany = array(
'Picture' => array(
'className' => 'Picture',
'foreignKey' => 'album_id',
'dependent' => true,
'conditions' => ''
)
);
and:
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Album' => array(
'className' => 'Album',
'foreignKey' => 'album_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
EDIT :
This should worked I tested it on my own!
Before your query add the following lane to specify the recursivity.
$this->Albums->recursive = 1;
$this->set('Albums', $this->Album->find('all'));
This way, it will also send the Pictures data. Then in your model associations, you can specify to only return the first image with the Album if that's what you want!
Just add 'limit' => '1', in your hasMany => Comments array, in Album Model.
Then you can iterate in your view doing
foreach($Albums as $Album){
$Album['Album']; // ALBUMS info do whatever
$Album['Picture']; // The thumbnail
}
EDIT2: I've just see you can also do
$this->Album->find('all', array('recursive' => 1));

hasAndBelongsToMany problem by changing the condition in the model

I select Blog entries by changing hasAndBelongsToMany conditions on the fly, it doesnt work anymore for me with cakephp 1.3.
Strange problem cause it was working fine with 1.2, in the model i test it by putting a condition with a static id to see what happen, (Tag.name => 'libros'). but it pass though the hasAndBelongsToMany condition. Bring me whatever results.
var $hasAndBelongsToMany = array('Tag' =>
array('className' => 'Tag',
'joinTable' => 'blogs_tags',
'foreignKey' => 'blog_id',
'associationForeignKey'=> 'tag_id',
'conditions' => '',
'order' => '',
'limit' => '',
'unique' => true,
'finderSql' => '',
'deleteQuery'=> ''
)
in the controller
$this->Blog->bindModel(array(
'hasAndBelongsToMany' => array(
'Tag' => array('conditions'=>array('Tag.name'=>'libros'))
)));
$this->Blog->find('all');
Now i dont have mysql error anymore , but i have others records with others results. Weird.
If you have a correct database structure, must use this=
$this->Blog->bindModel(array(
'hasOne' => array(
'BlogsTag',
'FilterTag' => array(
'className' => 'Tag',
'foreignKey' => false,
'conditions' => array('FilterTag.id = BlogsTag.tag_id')
))));
$data = $this->Blog->find('all', array(
'fields' => array('Blog.*'),
'conditions'=>array('FilterTag.name'=>'libros')
));
you can read more about this at :
http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM

Resources