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'));
Related
Given the following:
Content Model
public $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'contents_tags',
'foreignKey' => 'content_id',
'associationForeignKey' => 'tag_id',
'unique' => 'keepExisting',
)
);
Tag Model
public $hasAndBelongsToMany = array(
'Content' => array(
'className' => 'Content',
'joinTable' => 'contents_tags',
'foreignKey' => 'tag_id',
'associationForeignKey' => 'content_id',
'unique' => 'keepExisting',
)
);
Book Model
public $belongsTo = array(
'Content' => array(
'className' => 'Content',
'foreignKey' => 'content_id',
),
);
The Book model has a content_id. How can I ( if at all possible ) relate the Book Model to the Tag Model?
If you add a HasOne or HasMany relationship from the Content to the Book Model then Tag and Book are indirectly related via Content. If you want to use a find-call on one of them and get the other as associated data then all you have to do is set the recursive variable high. Does that make sense? Also then you can do stuff like $this->Book->Content->Tag or $this->Tag->Content->Book in their respective controllers.
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.
I want to save multiple categories for a product.
I have the models:
Category.php
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'product_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'product_id',
'unique' => 'keepExisting',
)
);
Product.php
public $hasMany = array(
'ProductCategory' => array(
'className' => 'ProductCategory',
'foreignKey' => 'product_id',
'dependent' => false,
),
ProductCategory.php
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id',
),
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
)
);
So in Product/add view I add a set of checkboxes of the Categories by:
echo $this->Form->input('ProductCategory.category_id',array(
'label' => __('Category',true),
'type' => 'select',
'multiple' => 'checkbox',
'options' => $categories
));
But this produces a set of inputs with the names of: name="data[ProductCategory][category_id][]" rather than name="data[ProductCategory][0][category_id]" the zero being incremented.
If they are in the format with the key between the model and field then I can use saveAll()?
As it is in the format I am getting I would have to manipulate the request->data to get it into the form I want to be able to save()
Am I going about this the correct way? Or maybe my models are set up incorrectly?
Also, what happens with editing hasMany data? What if for instance I uncheck an option and add another? Does cake automatically delete all associated records before adding new ones?
EDIT.
Essentially what I am asking is is there a better or quicker way of doing this, which works right now:
if ($this->Product->save($this->request->data)) {
$this->Product->ProductCategory->deleteAll(array('ProductCategory.product_id' => $this->Product->id));
foreach ($this->request->data['ProductCategory']['category_id'] as $cat_id) {
$this->Product->ProductCategory->create();
$this->Product->ProductCategory->set(array(
'product_id' => $this->Product->id,
'category_id' => $cat_id
));
$this->Product->ProductCategory->save();
}
}
in your form iterate however many you wish to display along the lines of
for/while/do()
{
$counter++
$this->Form->text('Product.'.$counter.'.price');
$this->Form->text('Product.'.$counter.'.description');
}
I would use saveAll() for this as it's designed to save a record and all it's related records for you automatically, assuming that your id's are in the data and it's formatted correctly.
http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveall-array-data-null-array-options-array
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' => ''
)));
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