In CakePHP I have a model Type and SpecificType.
SpecificType belongTo a Type. (type_id field)
When I delete an entry of SpecificType, how can I also delete Type?
I have it as
$this->SpecificType->del($id, true)
However, the entry under Type isn't getting deleted.
Thanks,
Tee
I don't think you can delete Type with SpecificType cascade. you can only use cascade if there's hasMany or HABTM relation.
it is said in the manual.
Deletes the record identified by $id. By default, also deletes records
dependent on the record specified to
be deleted.
For example, when deleting a User
record that is tied to many Recipe
records (User 'hasMany' or
'hasAndBelongsToMany' Recipes):
* if $cascade is set to true, the related Recipe records are also
deleted if the models dependent-value
is set to true.
* if $cascade is set to false, the Recipe records will remain after the
User has been deleted.
you can always run
$this->del($id, true);
to remove your Type with related SpecificType-s.
You want to delete the Type, not the SpecificType. You will also need to make sure you have your model set correctly for Type:
var $hasMany = array(
'SpecificType' => array(
'className' => 'SpecificType',
'foreignKey' => 'type_id',
'dependent'=> true,
)
);
Then delete the type and it will work.
If you are deleting the child (SpecificType) and you want to delete it's parent, you must call the delete on the parent model. But keep in mind, if you have the Cascade set up correctly (dependent = true on the model) all of the SpecificType children will be deleted anyway.
Note: If you want to delete the parent of the child, you may want to reconsider your relationships and confirm they are correct. If that is really how you want them, then don't do the delete on the child. Simply make sure your cascade relationships are set correctly, pull the child's parent information, and delete the parent. Then all of the children will be removed as well.
I had the same problem in a situation where I did not want to follow the Cake model key convention.
I set the SpecificType model's belongsTo relationship to Type like so:
public $belongsTo = array(
'Type' => array(
'className' => 'Type',
'foreignKey' => 'type_id',
'conditions' => '',
'fields' => '',
'order' => '',
),
);
Then to get cascading delete to work, I added the following to the SpecificType model:
public function beforeDelete($cascade) {
// Make sure the parent method runs.
$continue = parent::beforeDelete($cascade);
if ($continue) {
// Delete the Type if there is one.
$typeId = $this->field('type_id');
if (!empty($typeId)) {
$continue = $this->Type->delete($typeId);
}
}
return $continue;
}
I hope that helps someone who has the same problem you had as I'm sure you're not still waiting for an answer.
Related
I have a problem with associations. I have two tables : Companies and Users.
User hasOne Company and Company belongsTo User (OneToOne)
In my models, I wrote :
/* User.php Model */
public $hasOne = array(
'Company' => array(
'className' => 'Company',
'dependent' => true
)
);
/* Company.php Model */
public $belongsTo = array(
'User' => array(
'className' => 'User',
'dependent' => true
)
);
My problem : when I do
$this->Company->delete($id, true)
in my CompaniesController, the Company with the id $id is deleted but the User associated is not.
Could you help me?
There is no 'dependent' option in belongsTo, so the only one actually working is the other way around.
If you delete a User, it will delete it's Company.
Basically, deleting a parent can delete it's dependent children. But deleting a child can't delete it's "dependent" parent (since there's really no such thing in Cake's case of a "dependent parent").
More details here: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
You could choose to run the association in both directions (requiring a field in each table to determine which it belongs to). That way, regardless of which you delete, it should always also delete the other.
Or, you could just delete the User that owns the company.
I just confused because of a find() result. This is my configurations:
First, users can have different User.role values: student, admin, and some others.
// Book
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id'
'conditions' => array('User.role' => 'student')
);
);
When I chain Models like $this->Book->Student->find('list'); I was expecting to get only users whose role are 'student', but instead, it gets all users. What is going on here, what is conditions for on association definition, where can it and cannot be used. Any lead would help, thanks.
PS: I am aware that I could put conditions on find(), that's not the issue
There is a difference between associated data and accessing an associated model object. If you access $this->Book->Student you're accessing the Student model and work in it's scope. The conditions in the defined associations work only in the context of the accessed object.
So if you do a find on the Book and list the students for that book:
$this->Book->find('first', array('contain' => array('Student'));
Your code will work correctly. It will find the book plus the first user who has the role stundent. BUT your association is wrong then: It should be hasMany. because why would you filter a book by role if the book just belongsTo one student?
If you want to filter users by their role you can implement a query param that is checked in beforeFind(), pseudocode: if isset roleFilter then add contention to filter by that role from roleFilter.
Or, if you don't need to paginate just create a getStudents() method in the user model that will return a find('list') that has the conditions.
Or Student extends User and put the filter in the beforeFind() and use that model instead of the User model in your Book association.
If you want to filter on model level or per model I think the last one is a good option. Don't forget to set $useTable and $name or the inherited model will cause problems.
you have miss , inside your model.
try this:
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id', //<------ miss
'conditions' => array('User.role' => 'student')
);
);
Yoi can debug your query to check what is the real query that you make.
Personally I have never use this approach, I prefer to use foreign key with another table for examples Rolesand User.role_id.
Is better for me to use this approach to have more flexibility inside your app.
After I prefer to use a conditions where inside controller to check well the query, because in your way every query you search always for student role not for the other and can be a problem for the rest of role, because inside controller you see a find without conditions but it doesn't take right value because in your model there is a particular conditions.
For me the good way is to create a new table, use foreign key and where conditions inside action of the controller to view well what are you doing.
For default all relations are "left join", you must set the parameter "type" with "inner" value
// Book
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id'
'conditions' => array('Student.role' => 'student'), // <-- Fix That (field name)
'type' => 'inner', // <-- add that
);
);
My CakePHP Cart model/table has only one field: id.
It hasMany LineItems.
I am not having success saving the Cart model alone:
$this->Cart->create();
$this->Cart->save();
Or, by passing it a $data array structured as follows and using saveAssociated():
$data = array(
'Cart' => array(),
'LineItem' => array(
array(
'item_id' => $item_id,
'qty' => $qty,
'price_option_id' => $price_option_id
)
)
);
If I add a useless_field to the Cart table/model, and pass some data in it saves. So obviously the problem lies in my having a model with a table with just a single id field and not passing in any other data to save. It won't create what it must be assuming is an 'empty' record.
I have passed 'validate' => false into the saveAssociated call but it doesn't make a difference (and there are no validations for this model to ignore).
Is there a way to do this? Am I missing something? Please enlighten me!
CakePHP tables require created and modified fields, or for you to define your own fields (ie you can call them whatever you want but they do the same thing).
In this instance you would use
$this->Cart->set($data);
$this->Cart->saveAll();
Here is Yet another cakePHP question! I have table called blood_groups which has blood_group_id and group fields.. Then I have another table called donors, which has several fields such as name, surname etc. Another field included inside this table is the foreign key 'blood_group_id' which will need to map to the blood_group table on retrieval. in the donor registration view, i want to be able to retrieve the values from the blood_groups table, and display them using the formHelper (with their respective id's).
I have gone through CAKE doc, and I understand that I would need to create the association between my models, but I am struggling to figure this one out. Should I create $hasOne association inside the Donor Model (considering that the Donor table has the fk of the other table). And how would I go about retrieving the options of blood_groups from the blood_groups Model?
Should It work like this?(and are any other prerequisites involved?) :
In my DonorController -
$this->set('blood_groups', $this->Donor->Blood_Group->find('all'));
in Views/Donor/add.ctp
echo $this->Form->input('blood_group_id');
Accessing data through associations is fine. But for radios or checkboxes you want to do a find('list). Your model and variable name does not match the CakePHP convention, there should be no underscore.
Properly named this should be already enough to populate the input.
// controller
$this->set('bloodGroups', $this->Donor->BloodGroup->find('list'));
// view
echo $this->Form->input('blood_group_id');
If you don't follow the conventions for some reason:
echo $this->Form->input('blood_group_id', array(
'options' => $bloodGroups
));
See:
Linking Models Together
The Form Helper
Create one function in BloodGroup Model
function getDonors(){
$options = array(
// 'conditions' => array('Donor.blood_group_id'=>$id),
'joins' => array(
array(
'alias' => 'Donor',
'table' => 'donors',
'type' => 'LEFT',
'conditions' => array(
'Donor.blood_group_id = BloodGroup.blood_group_id',
),
)
),
'fields' => array('Donor.name','Donor.surname','Donor.blood_group_id',
'BloodGroup.blood_group_id')
);
$returnData = $this->find('all',$options);
return $returnData;
}
Now from controller call this function
App::import('model','BloodGroup');
$BloodGroup = new BloodGroup;
$donorList = $BloodGroup->getDonors();
$this->set('donorList',$donorList);
In view file you will get list of donors in $donorList.
I want to be able to delete a User, but a User has a Manager:
var $belongsTo = array(
'Manager' => array(
'className' => 'User',
'foreignKey' => 'manager_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
And whenever a User is deleted, all of it's "children" are deleted too.
For example, say I delete User A. User A is the manager of users B, C, and D. When A is deleted, so are B, C, and D, because they have A as their manager_id.
So my question is - is this supposed to be happening? And is there a way I can prevent this from happening?
Thanks!
Read the book, that is intended behavior and you can stop it by adding
'dependent' => false,
to the associations configuration array.
See http://book.cakephp.org/1.2/en/view/78/Associations-Linking-Models-Together and search for "dependent" on this page.
And I recommend you to use 2.0 if it's a new project, 1.2 is deprecated for a long time now.
It was an ACL issue - totally unexpected. Since our users operate in a tree structure with the Manager, the User has a lft and rght field that is only updated in the afterSave. The easy solution is to dissociate the user by setting their lft and rght to 0, but after deeper thought, I am setting their manager_id to NULL and saving it so that the tree reorganizes itself (via the afterSave).
Wow. That was quite the problem.