Laravel QueryException в обход try-catch?

Я использую Laravel 4 и красноречивый ORM. В моей системе, когда кто-то удаляет запись, он должен проверить, существуют ли связанные записи. Если это не так, то он может быть удален навсегда. Но если это так, просто выполните softDeletion.

способ обработки этой ситуации: попробуйте forceDelete, и если он выдает исключение из-за ссылочной целостности, поймайте его и softDelete. Я знаю, что это выглядит трюком, но это было сделано другим разработчиком, и я бы лучше не связываться с его кодом.

то, что он сделал, было удалить, а затем, если он бросил исключение, просто установите флаг "инактивировать" запись. Это сработало хорошо. Однако, когда я взял на себя, я реализовал softDeleting, чтобы сделать вещи менее трюковыми.

теперь, когда он пытается forceDelete, он бросает QueryException но не попадает в блок catch. Я попытался изменить исключение на Exception, QueryException, IlluminateDatabaseQueryException, но безуспешно. Любой идеи?

чтобы проиллюстрировать это лучше:

было так:

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":"IlluminateDatabaseQueryException","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}}

это функция forceDelete () из Illuminate/Database/Eloquent/Builder.на PHP:

    public function forceDelete()
{
    return $this->query->delete();
}

1 ответов


код $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();
}