I use softdelete Behaviour of Utils Plugin for CakePHP 2.x
I have following 4 tables
customers
customer_addresses
customer_contacts
customer_reports
And consider following its relationship with each other,
1. for customers
Customer hasMany CustomerAddress
Customer hasMany CustomerContact
Customer hasMany CustomerReport
public $hasMany = array(
'CustomerAddress' => array(
'className' => 'CustomerAddress',
'foreignKey' => 'customer_id',
'dependent' => true,
),
'CustomerContact' => array(
'className' => 'CustomerContact',
'foreignKey' => 'customer_id',
'dependent' => true,
),
'CustomerReport' => array(
'className' => 'CustomerReport',
'foreignKey' => 'customer_id',
'dependent' => true,
)
);
2. for customer_addresses
CustomerAddress belongsTo Customer
CustomerAddress belongsTo State
CustomerAddress hasOne CustomerContact
CustomerAddress hasOne CustomerReport
public $belongsTo = array(
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'customer_id',
'dependent' => false,
),
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
)
);
public $hasOne = array(
'CustomerContact' => array(
'className' => 'CustomerContact',
'foreignKey' => 'customer_address_id',
'dependent' => true,
),
'CustomerReport' => array(
'className' => 'CustomerReport',
'foreignKey' => 'customer_address_id',
'dependent' => true,
)
);
3. for customer_contacts
CustomerContact belongsTo Customer
CustomerContact belongsTo CustomerAddress
public $belongsTo = array(
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'customer_id',
'dependent' => false,
),
'CustomerAddress' => array(
'className' => 'CustomerAddress',
'foreignKey' => 'customer_address_id',
'dependent' => true,
)
);
4. for customer_reports
CustomerReport belongsTo Customer
CustomerReport belongsTo CustomerAddress
public $belongsTo = array(
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'customer_id',
'dependent' => false,
),
'CustomerAddress' => array(
'className' => 'CustomerAddress',
'foreignKey' => 'customer_address_id',
'dependent' => true,
)
);
I have put below code in bootstrap.
CakePlugin::load('Utils');
I have also added below actAs in all above model
public $actsAs = array('Containable','Utils.SoftDelete');
I have already put below code in my appModel.
// for softdelete, checking exist id
public function exists($id = null) {
if ($this->Behaviors->attached('SoftDelete')) {
return $this->existsAndNotDeleted($id);
} else {
return parent::exists($id);
}
}
// for softdelete, overrite delete method
public function delete($id = null, $cascade = true) {
$result = parent::delete($id, $cascade);
if ($result === false && $this->Behaviors->enabled('SoftDelete')) {
return $this->field('deleted', array('deleted' => 1));
}
return $result;
}
When I try to cascade delete with out soft delete ( means simple cascade delete ) , it works fine.
But My problem is that.
When I use softdelete behaviour of Utils plugin , Cascade delete does not work.
I have tried to delete record using below code
if ($this->CustomerAddress->delete()) {
$this->Session->setFlash(__('CustomerAddress deleted'));
$this->redirect($this->referer());
}
SQL log
array(
'log' => array(
(int) 0 => array(
'query' => 'SELECT COUNT(*) AS `count` FROM `lewie`.`customer_addresses` AS `CustomerAddress` LEFT JOIN `lewie`.`customers` AS `Customer` ON (`CustomerAddress`.`customer_id` = `Customer`.`id`) LEFT JOIN `lewie`.`states` AS `State` ON (`CustomerAddress`.`state_id` = `State`.`id`) LEFT JOIN `lewie`.`customer_contacts` AS `CustomerContact` ON (`CustomerContact`.`customer_address_id` = `CustomerAddress`.`id`) LEFT JOIN `lewie`.`customer_reports` AS `CustomerReport` ON (`CustomerReport`.`customer_address_id` = `CustomerAddress`.`id`) WHERE `CustomerAddress`.`id` = 43 AND `CustomerAddress`.`deleted` = '0'',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 0
),
(int) 1 => array(
'query' => 'SELECT COUNT(*) AS `count` FROM `lewie`.`customer_addresses` AS `CustomerAddress` LEFT JOIN `lewie`.`customers` AS `Customer` ON (`CustomerAddress`.`customer_id` = `Customer`.`id`) LEFT JOIN `lewie`.`states` AS `State` ON (`CustomerAddress`.`state_id` = `State`.`id`) LEFT JOIN `lewie`.`customer_contacts` AS `CustomerContact` ON (`CustomerContact`.`customer_address_id` = `CustomerAddress`.`id` AND `CustomerContact`.`deleted` = '0') LEFT JOIN `lewie`.`customer_reports` AS `CustomerReport` ON (`CustomerReport`.`customer_address_id` = `CustomerAddress`.`id` AND `CustomerReport`.`deleted` = '0') WHERE `CustomerAddress`.`id` = 43 AND `CustomerAddress`.`deleted` = '0'',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 1
),
(int) 2 => array(
'query' => 'SELECT COUNT(*) AS `count` FROM `lewie`.`customer_addresses` AS `CustomerAddress` LEFT JOIN `lewie`.`customers` AS `Customer` ON (`CustomerAddress`.`customer_id` = `Customer`.`id`) LEFT JOIN `lewie`.`states` AS `State` ON (`CustomerAddress`.`state_id` = `State`.`id`) LEFT JOIN `lewie`.`customer_contacts` AS `CustomerContact` ON (`CustomerContact`.`customer_address_id` = `CustomerAddress`.`id` AND `CustomerContact`.`deleted` = '0') LEFT JOIN `lewie`.`customer_reports` AS `CustomerReport` ON (`CustomerReport`.`customer_address_id` = `CustomerAddress`.`id` AND `CustomerReport`.`deleted` = '0') WHERE `CustomerAddress`.`id` = 43 AND `CustomerAddress`.`deleted` = '0'',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 0
),
(int) 3 => array(
'query' => 'UPDATE `lewie`.`customer_addresses` SET `deleted` = '1', `deleted_date` = '2014-05-27 10:46:43', `modified` = '2014-05-27 10:46:43' WHERE `lewie`.`customer_addresses`.`id` = '43'',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 0
),
(int) 4 => array(
'query' => 'SELECT `CustomerAddress`.`deleted` FROM `lewie`.`customer_addresses` AS `CustomerAddress` WHERE `deleted` = '1' LIMIT 1',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 0
)
),
'count' => (int) 5,
'time' => (float) 1)
How can I resolve this problem?
Related
I am new in cakephp and trying my best to implement queries in cakephp.
I have this query
SELECT * FROM question join question_topic on question.question_id=question_topic.question_id join topic on topic.topic_id=question_topic.topic_id join user_topic on user_topic.topic_id=topic.topic_id where user_topic .user_id=10
I need this in cakephp.
What I have tried is this
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User',
'UserInfo.UserTopic'=>array(
'conditions'=>array('UserTopic.user_id'=>10)
),
'QuestionAndTopic.Topic','UpVoteQuestion','Answer','Answer.UserInfo'
),
'order' => 'rand()',
'recursive' => 0
));
But the query is not giving me a right results. Could you please take a look.
Question.php
class Question extends AppModel
{
public $useTable = 'question';
public $primaryKey = 'question_id';
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'fields' => array('User.user_id','User.email','User.active')
),
'UserInfo' => array(
'className' => 'UserInfo',
'foreignKey' => 'user_id',
)
);
public $hasMany = array(
'Answer' => array(
'className' => 'Answer',
'foreignKey' => 'question_id',
),
'QuestionAndTopic' => array(
'className' => 'QuestionAndTopic',
'foreignKey' => 'question_id',
)
);
public function latestQuestions(){
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User',
'UserInfo.UserTopic'=>array(
'conditions'=>array('UserTopic.user_id'=>10)
),
'QuestionAndTopic.Topic','UpVoteQuestion','Answer','Answer.UserInfo'
),
'order' => 'rand()',
'recursive' => 0
));
}
}
You can use Mysql query it will works as like as cakephp query
$this->Behaviors->query('SELECT * FROM question join question_topic on question.question_id=question_topic.question_id join topic on topic.topic_id=question_topic.topic_id join user_topic on user_topic.topic_id=topic.topic_id where user_topic .user_id=10');
Refer this link
$options['joins'] = array(
array('table' => 'books_tags',
'alias' => 'BooksTag',
'type' => 'inner',
'conditions' => array(
'Book.id = BooksTag.book_id'
)
),
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'inner',
'conditions' => array(
'BooksTag.tag_id = Tag.id'
)
)
);
$options['conditions'] = array(
'Tag.tag' => 'Novel'
);
$books = $Book->find('all', $options);
make changes as per you table and fields.hope this helps.
with the updated code i am trying to bind relation between payment and website , but it seems group by is not working. and i am getting lot of duplicate result.
Updated :
$this->Website->unBindModel(array('hasMany' => array('User')));
$this->Website->bindModel(array(
'hasMany' => array(
'Payment' => array(
'className' => 'Payment',
'foreignKey' => 'website_id',
'fields' => array(
'Payment.id',
'Payment.website_id',
'Payment.created',
'Payment.user_id',
'Payment.is_get_invoice'
) ,
'conditions' => array(
'Payment.website_id <>' => '0',
'Payment.is_get_invoice' => '0'
),
'order' => array(
'Payment.id DESC'
),
'group' => array(
'Payment.website_id' //Its not working
)
)
)
)
);
$this->Website->recursive = 1;
$webPayments = $this->Website->find('all', array('fields' => array('Website.id'),'contain' => array('Payment')));
Old :
I am trying to bind and unbind model runtime.
but its giving me error. even association is not working.
$this->Website->unBindModel(array(
'hasMany' => array(
'User'
)
));
$this->Website->bindModel(array(
'hasMany' => array(
'Payment' => array(
'className' => 'Payment',
'foreignKey' => 'website_id'
)
)
));
$this->Website->recursive = 1;
$webPayments = $this->Website->find('all', array(
'fields' => array(
'Website.id',
'Payment.id',
'Payment.website_id',
'Payment.created',
'Payment.user_id'
) ,
'conditions' => array(
'Payment.website_id <>' => '0',
'Payment.is_get_invoice' => '0'
) ,
'order' => array(
'Payment.id DESC',
'group' => array(
'Payment.website_id'
)
)
));
pr($webPayments);
Error:
Columnnotfound: 1054 Unknowncolumn 'Payment.id' in 'field list'
SELECT`Website` . `id`, `Payment` . `id`, `Payment` . `website_id`, `Payment` . `created`, `Payment` . `user_id`, FROM`websites` AS `Website`WHERE`Payment` . `website_id` <> 0 AND `Payment` . `is_get_invoice` = '0' AND `Payment` . `created` > '2017-04-13 07:07:54' GROUPBY `Payment` . `website_id` ORDERBY `Payment` . `id` DESC
Try using contain like this:
$webPayments = $this->Website->find('all', array(
'fields' => array(
'Website.id',
),
'contain' => array(
'Payment' => array(
'fields' => array(
'Payment.id',
'Payment.website_id',
'Payment.created',
'Payment.user_id'
),
'conditions' => array(
'Payment.website_id <>' => '0',
'Payment.is_get_invoice' => '0'
),
'order' => array(
'Payment.id DESC',
'group' => array(
'Payment.website_id'
)
)
)
)
));
https://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
Are your models declared properly for the association? You should have
class Payment extends AppModel {
var $name = 'Payment';
public $actAs = array('Containable');
public $belongsTo = array (
'Website' => array(
'className' => 'Website',
'foreignKey' => 'website_id'
)
)
[...]
}
class Website extends AppModel {
var $name 'Website';
public $actAs = array('Containable');
public $hasMany = array(
'Payment' => array(
'className'=>'Payment',
'order' => 'Payment.id DESC'
)
)
[...]
}
I find that declaring things as low as possible in the model really works better than trying to do it on the fly with a query.. If the association is properly declared in the model itself you shouldn't have to dork with binding/unbinding like that..
The hasMany association does not support the group by key.
In this particular case, what you are trying to achieve by the incorrect use of group is to return just one result. Note that the same functionality can be accomplished by using the limit key, which is supported.
The code would be the following:
$this->Website->unBindModel(array('hasMany' => array('User')));
$this->Website->bindModel(array(
'hasMany' => array(
'Payment' => array(
'className' => 'Payment',
'foreignKey' => 'website_id',
'fields' => array(
'Payment.id',
'Payment.website_id',
'Payment.created',
'Payment.user_id',
'Payment.is_get_invoice'
) ,
'conditions' => array(
'Payment.website_id <>' => '0',
'Payment.is_get_invoice' => '0'
),
'order' => array(
'Payment.id DESC'
),
'limit' => 1
)
)
)
)
);
Reference
CakePHP 2.x hasMany Association
I am trying to link a HABTM model with joins but I dont get any records from the joined tables.
I have data for the tutor id =2 and also I have this id of 2 in the other tables of tutors-subjects and also a key in the subject. i should not get NULL in the other tables. I dont get an error.
I want all the subjects for tutor id =2.
Here is the controller and model with the relationship
array(
(int) 0 => array(
'Subject' => array(
'id' => null,
'name' => null
),
'TutorsSubject' => array(
'id' => null,
'tutor_id' => null,
'subject_id' => null
),
'Tutor' => array(
'id' => '2',
'tutor_inactive' => false,
'first_name' => 'fred2',
'last_name' => 'blah',..........
class TutorsController extends AppController {
public function tutordetails() {
$options2['joins'] = array(
array('table' => 'tutors_subjects',
'alias' => 'TutorsSubject',
'type' => 'LEFT',
'conditions' => array(
'Tutor.id = TutorsSubject.tutor_id', //fixed 'Tutor.id = TutorsSubject.id', //
)
),
array('table' => 'subjects',
'alias' => 'Subject',
'type' => 'LEFT',
'conditions' => array(
'TutorsSubject.subject_id=Subject.id',
)
)
));
$options2['fields'] = array('Subject.*','TutorsSubject.*','Tutor.*');
$this->Tutor->recursive = -1;
$options2['conditions'] = array('Tutor.id' => 2);
$subject=$this->Tutor->find('all',$options2);
$this->set('subject', $subject);
debug($subject);
class Subject extends AppModel {
public $hasAndBelongsToMany = array(
'Tutor' => array(
'className' => 'Tutor',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'subject_id',
'associationForeignKey' => 'tutor_id',
'unique' => 'keepExisting',
'conditions' => '',
)
);
}
class Tutor extends AppModel {
..
public $hasAndBelongsToMany = array(
'Subject' => array(
'className' => 'Subject',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'tutor_id',
'associationForeignKey' => 'subject_id',
'unique' => 'keepExisting',
'conditions' => '',
),
);
UPDATE=AgRIZZO solved it and changed made above
Agrizzo had the answer Using JOINs when you have properly defined model relations is huge mistake. Use the framework for what it was defined for (and you need is well supported without the JOINs.). That being said - your problem is most likely this: '
Tutor.id = TutorsSubject.id' in your first JOIN definition. Try
'Tutor.id = TutorsSubject.tutor_id
I have 3 tables structure as...
SONG(id, status)
TRACKLIST(id, song_id, artist_id, status)
ARTIST(id, status)
I wish to have HABTM so I mentioned as..
Song MODEL
var $hasAndBelongsToMany = array(
'Artist' => array(
'className' => 'Artist',
'joinTable' => 'tracklists',
'foreignKey' => 'song_id',
'associationForeignKey' => 'artist_id',
'conditions' => array('tracklist.status' => '1')
'with' => 'Tracklist',
//'unique' => true
),
);
Artist Model
var $hasAndBelongsToMany = array(
'Song' => array(
'className' => 'Song',
'joinTable' => 'tracklists',
'foreignKey' => 'artist_id',
'associationForeignKey' => 'song_id',
'with' => 'Tracklist',
//'unique' => true
),
);
Tracklist Model
var $belongsTo = array(
'Song' => array(
'className' => 'Song',
'foreignKey' => 'song_id',
'dependent' => true
),
'Artist' => array(
'className' => 'Artist',
'foreignKey' => 'artist_id',
'dependent' => true
)
);
This way but issue is when I tried to find records from the Artist table it find all the records without any condition.
$artist_conditions = array('Artist.status' => '1');
$artist_list = $this->Song->Artist->find('list', array('conditions' => $artist_conditions ));
I wish to fetch only those artist related to the tracklist and having tracklist.status as 1. Is the relationship is correct?? Or I simply use hasMany with (Song, Artist) and BelongsTo with (Tracklist).
You can try this:
/* for example in songs controller */
public $uses = array('Song','Tracklist');
$artist_conditions = array('Artist.status' => '1');
$this->Tracklist->recursive = 1;
$artist_list = $this->Tracklist->find('list', array('conditions' => $artist_conditions ));
Im trying to do a purge of records in a database though when I made my query and associations it seems to not want to do it correctly. I got the following error and Im confused as to why this is occurring:
SQL Error: 1054: Unknown column 'GuardiansStudents.student_id' in 'where clause'
The query that gets displayed afterwards is the following:
Query: SELECT `User`.`id`, `Guardian`.`id`
FROM `guardians` AS `Guardian`
LEFT JOIN `users` AS `User` ON (`Guardian`.`user_id` = `User`.`id`)
WHERE `GuardiansStudents`.`student_id` IS NULL
AND `User`.`active` = 1 AND `User`.`changeapprovalneeded` = 0
I also have the following associations in the Guardian model, not sure if Im doing this properly, and possibly this is where the error is occurring:
class Guardian extends AppModel {
var $name = 'Guardian';
//The Associations below have been created with all possible keys,
// those that are not needed can be removed
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
var $hasAndBelongsToMany = array(
'Student' => array(
'className' => 'Student',
'joinTable' => 'guardians_students',
'foreignKey' => 'guardian_id',
'associationForeignKey' => 'student_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
This is the code to do the purge function:
function manager_purgebygrade() {
ini_set('max_execution_time','120');
$this->layout = "manager";
$this->User->recursive = 0;
$grades = $this->User->Student->Grade->getDropDownList();
$this->set(compact('grades'));
//debug($this->data);
if(!empty($this->data['User']['grade_id']))
{
//$this->User->bindModel(array())
$users = $this->User->find(
'list',
array(
'fields' => array(
'User.id'
),
'conditions' => array(
'Student.grade_id' => $this->data['User']['grade_id']
),
'recursive' => 0
)
);
//debug($users);
$this->User->deleteAll(array('User.id' => $users), true);
$this->User->Guardian->bindModel(
array('hasOne' => array('GuardiansStudents')));
$guardianswithnostudents = $this->Guardian->deleteGuardiansWithNoStudent();
$guardians = $this->User->Guardian->find(
'list',
array(
'fields' => array(
'User.id',
'User.id'
),
'conditions' => array(
'GuardiansStudents.student_id' => null,
'User.active' => 1,
'User.changeapprovalneeded' => 0
),
'recursive' => 1
)
);
$this->User->deleteAll(array('User.id' => $guardians), true);
$this->set(compact('users','guardians','guardianswithnostudents'));
}
}
Hopefully someone can point me in the right direction I would greatly appreciate it :).
Your where clause:
WHERE `GuardiansStudents`.`student_id` IS NULL
is using table GuardiansStudents that appears nowhere in the from clause or join clause.
the model is GuardiansStudent, not GuardiansStudents.