Saving multiple models in CakePHP with saveAll() - cakephp

I'm trying to build an invitation system with CakePHP. I have Invitation model which hasMany People, and Person hasOne and belongsTo Invitation. I believe the relationships are working, since my Invitation index view can properly access and display its associated People through the Invitation model. But heres what the relationship rules look like:
class Invitation extends AppModel {
var $name = 'Invitation';
var $hasMany = array(
'People' => array(
'className' => 'Person',
'foreignKey' => 'invitation_id',
'dependent'=> true
)
);
...
}
class Person extends AppModel {
var $name = 'Person';
var $hasOne = 'Invitation';
var $belongsTo = 'Invitation';
...
}
UPDATED MODEL RELATIONSHIPS:
class Invitation extends AppModel {
var $name = 'Invitation';
var $hasMany = array('Person');
...
}
class Person extends AppModel {
var $name = 'Person';
var $belongsTo = array('Invitation');
...
}
In my Invitation add function, however, I am having trouble saving the data for new People. I want to simultaneously add one invitation and two people.
Heres my add function:
function add() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
$this->layout = 'ajax';
if(!empty($this->data)) {
$this->Invitation->create();
if($this->Invitation->saveAll($this->data)) {
//debug($this->data);
$this->Session->setFlash('Saved');
$this->redirect('invitations/add_invitations');
} else {
echo('Didnt save<br />');
}
}
}
}
Here is the output of my debug($this->data):
Array
(
[Invitation] => Array
(
[code] => 001
[password] => 85c8a3735499bf91d25e5960ab4ed9deeb0b457e
[type] => 1
[num_people] => 2
)
[Person] => Array
(
[0] => Array
(
[fname] => Jane
[lname] => Doe
)
[1] => Array
(
[fname] => John
[lname] => Doe
)
)
)
I don't get any errors. the Invitation data is saved properly, but the people are not.
UPDATE: I finally got this working with the above updated model relationships. Obviously the hasOne & belongsTo rules in the Person model were conflicting. After that I made a mistake (an embarrassing one) that was preventing saving to related the related Person model:
In the Invitation model, I hade $hasMany = array('People'); when it should have been $hasMany = array('Person').
I also had to change the configuration of my database to use InnoDB as the default, so that was certainly a necessary fix.

var $hasOne = 'Invitation';
var $belongsTo = 'Invitation';
These relations to the same model should have different Aliases otherwise Cake will get confused, as I did trying to unpick it. See http://book.cakephp.org/view/1046/Multiple-relations-to-the-same-model

Related

Model Association Not Correct

I am few months old with CakePHP. This is first time I am trying CakePhp Association. I assume I am following almost all instruction but still my model doesn't seem to work.
This is simple 'User' and 'Profile' Model. Table Structure: User:
- id (Primary Key)
- name
Profile:
- id (primary key)
- role
- user_id (Reference Key)
Models: User:
class UserModel extends AppModel{
var $name = 'User';
public $hasOne = array(
'Profile'
);
}
Profile:
class ProfileModel extends AppModel{
var $name = 'Profile';
public $belongsTo = array('User'); }
Controller: Users:
lass UsersController extends AppController{
var $name = 'Users';
public $scaffold;
function index(){
$user = $this->User->find('all'); //HERE I expect to get User and Profiles data
pr($user);
}
}
Profiles:
class ProfilesController extends AppController{
var $name = 'Profiles';
public $scaffold;
function index(){
$profile = $this->Profile->find('all');
pr($profile);
}
}
If I run users: /localhost/test_php_apps/users/ I get:
Array (
[0] => Array
(
[User] => Array
(
[id] => 1
[name] => rohini
)
)
)
I am wondering why 'Profile' data is not shown. I have manually added records in tables.
Further if I try in UsersController: $user = $this->User->Profile->find('all'); I get the following error:
Call to a member function find() on a non-object
My guess is something is wrong with setting up Associations. But not sure what is messing things up.
I know this is very basic question, but even after reading 10 to 15 related cases I don't seem to find the answer.
Any help will be much appreciated.
Do me a favor, change
class UserModel extends AppModel
to
class User extends AppModel
and
class ProfileModel extends AppModel
to
class Profile extends AppModel
and see if that helps when doing $user = $this->User->Profile->find('all'); in the UsersController.
Also, is
public $actsAs = array('Containable');
not
public $actAs = 'Containable';
not actAs. See if that helps any. If not, it would be helpful to know your cake version.
See here for containable and this for naming model conventions.
If you bake this things is made your life easier.
Models: User:
class User extends AppModel{
var $name = 'User';
public $hasMany = array(
'Profile'=>array(
'className' => 'Profile',
'foreignKey' => 'user_id',)
);
}
Profile:
class Profile extends AppModel{
var $name = 'Profile';
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
)
);
}
Controller: Users:
class UsersController extends AppController{
var $name = 'User';
public function index(){
$users = $this->User->find('all');
var_dump($users);
}
}
Controller Profile:
class ProfilesController extends AppController{
var $name = 'Profile';
public function index(){
$user_id = 2;
$users = $this->Profile->find('all', array('conditions'=>array('Profile.user_id'=>$user_id)));
var_dump($users);
}
}
add the following lines in your usermodel
public $useTable = 'YOUR USERTABLENAME';
and change
public $hasOne = array(
'Profile'
);
to public $hasOne = 'Profile';
in your profilmodel add the same.
public $useTable = 'YOUR PROFILETABLENAME';
and change
public $belongsTo = array('User');
to
public $belongsTo = array('User' => array('className' => 'User',
'foreignKey' => 'user_id'));
in your userscontontroller add this
public $uses = array('User','Profile');
normally it should work now when you try the query
$u = $this->User->find('all',array('contain' => array('Profile'));
or
$u = $this->User->find('all',array('recursive' => 2));
but it also should work if you write only:
$u $this->User->find('all');
regards

Cakephp: Associations not working

I want to do a simple cakephp association program but it's not working.
I have two database tables: users and sec_datas. When i run this program it just shows the result of first row of users table, not the result of both tables which have same sec_id value.
Controller code:
<?php
class UsersController extends AppController
{
public function index()
{
$this->autoRender = FALSE;
$this->loadModel('User');
$storeDivisions = $this->User->find();
echo "<pre>";
print_r($storeDivisions);
echo "</pre>";
}
}
Model code:
<?php
class User extends AppModel {
public $useTable='users';
public $hasOne = array(
'Sec_data' => array(
'ClassName' => 'Sec_data',
'Conditions' => array('User.sec_id=Sec_data.sec_id'),
'Dependent' => false
)
);
}
?>
If the primary key of User model is id then cake try to associate the foreign key in Sec_data with that key regardless the conditions you set.
First of all you should do domething like
public $hasOne = array(
'Sec_data' => array(
'ClassName' => 'Sec_data',
'ForeignKey' => 'sec_id',
'Dependent' => false
)
);
But it would work only if sec_id is related to User.id
if you want Sec_data.sec_id related to User.sec_id (and User.sec_id is different from User.id) then you have to join the tables manually
edit: see comments
There are a couple of things going wrong here. You should read up on CakePHP's conventions.
Your associated model class should be called SecData, then it will automatically map to the sec_datas table.
No need to use loadModel.
No need to specify conditions. Set the correct recursive level instead.
For hasOne, only one table has a foreign key. By default, the other Model has it ("User hasOne SecData" -> SecData has foreign key). So in your example, you should remove the column sec_id from User, and add a user_id column to your SecData Model.
See also: CakePHP Book on associations
Updated Controller code:
<?php
class UsersController extends AppController {
public $uses = array('User'); // Do this instead of loadModel
public function index() {
$this->autoRender = FALSE;
$this->User->recursive = 1; // Make User load associated records
$storeDivisions = $this->User->find('all');
pr($storeDivisions); // pr() is a Cake shorthand for print_r wrapped in <pre>
}
}
For your model:
<?php
class User extends AppModel {
// Unecessary. Convention is to use lowercase classname + 's', which
// already gives us 'users'
// public $useTable='users';
public $hasOne = array(
'SecData' => array( // Model class Sec_Data must be renamed accordingly
'dependent' => false
)
);
}
?>
Study model association in cake php . Here is very good explanation http://www.phpsupercoder.com/model-association-cake-php

How can I use counterCache() for tracking view counts with CakePHP?

Every time a user views a submission, I track the count and tie it to a session:
SubmissionsController:
// Count view
if ($this->Session->check('viewed_submission_' . $submissionId) !== true) {
$clientIp = ip2long($this->request->clientIp());
$this->SubmissionsViews->countView($submissionId, $clientIp);
$this->Session->write('viewed_submission_' . $submissionId, true);
}
I'm keeping track of them in a SubmissionsViews table.
SubmissionsViews Model:
class SubmissionsViews extends AppModel {
var $name = 'SubmissionsViews';
var $belongsTo = array(
'Submission' => array(
'className' => 'Submission'
)
);
public function countView($submissionId, $clientIp) {
$this->set('submission_id', $submissionId);
$this->set('user_ip', $clientIp);
$this->save($this->data);
}
}
My SubmissionsView table submissions_views has the following fields:
id
submission_id
user_ip
created
I'm trying to set up counterCache to keep track of additions to that table, but not sure how to set it up. I'm currently adding the counterCache in my $belongsTo within my Submission model:
class Submission extends AppModel {
var $belongsTo = array(
'User' => array(
'className' => 'User'
),
'SubmissionsViews' => array(
'counterCache' => true
)
);
But it's telling me it can't find Submission.submissions_views_id. In the documentation, all it said was that I needed to add a field to my submissions table called submissions_views_count, so I'm confused how to get this working?
Model names should be singlular, so SubmissionViews should be SubmissionView.
Your association is incorrect. Submission hasMany SubmissionView, not belongsTo.
counterCache needs to be specified in the SubmissionView model inside the belongsTo config for Submission, not in the Submission model file. Please read the manual more carefully.

CakePHP bindModel working, preset Model associations not

I am in development of a personal project.
I have two models 'Show' and 'Episode'. I have one controller 'Ops'.
Show model:
class Show extends AppModel
{
var $name = 'Show';
var $hasMany = array(
'Episode' => array(
'className' => 'Episode',
'foreignKey' => 'show_id'
)
);
}
Episode model:
class Episode extends AppModel
{
var $name = 'Episode';
var $belongsTo = array(
'Show' => array(
'className' => 'Show',
'foreignKey' => 'show_id'
)
);
}
Ops controller:
class OpsController extends AppController
{
var $name = 'Ops';
var $uses = array('Show','Episode');
function index()
{
$episodes = $this->Episode->find('all',array(
'limit' => 10,
'order' => array('Episode.first_aired' => 'DESC'),
)
);
debug($this->Episode);
debug($episodes);
}
}
When running the Ops controller I get the 'Episode' records like I want but don't get the associated 'Show' record based on the 'show_id' in the 'belongsTo' configuration. It appears that it is not referencing the model at all as I can purposefully break the model class an the request still goes on.
After doing a lot of checking, researching, and testing, I was able to get it to work by adding the following into the Ops controller before the find() request:
$this->Episode = ClassRegistry::init('Episode');
$this->Episode->bindModel(
array('belongsTo' => array(
'Show' => array(
'className' => 'Show'
)
)
)
);
Now while this works I would still like to know why my models are not being called properly. Any help would be most appreciated. Thanks!
What happens if you query Show in the same way?
Are you certain the id fields are defined correctly?
On both tables you should have id(INTsize) and on episodes there should also be show_id(INTsize).
If it's set up according to Cake convention, you should be able to remove the 'foreignKey' => 'show_id' line and Cake will sort it out itself.`
It sounds like Cake isn't using your model files and instead automagically generating some based on the tables.
It sounds dumb, but check the folders and file names for spelling errors and that they are lowercase.
In your Show model, you have the Episode foreign key set to show_id, which should be episode_id. However, I don't think that is causing the problem.
You aren't changing any CakePHP naming conventions, from what I can tell, so just remove the arrays that define the association and leave as string, e.g.
class Show extends AppModel
{
var $name = 'Show';
var $hasMany = array(
'Episode'
);
}
class Episode extends AppModel
{
var $name = 'Episode';
var $belongsTo = array(
'Show'
);
}
This may not work, but I have bumped into similar issues before and this resolved it. Good luck.

Using HABTM relationships in cakephp plugins with unique set to false

I am working on a plugin for our CakePHP CMS that will handle blogs. When getting to the tags I needed to set the HABTM relationship to unique = false to be able add tags to a post without having to reset them all.
The BlogPost model looks like this
class BlogPost extends AppModel {
var $name = 'BlogPost';
var $actsAs = array('Core.WhoDidIt', 'Containable');
var $hasMany = array('Blog.BlogPostComment');
var $hasAndBelongsToMany = array('Blog.BlogTag' => array('unique' => false), 'Blog.BlogCategory');
}
The BlogTag model looks like this
class BlogTag extends AppModel {
var $name = 'BlogTag';
var $actsAs = array('Containable');
var $hasAndBelongsToMany = array('Blog.BlogPost');
}
The SQL error I am getting when I have the unique => true setting in the HABTM relationship between the BlogPost and BlogTag is
Query: SELECT `Blog`.`BlogTag`.`id`, `Blog`.`BlogTag`.`name`, `Blog`.`BlogTag`.`slug`, `Blog`.`BlogTag`.`created_by`, `Blog`.`BlogTag`.`modified_by`, `Blog`.`BlogTag`.`created`, `Blog`.`BlogTag`.`modified`, `BlogPostsBlogTag`.`blog_post_id`, `BlogPostsBlogTag`.`blog_tag_id` FROM `blog_tags` AS `Blog`.`BlogTag` JOIN `blog_posts_blog_tags` AS `BlogPostsBlogTag` ON (`BlogPostsBlogTag`.`blog_post_id` = 4 AND `BlogPostsBlogTag`.`blog_tag_id` = `Blog`.`BlogTag`.`id`)
As you can see it is trying to set the blog_tags table to 'Blog'.'BlogTag. which isn't a valid MySQL name.
When I remove the unique => true from the relationship it all works find and I can save one tag but when adding another it just erases the first one and puts the new one in its place.
Does anyone have any ideas? is it a bug or am I just missing something?
Cheers,
Dean
Dean
So do you have the tables blog_posts_blog_tags?
To quote the CakePHP literature on HABTM relationships
We'll need to set up an extra table in the database to handle HABTM associations. This new join table's name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ ).
So ( dropping the Blog bit for readability !) you need your posts tables, your tags table and your posts_tags table and then the HABTM definition is
class Post extends AppModel {
var $name = 'Post';
var $hasAndBelongsToMany = array(
'Tag' =>
array(
'className' => 'Tag',
'joinTable' => 'posts_tags',
'foreignKey' => 'post_id',
'associationForeignKey' => 'tag_id',
'unique' => true,
)
);
}

Resources