7

I am using Laravel 4, and the Eloquent ORM. In my system, when someone deletes a record, it has to check if it has any associated records. If it doesn't, then it may be deleted permanently. But if it does, just perform a softDeletion.

The way that this situation is being handled is: try to forceDelete, and if it throws an Exception because of the referential integrity, catch it and softDelete. I know this looks gimmicky, but it was made by another developer and I'd rather not mess with his code.

What he did was to delete, then if it threw an Exception, just set a flag to "inactivate" the record. It did work well. However, when I took over I implemented softDeleting to make things less gimmicky.

Now, when it tries to forceDelete,it throws the QueryException but doesn't fall into the catch block. I've tried changing Exception to \Exception, QueryException, Illuminate\Database\QueryException, but no success. Any ideas?

To illustrate it better:

It was like this:

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

And now it is like this:

protected $softDelete = true;

....

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

Firebug response:

{"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();
}
8
  • If you're using Laravel 4.2, the way soft deletion works has changed - see here: laravel.com/docs/upgrade. But if you're not, then I'm afraid I don't know the cause. Commented Jun 19, 2014 at 16:57
  • Let it throw an exception and it should tell you what exception it's throwing. Should just be able to copy and paste that. Commented Jun 19, 2014 at 17:02
  • Nope. It's Laravel 4.1. But thanks for your help! Commented Jun 19, 2014 at 17:03
  • @user3158900 I'm sorry, I didn't understand. Can you be more specific? Commented Jun 19, 2014 at 17:03
  • Run it and then it should output the error page in the browser and the error page should contain the exception that was thrown. You should just be able to copy and paste that into your code where Exception is. For example on this page filp.github.io/whoops/demo it's showing RuntimeException so you'd catch it with catch(RuntimeException) in your try/catch block. Can you also post your forceDelete() function as well, maybe there is an underlying issue which is throwing these exceptions. If the query is bad, this won't matter anyway. Commented Jun 19, 2014 at 17:06

1 Answer 1

4

Your $contact->forceDelete(); will call the 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 happen is your code will error on $this->delete(); above and throw an exception.

So it reaches your catch, and so you call $contact->delete(); once more. So it gets another QueryException, without $this->softDelete ever set back to true.

What you need to do is set soft delete back and try delete it again:

try
{
    $contact->forceDelete();
}
catch(Exception $ex)
{
    $contact->softDelete = true;
    $contact->delete();
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.