I've been trying to figure out how to save multi-level models in CakePHP for some time now, but can't seem to find a solution.
I have three models. Survey, Question, and Choice.
Survey hasMany Question - so Question belongsTo Survey
Question hasMany Choice - so Choice belongsTo Question
The Question is linked to the Survey through its survey_id key.
The Choice, on the otherhand, is linked to the Question through its question_id key. (not directly linked to Survey though)
The form is created through $this->Form->create('Survey').
I want the application to save a survey with its corresponding questions, AND each question having their corresponding choice(s).
The problem is, only the Survey and Question models are saved. Choice gets discarded.
I'm using $this->saveAssociated($this->request->data, array( 'deep' => true) )
I will be updating my post to show the $_POST data.
Thanks,
XTN
Before saving data, you have to ensure that data should be in this format
in your controller:
$data = array('Survey' => array('id' => 1,'name' => 'test'),
'Question' => array(
array('id' => 1,'question' => 'test1','survey_id' => 1,
'Choice' => array(
array('id' => 1,'question_id' => 1,'choice' => 1),
array('id' => 2,'question_id' => 1,'choice' => 2)
)
),
array('id' => 2,'question' => 'question2','survey_id' => 1,
'Choice' => array(
array('id' => 3,'question_id' => 2,'choice' => 'sd'),
array('id' => 4,'question_id' => 2,'choice' => 'we')
)
)
)
);
$this->Survey->create();
$this->Survey->saveAssociated($data,array('deep'=>true));
Survey Model :
public $hasMany = array(
'Question' => array(
'className' => 'Question',
'foreignKey' => 'survey_id',
'dependent' => false,
)
);
Question Model :
public $belongsTo = array(
'Survey' => array(
'className' => 'Survey',
'foreignKey' => 'survey_id',
)
);
public $hasMany = array(
'Choice' => array(
'className' => 'Choice',
'foreignKey' => 'question_id',
'dependent' => false,
)
);
Choice Model :
public $belongsTo = array(
'Question' => array(
'className' => 'Question',
'foreignKey' => 'question_id',
)
);
I think it will work if found any problem please notify
Your models should looks like:
Survey Model: Survey.php
class Survey extends AppModel {
public $name = 'Survey';
public $hasMany = array('Questions' => array(
'className' => 'Question',
'foreignKey' => 'survey_id'
)
);
}
Question Model: Question.php
class Question extends AppModel{
public $name = 'Question';
public $belongsTo = array(
'Survey' => array('className' => 'Survey', 'foreignKey' => 'survey_id'),
'Answer' => array('className' => 'Choice', 'foreignKey' => 'answer_id'));
public $hasMany = array('Choices' => array('className' => 'Choice',
'foreignKey' => 'question_id'));
}
Choice Model: Choice.php
class Choice extends AppModel
{
public $name = 'Choice';
public $belongsTo = array('Question' => array('className' => 'Question',
'foreignKey' => 'question_id'));
}
Kindly ask if it not worked for you.
Related
'books
id,name
categories
id,name
books_categories
id,book_id,category_id'
' App::uses('AppModel', 'Model');
class Book extends AppModel {
public $useTable = 'books';
public $belongsTo = array(
'Agerange' => array(
'className' => 'Agerange',
'foreignKey' => 'agerange_id'
),
'Publication' => array(
'className' => 'Publication',
'foreignKey' => 'publication_id'
),
);
public $hasMany = array(
'Category' => array(
'className' => 'Book_Category',
'foreignKey' => 'book_id',
'joinTable' => 'books_categories',
'fields' => array('Category_id',),
)
);
}
<?php
App::uses('AppModel', 'Model');
class Book_Category extends AppModel {
public $useTable = 'books_categories';
public $belongsTo = array(
'Book' => array(
'className' => 'Book',
'foreignKey' => 'book_id'
),
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id'
)
);
}
in BooksController ......
$this->paginate = array(
'contains'=>array('Book','Publication','Agerange','Book_Category'),
'order' => 'Book.id ASC');
$books = $this->paginate('Book');
enter code here
{
Book: {id: "111", title: "ABC", subtitle: "English Today Primer", author: "Pruthviraj",…},…}
Agerange:{id: "31", from: "0", to: "2", status: true}
Book:{id: "111", title: "ABC", subtitle: "English Today Primer", author: "Pruthviraj",…}
Category:[{Category_id: "5", book_id: "111"}]
}'
Output Now I am getting only category_id:5 it's okay but I want name field also of category so How can I get name field of category using Book and Book_Category?
Modify your contain array by adding Categoy to Book_Category
$this->paginate = array(
'contains' => array(
'Book',
'Publication',
'Agerange',
'Book_Category' => 'Category'
),
'order' => 'Book.id ASC'
);
OR Use hasAndBelongsToMany association, it's much simpler
Start by deleting the Book_Category
Then change the book Model
class Book extends AppModel {
public $useTable = 'books';
public $belongsTo = array(
'Agerange' => array(
'className' => 'Agerange',
'foreignKey' => 'agerange_id'
),
'Publication' => array(
'className' => 'Publication',
'foreignKey' => 'publication_id'
),
);
public $hasAndBelongsToMany = array(
'Category' => array(
'className' => 'Category',
'joinTable' => 'books_categories',
'foreignKey' => 'book_id',
'associationForeignKey' => 'category_id'
)
);
}
Then, in your controller change the pagination setting like this
$this->paginate = array(
'contains' => array(
'Publication',
'Agerange',
'Category'
),
'order' => 'Book.id ASC'
);
#link Cakephp HABTM association
Here's my models
MODEL USERLIST
class UserList extends AppModel {
public $belongsTo = array(
'UserOwner' => array(
'className' => 'Usermgmt.User',
'foreignKey' => 'owner_id'
),
'UserMember' => array(
'className' => 'Usermgmt.User',
'foreignKey' => 'member_id'
)
);
public $recursive = -1;
public $actsAs = array('Containable');
MODEL USER
class User extends UserMgmtAppModel {
public $actsAs = array('Containable');
/**
* This model belongs to following models
*
* #var array
*/
var $belongsTo = array('Usermgmt.UserGroup');
/**
* This model has following models
*
* #var array
*/
var $hasMany = array(
'LoginToken' => array('className' => 'Usermgmt.LoginToken', 'limit' => 1),
'UserListOwner' => array('className' => 'UserList', 'foreignKey' => 'owner_id'),
'UserListMember' => array('className' => 'UserList', 'foreignKey' => 'member_id'),
);
var $hasOne = array(
'PhoneNumber' => array('className' => 'PhoneNumber', 'foreignKey' => 'user_id')
);
MODEL PHONENUMBER
class PhoneNumber extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'Usermgmt.User'
)
);
I want to do a database request on multiple parameters who are on multiple levels. This is my request.
$this->UserList->find("all", array('conditions' => array(
"UserList.type" => 1,
'UserList.owner_id' => $this->UserAuth->getUserId(),
"UserMember.PhoneNumber.phoneNumber LIKE" => "%" . "514" . "%"
), 'fields'=>array('UserMember.first_name', 'UserMember.last_name', "PhoneNumber.phoneNumber")))
My problem is when I run this request, I always receive an SQL error message who says that the field UserMember.PhoneNumber.phoneNumber does not exists.
I can do that request using standard SQL but i'dd like to do it with CakePhp.
How can I do it?
thanks
Your column name is wrong, this line "UserMember.PhoneNumber.phoneNumber LIKE" => "%" . "514" . "%" should be "PhoneNumber.phoneNumber LIKE" => "%" . "514" . "%" from the looks of things like you have in your fields.
You might also need to specify which models you want to contain like this:-
$this->UserList->find(
'all',
array(
'contain' => array(
'UserMember' => array('PhoneNumber')
),
'conditions' => array(
'UserList.type' => 1,
'UserList.owner_id' => $this->UserAuth->getUserId(),
'PhoneNumber.phoneNumber LIKE' => '%' . '514' . '%'
),
'fields'=>array(
'UserMember.first_name',
'UserMember.last_name',
'PhoneNumber.phoneNumber'
)
)
);
I am trying to save data with multiple HABTM & hasMany relation. Even if I use
$this->Project->save();
$this->Project->saveMany();
$this->Project->saveAssociated();
$this->Project->saveAlll();
It does not save associated model, I can't figure out what I am doing wrong.
Models Reations
Project hasAndBelongsToMany Skill
Project hasMany Milestone
Project hasAndBelongsToMany Attachment (because Milestone's will also have attachement so can not bind project & attachment in hasMany Relation)
Project Model
class Project extends AppModel{
public $belongsTo = array('Profile');
public $hasMany = array('Milestone');
public $hasAndBelongsToMany = array(
'Skill' =>
array(
'className' => 'Skill',
'joinTable' => 'projects_skills',
'foreignKey' => 'project_id',
'associationForeignKey' => 'skill_id',
'dependent' => true,
//'conditions' => array('Advertisement.advertisement_is_active' => '1')
),
'Attachment' =>
array(
'className' => 'Attachment',
'joinTable' => 'attachments_projects',
'foreignKey' => 'project_id',
'associationForeignKey' => 'attachment_id',
)
);
public function beforeSave($options = array()) {
parent::beforeSave($options = array());
foreach (array_keys($this->hasAndBelongsToMany) as $model):
if(isset($this->data[$this->alias][$model])):
$this->data[$model][$model] = $this->data[$this->alias][$model];
unset($this->data[$this->alias][$model]);
endif;
endforeach;
return true;
}
}
Skill Model
class Skill extends AppModel {
public $name = 'Skill';
public $hasOne = array('Exam');
public $hasAndBelongsToMany = array(
'Category' =>
array(
'className' => 'Category',
'joinTable' => 'categories_skills',
'foreignKey' => 'skill_id',
'associationForeignKey' => 'category_id',
'dependent' => true
),
'Profile' =>
array(
'className' => 'Profile',
'joinTable' => 'profiles_skills',
'foreignKey' => 'skill_id',
'associationForeignKey' => 'profile_id',
'dependent' => true
),
'Project' =>
array(
'className' => 'Project',
'joinTable' => 'projects_skills',
'foreignKey' => 'skill_id',
'associationForeignKey' => 'project_id',
//'dependent' => true
)
);
}
Attachment Model
class Attachment extends AppModel{
public $name = 'Attachment';
public $hasAndBelongsToMany = array(
'Project' =>
array(
'className' => 'Project',
'joinTable' => 'attachments_projects',
'foreignKey' => 'attachment_id',
'associationForeignKey' => 'project_id',
'dependent' => true,
)
);
}
Data
Array
(
[Project] => Array
(
[project_name] => Name Of Project
[project_detail] => Dummy short description
[project_category_id] => 3
[project_budget] => 45
[Skill] => Array
(
[0] => Array
(
[skill_id] => 14
)
[1] => Array
(
[skill_id] => 16
)
)
[project_status] => 1
[project_created] => 2014-08-04 15:31:00
[creator_id] => 1
)
[Milestone] => Array
(
[milestone_name] => Milestone 1
[milestone_budget] => 45
[milestone_created_on] => 2014-08-04 15:31:00
[project_id] => 8
)
[Attachment] => Array
(
[attachment_path] => 11615297103.zip
[attachment_term] => Project Attachment
[attachment_type] => zip
[project_id] => 8
)
)
Pass Skill id not the field name of relation model
[Skill] => Array
(
[0] => Array
(
[id] => 14
)
[1] => Array
(
[id] => 16
)
)
I have the following database tables:
products
********
id
title
artist_id
artists
*******
id
profile
rating
person_id
people
******
id
full_name
With the following model associations:
Product Model
*************
public $belongsTo = array(
'Artist' => array(
'className' => 'Artist'
'foreignKey' => 'artist_id'
)
);
Artist Model
************
public $belongsTo = array(
'Person' => array(
'className' => 'Person'
'foreignKey' => 'person_id'
)
);
public $hasMany = array(
'Product' => array(
'className' => 'Product'
'foreignKey' => 'product_id'
)
);
Person Model
************
public $hasOne = array(
'Artist' => array(
'className' => 'Artist'
'foreignKey' => 'person_id'
)
);
I have set each of the three models to use the Containable behaviour using:
public $actsAs = array('Containable');
When I use the following to get the product details along with the artist's name:
$this->Product->find('first', array('conditions' => array('Product.id' => $id), 'contain' => 'Person.full_name'))
I get the warning:
Model "Product" is not associated with model "Person"
And I only get the product details ie no artist's name. Why is this happening?
This is happening because you are calling the find operation on the Product model, and Person is not directly related to Product, but indirectly, by its relation to Artist. In this case, your contain array should be something like the following:
$this->Product->find('first', array(
'conditions' => array('Product.id' => $id),
'contain' => array('Artist' => 'Person.full_name')
));
This will return a result like
array(
[Product] => array(...),
[Artist] => array(
[Person] => array(
'full_name' => '...'
)
)
)
I use Cakephp framework, and I have problem with my association.
How create belong to association in models in cake php.
When I use belongto and hasMany in my model.
Can I find sample model to view this example?
Simple belongsTo association:
<?php
class Profile extends AppModel {
var $name = 'Profile';
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
}
?>
Simple hasMany association:
<?php
class User extends AppModel {
var $name = 'User';
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'user_id',
'conditions' => array('Comment.status' => '1'),
'order' => 'Comment.created DESC',
'limit' => '5',
'dependent'=> true
)
);
}
?>
More specific information about associations is in the CakePHP Book.
User has Many Photos
Photos belongs to User
In User Model :
var $hasMany = array(
'Photo' => array(
'className' => 'Photo',
'foreignKey' => 'user_id'
);
In Photo Model :
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'PhotoAlbum' => array(
'className' => 'PhotoAlbum',
'foreignKey' => 'photo_album_id',
'conditions' => '',
'fields' => '',
'order' => '',
))