Laravel 查询异常可以绕过 try-catch 吗?

7

我正在使用Laravel 4和Eloquent ORM。在我的系统中,当有人删除一条记录时,必须检查它是否有任何关联的记录。如果没有,那么可以永久删除。但是如果有,就执行软删除。

处理这种情况的方式是:尝试forceDelete,如果由于引用完整性而抛出异常,则捕获它并进行softDelete。我知道这看起来很花哨,但它是由另一个开发人员制作的,我不想改变他的代码。

他所做的是删除,然后如果抛出异常,只需设置一个标志来“停用”记录。它确实运行良好。但是,当我接手后,我实施了softDeleting以使事情不那么花哨。

现在,当它尝试forceDelete时,它会抛出QueryException但不会进入catch块。我已经尝试将Exception更改为\Exception,QueryException,Illuminate\Database\QueryException,但没有成功。有什么想法吗?

为了更好地说明:

它就像这样:

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

现在是这样的:

protected $softDelete = true;

....

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

Firebug 响应:

{"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}}

这是Illuminate/Database/Eloquent/Builder.php中的forceDelete()函数:
    public function forceDelete()
{
    return $this->query->delete();
}

如果你正在使用Laravel 4.2版本,软删除的工作方式已经发生了变化 - 请参考这里:http://laravel.com/docs/upgrade。但是如果你不是在使用这个版本,那么很抱歉我不知道原因。 - Joel Hinz
让它抛出一个异常,它应该告诉你它正在抛出什么异常。你只需能够复制粘贴它。 - user1669496
@user3158900 对不起,我没听懂。你能具体说明一下吗? - Gustavo Silva
运行它,应该会在浏览器中输出错误页面,并且错误页面应该包含抛出的异常。你只需将其复制粘贴到Exception的代码中。例如,在这个页面http://filp.github.io/whoops/demo/上,它显示的是`RuntimeException`,所以你可以在`try/catch`块中使用`catch(RuntimeException)`来捕获它。你能否也张贴一下你的`forceDelete()`函数,或许有一个潜在的问题导致了这些异常。如果查询有问题,那么这也无关紧要。 - user1669496
它没有输出,因为它是一个 AJAX 请求。我已经更新了问题,并附上了 Firebug 的响应。 - Gustavo Silva
显示剩余3条评论
1个回答

4

您的$contact->forceDelete();将调用Illuminate\Database\Eloquent\Model中的方法,该方法具有以下代码

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;
}

现在发生的情况是你的代码将在上面的$this->delete();处出现错误并抛出异常。
所以它到达了你的catch,然后你再次调用$contact->delete();。这样它又得到了另一个QueryException,而$this->softDelete从未被设置为true
你需要做的是重新设置软删除并尝试再次删除它:
try
{
    $contact->forceDelete();
}
catch(Exception $ex)
{
    $contact->softDelete = true;
    $contact->delete();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接