Is it possible to custom the delete on cascade of CakePHP? - cakephp

I have a table with logs related to the Post ones and i dont want its data to be deleted when i delete a Post.
In the other hand, i want to delete all the comments of the Post as well as other data.
I have been taking a look at the documentation but they dont say anything about it:
http://book.cakephp.org/2.0/en/models/deleting-data.html
Thanks.

You can do this in at least two different ways.
On is when you're calling $this->Post->delete($id, $cascade) the second parameter is a boolean that shows if the delete operation should also remove any associated records - such that depend on a Post record:
$this->Post->delete($id, false);
Will not delete any associated records. This is also true for $this->Model->deleteAll();This is when you want to set it not globally.
Depends is very important because this concept could also be set in the configuration of a hasMany or hasOne relation so that this is the default deletion behaveour:
public $hasMany = array(
'Log' => array(
'className' => 'Log',
'foreignKey' => 'post_id',
'dependent' => false
)
);
In this example, Log records will NOT be deleted when their associated Post record has been deleted.

You can try removing the association before calling the delete using $this->Post->unbindModel('hasMany' => 'Log') (or $this->unbindModel('hasMany' => 'Log'inside Post model.)

If your back end is MySQL, you can switch off foreign key checks (SET FOREIGN_KEY_CHECKS=0;), remove the parent Post and its comments, and re-enable foreign key checks (SET FOREIGN_KEY_CHECKS=1;). I don't recommend this however.
I'd be inclined to implement a 'soft delete' on posts (give it a 'deleted' field and add an index to it which you set to true when it's deleted) and update your front end queries to ignore any posts with deleted = 1
There are a few soft delete behaviors out there but the code is pretty simple to implement.

Related

How to work with temporary tables defined with prepared statements in cakePHP 3.x

I'm working with cakePHP 3.7
I'd like to create a temporary table from a controller, and then use it (with some conditions and joins) to search some data to be displayed.
The table structure is for the moment statically defined, i.e. the fields it has are fixed, so I'm able to define an entity or a set of fields.
The content, though, varies with the user input. This means I want to define the table with a prepared SQL statement, whose variables I will bind to user input.
I know how to handle prepared statements.
But I've not understood yet precisely what's the correct way to proceed, to let cakePHP create my temporary table and load a model for it.
I've found a useful answer by #ndm at CakePHP 3: Best Practice for Temporary SQL Tables
and, in the tries I've made, I've specified the setTemporary(true) for the table.
Yet I keep getting "table doesn't exist" exceptions, so I suppose I'm not structuring the project classes and code correctly.
I can't create the table, as #ndm suggests, by using queries got with
$schema->createSql($connection);
because the sql is dependent to the user input.
Other found stackoverflow answers are about older versions of cakePHP (2.x) which are different from 3.x
Could someone please give me some more detailed hints about which is the way to create and use temporary tables, created with prepared statements, from within my cakePHP project?
Solved this way:
I've created a table in the database corresponding to my desired temporary table
I've run the cake bake model command to let cakePHP generate the entity and the table class
I've dropped the table from the DB
in the controller:
4.a I've prepared and executed the statement to create the temporary table
4.b I've loaded the model and used it
The issue I had was (what a shame!) a typographical error, because at a certain moment in a join query I used the name of the model instead of the name of the table in the conditions array.
I.e. I was asking wrongly for:
->join([
'table' => 'tempLogs',
'type' => 'INNER',
'conditions' => 'tempLogs.Job = Istanze.Job',
])
instead of the correct:
->join([
'table' => 'temp_logs',
'type' => 'INNER',
'conditions' => 'temp_logs.Job = Istanze.Job',
])
temp_logs is the temporary table name, TempLogs is the name of the table class

One Way One-To-One Association in CakePHP

I have an idea of how to do this but it doesn't seem like proper convention. I have a Submission model and a Revision model each with their similarly named tables. Each Submission can have one or more Revisions associated to it in a $hasMany relationship. The Revision model hence has a $belongsTo relationship linking back to the Submission.
In addition to having this relationship, the Submission model needs to have another association (called activeRevision) to a particular Revision in a $hasOne style of relationship. However, the $hasOne type requires the foreign key to be in the Revision table. I want it to be in the Submission table, so I don't need to query all of the Submission's Revisions to find the active one. I realized just specifying a $belongsTo relationship in the Submission would do what I want, but this feels wrong to me as now the two models "belong to eachother".
Is there a better way to go about this?
I wouldn't worry too much because of the 'naming' of the relation. By having the foreign key of the Revision inside the Submission table, CakePHP is, in fact, right that you've created a 'belongsTo' relation.
Although not strictly the 'right' (?) relation, in this situation, this looks like it's an easy way to achieve what you want. Just be sure to add an additional condition to your relation to prevent that a revision of another submission can be set as the current revision, i.e.;
public $belongsTo = array(
'Revision' => array(
'conditions' => array(
'Revision.submission_id = Submission.id',
)
)
);
However, make sure to add a proper comment in your code to prevent confusion if you're (or somebody else is) looking at your code in a later stage. (e.g. "note: using belongsTo relation, because its easier to maintain)
If you really want to convert it to a hasOne relation, you'll have to add an additional column to the 'Revisions' table, for example 'is_curreny_revision'. However, you will also need to be sure that only one revision of a submission can be set to be the current revision.
If you're using PostgreSQL, this can be achieved using a 'partial unique' index (see this question on StackOverflow; PostgreSQL: Conditional unique constraint). MySQL does not support partial indexes, so you're out of luck there

CakePHP Models with associated conditions

I have three models that are as follows:
Location hasMany SportType hasMany Sport, then
Sport belongsTo SportType belongsTo Location
In the SportType model, the belongsTo Location has a condition 'Location.status' => true, such that it only retrieves records where the Location status is true. Works fine.
When retrieving records via a plain old find() in the Sport model, I would assume that it would not return records where the associated SportType's associated Location was false, but that is not the case.
I believe I could use containable behavior or explicitly constructed joins in my controller to get what I want, but I'm wondering if this is something I can achieve purely through the model relationships. Perhaps not.
You can either use Joins or change the model you're doing the search on and do it through the restricting model (ie Location).
$this->Location->find('all', array(
'conditions' => array(
'Location.status' => true
),
'contain' => array(
'SportType' => array(
'Sport'
)
)
));
But you cannot narrow the results of the searching model based on conditions within contained models.
Update:
Joins also allow you to add more conditions to other models...etc, as opposed to Contain which does not, so I supposed I'd lean toward going with Joins as that leaves you more flexibility moving forward.
Also, a JOIN will do one more-complicated query, while a contain will do many simpler queries... so depending on your database structure, that could be considered.
Bottom line, it's preference - both are just fine and whichever works for you is great.

CakePHP automatically remove associated items

this may be a rookie question for CakePHP but here it goes
I design 3 models with associations:
'Client' hasMany 'Invoice' hasMany 'Item'
So when we do a read from Client, it will automatically grab related Invoices.
What if we try to delete a Client, is there a way so that CakePHP will automatically delete all related entries in 'Invoice' and subsequently all related entries in 'Item' ?
Yes, if the association is declared as dependent.
See http://book.cakephp.org/view/1043/hasMany.

CakePHP hasAndBelongsToMany (HABTM) Delete Joining Record

I have a HABTM relationship between Users and Locations. Both Models have the appropriate $hasAndBelongsToMany variable set.
When I managing User Locations, I want to delete the association between the User and Location, but not the Location. Clearly this Location could belong to other users. I would expect the following code to delete just the join table record provided the HABTM associations, but it deleted both records.
$this->Weather->deleteAll(array('Weather.id' => $this->data['weather_ids'], false);
However, I am new to CakePHP, so I am sure I am missing something. I have tried setting cascade to false and changing the Model order with User, User->Weather, Weather->User. No luck.
Thanks in advance for any help.
Not quite sure how Weather is related to your models, so I'll just go with the traditional names, LocationsUser is the joining table. This should delete all associations between the user with id $id and any locations:
$this->User->LocationsUser->deleteAll(array('LocationsUser.user_id' => $id), false);
Notice also that you're missing a closing bracket in your code snippet.

Resources