saveall on habtm creates duplicate new rows - php

I have a simple HABTM with a lessons/Students table. i simply create a new lesson with an existing student via a while loop , so I should get 2 new rows. I am testing this function. What I get is 4 new rows in the lesson table instead of 2. I have no idea why the extra 2 rows are created as they are a duplicates of the 2 new rows which are outputted in debug. Everything is correctly saved like the entries in join lesson/student table and all the FK exist.
Just to add confusion, sometimes the same code produces the desired 2 rows . This is unstable so I am doing something wrong. I followed the array setup for habtm as in the manual for saves.
http://book.cakephp.org/2.0/en/models/saving-your-data.html
private function book_lessons($lesson=null) {
// debug( $lesson);
$i=0;
while ($i<2)
{
$date=date('Y-m-d');
$data[$i]=array();
$this->Lesson->create();
$data[$i]['Lesson']['lesson_date']= $date;
$data[$i]['Lesson']['start_time']= $lesson['Lesson']['start_time'];
$data[$i]['Lesson']['end_time']=$lesson['Lesson']['end_time'];
$data[$i]['Lesson']['schedule_rec']= 1;
$data[$i]['Lesson']['subject_id']= $lesson['Lesson']['subject_id'];
$data[$i]['Lesson']['tutoring_type_id']= 1;
$data[$i]['Lesson']['tutor_id']= $lesson['Lesson']['tutor_id'];
$data[$i]['Lesson']['subject_id']= $lesson['Lesson']['subject_id'];
$data[$i]['Lesson']['term_id']= $lesson['Lesson']['term_id'];
$data[$i]['Student']['id']=$lesson['Student']['id'];
$i=$i+1;
}
$this->Lesson->saveAll($data);
public $hasAndBelongsToMany = array(
'Student' => array(
'className' => 'Student',
'joinTable' => 'lessons_students',
'foreignKey' => 'lesson_id',
'associationForeignKey' => 'student_id',
'unique' => 'keepExisting',
)
);
array(
(int) 0 => array(
'Lesson' => array(
'lesson_date' => '2015-06-11',
'start_time' => '16:00:00',
'end_time' => '17:00:00',
'schedule_rec' => (int) 1,
'subject_id' => '16',
'tutoring_type_id' => (int) 1,
'tutor_id' => '12',
'term_id' => '10'
),
'Student' => array(
'id' => '206'
)
),
(int) 1 => array(
'Lesson' => array(
'lesson_date' => '2015-06-11',
'start_time' => '16:00:00',
'end_time' => '17:00:00',
'schedule_rec' => (int) 1,
'subject_id' => '16',
'tutoring_type_id' => (int) 1,
'tutor_id' => '12',
'term_id' => '10'
),
'Student' => array(
'id' => '206'
)
)
)

Move the $this->Lesson->create(); out of the loop. Cake will still save multiple records when you have only in create() method.

Related

cant join tables HABTM and many to one ,cakephp

I cant use a join to get the required data from the table relationship of
Student HABTM Subject, and
Guardian 1 to many Student
Without giving all the code,my find gets the required data but it adds another table (AvailabilityForStudent)which has a HABTM relationship with Student, along with other fields. I simply get too much data.
I have to add Guardian2 to the Guardian table to avoid a conflict which i dont understand.
What is the correct join to display data from 3 tables only?
$students = $this->find('all', array(
'joins'=>$joins,
'conditions' => $conditions,
'fields'=> $fields,
'order'=>$order,
));
$joins = array(
array('table' => 'students_subjects',
'alias' => 'StudentsSubject',
'type' => 'LEFT',
'conditions' => array(
'Student.id=StudentsSubject.student_id',
)
),
array('table' => 'subjects',
'alias' => 'Subject',
'type' => 'LEFT',
'conditions' => array(
'StudentsSubject.subject_id=Subject.id',
)
),
array('table' => 'guardians',
'alias' => 'Guardian2',
'type' => 'LEFT',
'conditions' => array(
'Student.guardian_id=Guardian2.id',
)
),
);
(int) 0 => array(
'Student' => array(
'id' => '267',
'last_name' => 'xxx',
'first_name' => 'xxx',
'address_suburb' => 'xxx',
'student_inactive' => false,
'student_mobile' => '0'
),
'Guardian' => array(
'guardian_last_name' => 'xx',
'guardian_first_name' => 'xxxx',
'id' => '267',
'guardian_mobile' => 'xxxx',
'guardian_email' => 'xx#yahoo.com.au'
),
'Subject' => array(
'name' => 'English: Year 7 - 10',
(int) 0 => array(
'id' => '9',
'name' => 'English: Year 7 - 10',
'StudentsSubject' => array(
'id' => '1079',
'student_id' => '267',
'subject_id' => '9',
'created' => null,
'modified' => null
)
)
),
'StudentsSubject' => array(
'id' => '1079'
),
'AvailabilityForStudent' => array(
(int) 0 => array(
Update- added this line $this->recursive = -1 instead of $this->Student->recursive = -1; and it works
Update- added this line $this->recursive = -1 instead of $this->Student->recursive = -1; and it works

CakePHP 2.x HABTM returning is no matching results

I have a problem with habtm with cakephp and i dont know how to solve yet. I've got three tables: setores, veiculos e setores_veiculos.
Setor model:
public $hasAndBelongsToMany = array(
'Veiculo' => array(
'className' => 'Veiculo',
'joinTable' => 'setores_veiculos',
'foreignKey' => 'setor_id',
'associationForeignKey' => 'veiculo_id',
'unique' => 'keepExisting'
)
);
Veiculo model:
public $hasAndBelongsToMany = array(
'Setor' => array(
'className' => 'Setor',
'joinTable' => 'setores_veiculos',
'foreignKey' => 'veiculo_id',
'associationForeignKey' => 'setor_id',
'unique' => 'keepExisting'
)
);
In my setores controller i have:
$options = array('conditions' => array('Setor.' . $this->Setor->primaryKey => $id));
$setores = $this->Setor->find('first', $options);
then in my debug:
array(
'Setor' => array(
'id' => (int) 5,
'nome' => '2º Batalhão',
'secretaria_id' => (int) 6,
'sigla' => '2º BPM',
'status_id' => (int) 1
),
'Veiculo' => array()
)
I can not understand why the Veiculo (vehicle) are not being listed. The insertion is working perfectly.
I expected:
'Veiculo' => array(
0 => array(
'id' => 1,
'name' => 'Corolla'
),
1 => array(
'id' => 2,
'name' => 'Hillux'
)
);
In my veiculos controller the setores are being listed. Any suggestion?
Thank you in advance and sorry about my english.
Looks fine to me. Try changing
'unique' => 'keepExisting'
to
'unique' => true
At present, I go by the simple rules as explained in the documentation that if I am using a simple link table, i.e. not storing any data in it, I use HABTM and unique set to true, otherwise I use hasMany through (The Join Model) and unique set to keepExisting so as not to lose extra stored data.
Post a data dump of setores_veiculos.

Using Containable behavior to filter results in Cakephp 2.2.4

I'm using containable behavior and the result of my find('all') is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
(int) 0 => array(
'lead_id' => '6',
'Estimate' => array(
(int) 0 => array(
'TOT_count' => '2'
)
)
)
)
)
)
I need to to count how many estimates there are in the lead.
The total (2) is correct, but i see nested 'Estimated' array, why ?
The result i would like to get is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
'TOT_count' => '2'
)
)
)
This is the find:
$options = array(
'contain' => array(
'User',
'Estimate' => array(
'fields' => 'COUNT(*) AS TOT_count'
)
),
'conditions' => array('Lead.id' => 6),
'fields' => 'User.*',
'limit' => 1
);
debug($this->Lead->find('all', $options));
How can i do it?
Thanks!
When you use a "custom" AS statement, in your case TOT_count, Cake will always put this in a result key called 0. You can avoid this by defining TOT_count as a virtualField in your model. That way it will be nested directly under the model name in your resultset.
Secondly, the lead_id is forcedly retrieved, because it is "needed" to make the join with the Lead model. It can not properly retrieve all the data without that piece of information there.

CakePHP: Joining calculated fields from another model to a model

I've been trying to figure out how to add some computed fields to a model in CakePHP. I'm able to achieve the desired result with the following query:
SELECT project_id,
COUNT(*) AS clicks_total,
SUM(CASE WHEN clicks.redirect_url = projects.url THEN 1 ELSE 0 END) AS clicks_redirected,
SUM(CASE WHEN clicks.redirect_url = projects.url THEN 0 ELSE 1 END) AS clicks_not_redirected
FROM clicks
LEFT JOIN projects ON clicks.project_id = projects.id
GROUP BY project_id
If I attempt to execute it as a custom query Cake transforms the result in such a way that it would require much array manipulation to be usable. I tried to do it the Cake way with the following code, but for some reason the calculated fields end up in a separate array which causes strange behavior in the view:
$this->paginate = array(
'Project' => array(
'fields' => array(
'id', 'name', 'url', 'url_mac', 'url_mobile',
'COUNT(*) AS clicks_total',
'SUM(CASE WHEN Click.redirect_url = Project.url THEN 1 ELSE 0 END) AS clicks_redirected',
'SUM(CASE WHEN Click.redirect_url = Project.url THEN 0 ELSE 1 END) AS clicks_not_redirected'
),
'joins' => array(
array(
'table' => 'clicks',
'alias' => 'Click',
'type' => 'LEFT',
'conditions' => array('Click.project_id = Project.id')
)
),
'group' => 'project_id'
));
$this->set('projects', $this->paginate());
Produces the following result:
array(
(int) 0 => array(
'Project' => array(
'id' => '508705c8-126c-48f9-bd9a-6d79d13bb9ea',
'name' => 'Test Project',
'url' => 'http://www.test.com',
'url_mac' => 'http://www.mac.com',
'url_mobile' => 'http://www.mobile.com'
),
(int) 0 => array(
'clicks_total' => '80',
'clicks_redirected' => '35',
'clicks_not_redirected' => '45'
)
),
(int) 1 => array(
'Project' => array(
'id' => '508b1073-2aa8-4895-b8d9-152ed13bb9ea',
'name' => 'Another Project',
'url' => 'http://another.com',
'url_mac' => 'http://anothermac.com',
'url_mobile' => 'http://anothermobile.com'
),
(int) 0 => array(
'clicks_total' => '134',
'clicks_redirected' => '70',
'clicks_not_redirected' => '64'
)
)
)
Does anyone have any ideas for getting the calculated click counts to show up under the Project array?
You can add virtual fields to your model:
Check it out: http://book.cakephp.org/1.3/view/1608/Virtual-fields
In Project model:
public $virtualFields = array('clicks_total' => 'COUNT(*)');

Cakephp counterCache multiple counterScope - Logical issue

Problem:
I have two models: Dealer, Testdrive (Testdrive belongs to Dealer through dealer_id). I want to show real time statistics about the dealers: total (Testdrive.active = 1), processed (Testdrive.active = 1 && Testdrive.processed = 1) ...
I have approx 100 dealers and 10000 testdrives. The count based sql takes about 10 sec (inefficient). Now i have a cronjob that runs every hour but I don't have real time stats.
I tried something like this:
var $belongsTo = array(
'Dealer' => array(
'className' => 'Dealer',
'foreignKey' => 'dealer_id',
'counterCache' => 'active',
'counterScope' => array('Testdrive.active' => 1),
'conditions' => '',
'fields' => '',
'order' => ''
),
'Dealer' => array(
'className' => 'Dealer',
'foreignKey' => 'dealer_id',
'counterCache' => 'processed',
'counterScope' => array('Testdrive.active' => 1, 'Testdrive.processed' => 1),
'conditions' => '',
'fields' => '',
'order' => ''
)
);
... but i overwritten the belongsTo => 'Dealear' value.
Can I have an array of counterCache with an array of counterScope?
var $belongsTo = array(
'Dealer' => array(
'className' => 'Dealer',
'foreignKey' => 'dealer_id',
'counterCache' => array('active', 'processed'),
'counterScope' => array('active' => array('Testdrive.active' => 1), 'processed' => array('Testdrive.active' => 1, 'Testdrive.processed' => 1)),
'conditions' => '',
'fields' => '',
'order' => ''
),
);
There's (now) an example of this in the documentation. Applied to the example in the question that would be:
class TestDrive extends AppModel {
public $belongsTo = array(
'Dealer' => array(
'counterCache' => array(
'active' => array(
'TestDrive.active' => 1
),
'processed' => array(
'TestDrive.active' => 1,
'TestDrive.processed' => 1
)
)
)
);
}
Note there's no need to define keys with default values (className, foreignKey etc.).

Categories