CakePHP 2.8 saveAll Creates Two Records Instead of One - cakephp-2.0

I'm cloning a milestone record with associated data. I first find the data from the source milestone, then change the contents of the array and remove all 'id' fields. Then I attempt a 'saveAll'. All the associated data is being created properly but the 'milestones' table now has 2 new records instead of 1. The second record contains the ID used by the associated data, so why does the first record even exist?
The Data (simplified) and Call:
$test = array(
'Milestone' => array(
'name' => 'Clone Test',
'customer_status' => '',
'time_to_complete' => '1',
'is_active' => true,
),
'MilestoneAlert' => array(
(int) 0 => array(
'name' => 'Clone Test',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'First alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'Second alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
)
),
'MilestoneCondition' => array(
(int) 0 => array(
'name' => 'Clone Test',
'condition' => 'First condition.',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'condition' => 'Second condition.',
'is_active' => true,
)
)
);
$this->loadModel('Milestone');
$this->Milestone->create();
$this->Milestone->saveAll($test);
In Model/Milestone.php:
public $hasMany = array(
'MilestoneAlert' => array(
'className' => 'MilestoneAlert',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'MilestoneCondition' => array(
'className' => 'MilestoneCondition',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => 'MilestoneCondition.order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
In Model/MilestoneAlert.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In Model/MilestoneCondition.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
After running the method, there are two records in 'milestone_conditions', two records in 'milestone_alerts', and two identical records in 'milestones'. How do I keep it from creating two 'milestone' records?

Try to get the original data like this:
$test= $this->Milestone->findById('insert your id');
$this->Milestone->create(); // Create a new record
$this->Milestone->saveAll($test,array('deep' => true)); // And save it

Related

HABTM inner join CakePHP 2.0

I have 5 tables: tournaments, rounds, videos, rounds_tournaments, rounds_videos
Relations:
Tournament hasMany Video
Video belongsTo a Tournament
Tournament HABTM Round
Round HABTM Tournament
Video HABTM Round
Round HABTM Video
What I want to achieve:
Now I only want the videos that belong to a specific Tournament and Round.
So when clicking on a Tournament I only want the rounds associated with the clicked Tournament. And when clicking on a Round I only want the get the videos associated with the clicked Round and the Tournament.
I've tried everything but can't get it to work. I've played with several views as well (the index, view actions of Round/Tournament/Video). I'm not sure where to put the the JOIN statement, but I think it's inside the controller.
The Problem I've got atm is that when clicking on a Round it gives me the videos of that Round but for all the Tournaments and not for one Tournament.
Also looked here:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
CakePHP find HABTM
Round Model:
public $hasAndBelongsToMany = array(
'Tournament' => array(
'className' => 'Tournament',
'joinTable' => 'rounds_tournaments',
'foreignKey' => 'round_id',
'associationForeignKey' => 'tournament_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
'Video' => array(
'className' => 'Video',
'joinTable' => 'rounds_videos',
'foreignKey' => 'round_id',
'associationForeignKey' => 'video_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
Video Model:
public $belongsTo = array(
'Tournament' => array(
'className' => 'Tournament',
'foreignKey' => 'tournament_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
public $hasAndBelongsToMany = array(
'Round' => array(
'className' => 'Round',
'joinTable' => 'rounds_videos',
'foreignKey' => 'video_id',
'associationForeignKey' => 'round_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
Tournament Model:
public $hasMany = array(
'Video' => array(
'className' => 'Video',
'foreignKey' => 'tournament_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
public $hasAndBelongsToMany = array(
'Round' => array(
'className' => 'Round',
'joinTable' => 'rounds_tournaments',
'foreignKey' => 'tournament_id',
'associationForeignKey' => 'round_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
);
RoundsVideo model:
public $belongsTo = array(
'Round' => array(
'className' => 'Round',
'foreignKey' => 'round_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Video' => array(
'className' => 'Video',
'foreignKey' => 'video_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
RoundsTournament model:
public $belongsTo = array(
'Round' => array(
'className' => 'Round',
'foreignKey' => 'round_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Tournament' => array(
'className' => 'Tournament',
'foreignKey' => 'tournament_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
What I have tried:
index action of VideosController
$this->Video->recursive = -1;
$options['joins'] = array(
array('table' => 'rounds_videos',
'alias' => 'RoundsVideo',
'type' => 'inner',
'conditions' => array(
'Video.video_id = RoundsVideo.video_id'
)
),
array('table' => 'rounds',
'alias' => 'Round',
'type' => 'inner',
'conditions' => array(
'RoundsVideo.round_id = Round.round_id'
)
)
);
$this->set('videos', $this->Paginator->paginate());
index action of TournamentsController
$this->Tournament->recursive = -1;
$options['joins'] = array(
array('table' => 'rounds_tournaments',
'alias' => 'RoundsTournament',
'type' => 'inner',
'conditions' => array(
'Tournament.tournament_id = RoundsTournament.tournament_id'
)
),
array('table' => 'rounds',
'alias' => 'Round',
'type' => 'inner',
'conditions' => array(
'RoundsTournament.round_id = Round.round_id'
)
)
);
$this->set('tournaments', $this->Paginator->paginate());

cakephp deep conditions from controller

I am trying to get records from CoursesEmployee model within my BusinessesController. They are not linked directly which is my problem.
Each Business has Employees which can enrol in courses.
BusinessesController.php:
$options = array(
'conditions' => array('Business.' . $this->Business->primaryKey => 1)
);
$test = $this->Business->find('all', $options);
debug($test);
The output:
array(
(int) 0 => array(
'Business' => array(
'id' => '1',
'name' => 'Test Business',
),
'Employee' => array(
(int) 0 => array(
'id' => '1',
'business_id' => '1',
'name' => 'Keith Power',
'Business' => array(
'id' => '1',
'name' => 'Test Business',
),
'Course' => array(
(int) 0 => array(
'id' => '1',
'name' => 'Manual Handling',
'CoursesEmployee' => array(
'id' => '1',
'employee_id' => '1',
'course_id' => '1',
'course_module_id' => '1',
'completed' => true
)
),
(int) 1 => array(
'id' => '3',
'name' => 'Induction',
'CoursesEmployee' => array(
'id' => '2',
'employee_id' => '1',
'course_id' => '3',
'course_module_id' => '0',
'completed' => false
)
)
)
)
)
)
)
I wish to get the list of CoursesEmployee where CoursesEmployee.completed = true and Business.id = 1
Model Associations:
Business $hasMany Employee
Employee $belongsTo Business
Employee $hasAndBelongsToMany Course
public $hasAndBelongsToMany = array(
'Course' => array(
'className' => 'Course',
'joinTable' => 'courses_employees',
'foreignKey' => 'employee_id',
'associationForeignKey' => 'course_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
CoursesEmployee
public $belongsTo = array(
'Employee' => array(
'className' => 'Employee',
'foreignKey' => 'employee_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Course' => array(
'className' => 'Course',
'foreignKey' => 'course_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
cakephp 2.5
I suggest this way, if it doesn't work we'll try join way :
updated :
$coursesEmployes = $this->Business->Employee->CoursesEmployee->find('all',array(
'conditions'=>array('CoursesEmployee.completed '=> 'true' ,'Employee.business_id' => '1' ),
'recursive'=>3)
);
Hope it helps !

HABTM associations with another table

I'm in trouble with a more complex situation of HABTM in Cakephp. Ina nutshel, the situation is: a have users and movies, the relationship between then is HABTM, but i also need a relationship types.
USERS - HABTM - MOVIES
|
RELATION_TYPES
The relationship between users and movies could be many different types: author type, public type, etc.
When i try to use the contain behavior, i get an error message that says:
Model "MoviesUser" is not associated with model "RelationType".
But all the models are associated.
These are the models:
User Model
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'movies_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => 'Movie.title',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Movie Model
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'movies_users',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
MoviesUser Model
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'RelationType' => array(
'className' => 'RelationType',
'foreignKey' => 'relation_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In the MoviesController, i'm trying to get some movies and the relation with users and the type of the relation. Here is where i call the Contain on Movies Controller:
$this->Movie->contain(array(
'Person' => array(
'order' => array(
'Person.name'=>'ASC'
),
'Activity'
),
'Country' => array(
'order'=>array(
'Country.name'=>'ASC'
)
),
'User'=>array(
'conditions'=>array(
'User.id'=>$this->Session->read('Auth.User.id')
),
'MoviesUser'=>array(
'RelationType'
)
)
));
When i try to run this i get the message Model "MoviesUser" is not associated with the model "RelationType".
The fields of movies_user are:
id, user_id, relation_type_id, rate, comment
The fields of relation_types are:
id, title
And here my $has_many property on RelationType Model:
public $hasMany = array(
'MoviesUser' => array(
'className' => 'MoviesUser',
'foreignKey' => 'relation_type_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);

Cakephp 2.0 containable not working

edit - the code that uses contain.
$this->paginate = array(
'limit' => 20,
'order' => array(
'Individual.last_name' => 'asc',
'Individual.first_name' => 'asc'
),
'contain' => array(
'AccountsTrailersIndividual' => array(
'fields' => array('id', 'accounts_trailer_id', 'individual_id', 'account_holder_id'),
'AccountsTrailer' => array(
'fields' => array('id', 'account_id', 'trailer_id', 'charge_off_date', 'closed_date'),
'Balance' => array(
'fields' => array('id', 'accounts_trailer_id', 'balance')
),
'Account' => array(
'fields' => array('id', 'account_number'),
'conditions' => array('account_number' => $search)
),
),
'AccountHolder' => array(
'fields' => array('id', 'name')
)
),
),
'fields' => array('id', 'first_name', 'middle_initial', 'last_name', 'suffix'),
);
I am trying to contain my data to only pull what I need and it is not working. I have everything set up correctly I believe but it is giving me errors. What I have is in my appModel.php file
public $actsAs = array('Containable');
the errors I am getting are as follows:
Model "AccountsTrailersIndividual" is not associated with model "AccountsTrailer" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 339]
Model "AccountsTrailersIndividual" is not associated with model "AccountHolder" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 339]
I have checked the associations in the stated models and the associations are there.
for AccountsTrailersIndividual it looks like this
public $belongsTo = array(
'Individual' => array(
'className' => 'Individual',
'foreignKey' => 'individual_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'AccountsTrailer' => array(
'className' => 'AccountsTrailer',
'foreignKey' => 'accounts_trailer_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'AccountHolder' => array(
'className' => 'AccountHolder',
'foreignKey' => 'account_holder_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
for AccountsTrailer
public $hasAndBelongsToMany = array(
'Individual' => array(
'className' => 'Individual',
'joinTable' => 'accounts_trailers_individuals',
'foreignKey' => 'accounts_trailer_id',
'associationForeignKey' => 'individual_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
and for the AccountHolder
public $hasMany = array(
'AccountsTrailersIndividual' => array(
'className' => 'AccountsTrailersIndividual',
'foreignKey' => 'account_holder_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
I know that I must be missing something but I can't find it.
Any help is greatly appreciated.

CakePHP display custom fields from array

I know the title doesn't describe the best what I want to achieve, but I couldn't think of anything else.
Let's say I have the following array:
[Sender] => Array
(
[0] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 1
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 3
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
[1] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 3
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 2
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
)
I am using the ContainableBehaviour to cut off extra data.
My problem is: how do I filter out the Senders after a key which is present in PrivateMessagesUser? Say I need only the Sender where PrivateMessagesUser.recipient_id = 3.
I tried with
'Sender' => array(
'PrivateMessagesUser' => array(
)
),
but it didn't work. Looks like I have to get over the [0], [1]... keys somehow and I don't know how.
Any help would be appreciated!
EDIT
Here's how I obtain the array posted above:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()
),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
'PrivateMessagesUser' => array(
'fields' => array('PrivateMessagesUser.id')
//'conditions' => array('PrivateMessagesUser.recipient_id' => $this->Auth->user('id'))
)
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
);
How can I edit these lines in order to achieve the desired result?
EDIT 2
I am calling the paginate() from the PrivateMessagesController.
Associations:
User Model:
var $hasAndBelongsToMany = array(
'PrivateMessageSent' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'sender_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'PrivateMessageReceived' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'recipient_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
PrivateMessage Model:
var $hasAndBelongsToMany = array(
'Sender' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'sender_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Recipient' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'recipient_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
);
PrivateMessagesUser Model:
var $belongsTo = array(
'PrivateMessage' => array(
'className' => 'PrivateMessage',
'foreignKey' => 'private_message_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Sender' => array(
'className' => 'User',
'foreignKey' => 'sender_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
And the database tables look like:
users: id, username, ...
private_messages: id, subject, ...
private_messages_users: id, private_message_id, sender_id, recipient_id, status, ...
There are three ways to achieve this.
Looking at your returned data array, I'm guessing PrivateMessagesUser belongsTo Sender.
1. Querying the PrivateMessagesUser model
Sometimes, all it takes is querying the right model. You can apply the conditions directly to the model you want to apply your restrictions on.
$this->Sender->PrivateMessagesUser->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender')
));
2. Applying conditions to related models
This doesn't work all the time, because CakePHP's SQL generation doesn't always work the way you want it to. But in simple cases like a hasMany relationship, you can use this:
$this->Sender->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('PrivateMessagesUser')
));
Again, this will work only if Cake executes a JOIN for the Containable parameters AND uses the conditions right.
3. Using joins
This method is foolproof but a little messy since it's highly customizable.
$this->Sender->find('all', array(
'joins' => array(
array(
'table' => 'private_messages_users',
'alias' => 'PrivateMessagesUser',
'type' => 'inner',
'conditions' => array(
'PrivateMessagesUser.sender_id = Sender.id',
'PrivateMessagesUser.recipient_id' => 3
)
)
)
));
My last piece of advice for you is to place this code into the Model. Follow the principle of "fat models, skinny controllers" whenever possible.
In the Sender model:
function fetchByRecipientId($recipientId) {
...
}
Good luck!
EDIT: In order to make this work for pagination, follow the methods above but use the following format:
$this->paginate = array(
'PrivateMessagesUser' => array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender'),
// 'order' => ... other keys if you wish
)
);
$this->set('senders', $this->paginate());
You can put conditions inside Containable, like so:
$this->Sender->find('all', array(
'contain' => array(
'PrivateMessagesUser' => array('conditions' => array('recipient_id' => 3))
)
));
EDIT:
Try modifying your $this->paginate as follow:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()//array of message id's
),
'fields' => array('PrivateMessagesUser.id'),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
)
Then call your paginate $this->paginate($this->PrivateMessage)

Resources