Laravel QueryException bypassing try-catch?

I am using Laravel 4 and Eloquent ORM. On my system, when someone deletes a record, he needs to check if she has any related records. If this is not the case, it may be permanently deleted. But if so, just do softDeletion.

The way to handle this situation is as follows: try to force delete, and if it throws an exception due to referential integrity, catch it and softDelete. I know this looks awkward, but it was done by another developer, and I would prefer not to interfere with his code.

What he did was delete, and then if he threw an exception, just set the flag to "inactivate" the record. This worked well. However, when I took over, I implemented softDeleting to make things less tricks.

Now, when he tries to force delete, he throws a QueryException, but does not fall into the catch block. I tried changing Exception to \ Exception, QueryException, Illuminate \ Database \ QueryException, but without success. Any ideas?

To illustrate this better:

It was like this:

try { $contact->delete(); } catch(Exception $ex) { $contact->status = 0; $contact->save(); //this works } 

And now it’s something like this:

 protected $softDelete = true; .... try { $contact->forceDelete(); } catch(Exception $ex) { $contact->delete(); //this doesn't work } 

Firebug answer:

 {"error":{"type":"Illuminate\\Database\\QueryException","message":"SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`tst_db\/contact_company`, CONSTRAINT `fk_contact_company_contacts_id` FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE) (SQL: delete from `contacts` where `id` = 28)","file":"\/Applications\/XAMPP\/xamppfiles\/htdocs\/application\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Connection.php","line":555}} 

This is the forceDelete () function from Illuminate / Database / Eloquent / Builder.php:

  public function forceDelete() { return $this->query->delete(); } 
+6
source share
1 answer

Your $contact->forceDelete(); will call a method in Illuminate\Database\Eloquent\Model , which has the following code :

 public function forceDelete() { $softDelete = $this->softDelete; // We will temporarily disable false delete to allow us to perform the real // delete operation against the model. We will then restore the deleting // state to what this was prior to this given hard deleting operation. $this->softDelete = false; $this->delete(); $this->softDelete = $softDelete; } 

Now what happens, your code will be an error on $this->delete(); higher and throw an exception.

So, it reaches your catch , and you call $contact->delete(); again. This way it gets another QueryException , without $this->softDelete ever returning to true .

What you need to do is install soft deletion and try again:

 try { $contact->forceDelete(); } catch(Exception $ex) { $contact->softDelete = true; $contact->delete(); } 
+3
source

Source: https://habr.com/ru/post/971066/


All Articles