Проверка Laravel на нарушение ограничений
Мне было любопытно, есть ли способ проверить, есть ли ошибка нарушения ограничения при удалении или вставить запись в базу данных.
Исключенное исключение называется QueryException, но это может быть широкий диапазон ошибок. Было бы неплохо, если бы мы могли проверить исключение, какова конкретная ошибка.
Ответы
Ответ 1
Вы ищете 23000 Error code (Integrity Constraint Violation)
. Если вы посмотрите на QueryException
класс, он простирается от PDOException
, поэтому вы можете получить доступ к переменной $errorInfo
.
Чтобы поймать эту ошибку, вы можете попробовать:
try {
// ...
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
// Example output from MySQL
array (size=3)
0 => string '23000' (length=5)
1 => int 1452
2 => string 'Cannot add or update a child row: a foreign key constraint fails (...)'
Чтобы быть более конкретным (Duplicate entry, not null, add/update child row, delete parent row...), это зависит от каждой СУБД:
- PostgreSQL и SQL-сервер следовать стандартные соглашения SQL для кода
SQLSTATE
, поэтому вы можете вернуть первое значение из массива $e->errorInfo[0]
или вызвать $e->getCode()
непосредственно
- MySQL, MariaDB и SQLite не строго соблюдают правила, поэтому вам нужно вернуть второе значение из массива
$e->errorInfo[1]
Для laravel, обработка ошибок проста, просто добавьте этот код в свой файл "app/start/global.php" (или создайте поставщик услуг):
App::error(function(\Illuminate\Database\QueryException $exception)
{
$error = $exception->errorInfo;
// add your business logic
});
Ответ 2
Вы также можете попробовать
try {
...
} catch ( \Exception $e) {
var_dump($e->errorInfo );
}
затем найдите код ошибки.
Это улавливает все исключения, включая QueryException
Ответ 3
сначала поместите это в свой контроллер
use Exception;
второй обработать ошибку с помощью try catch, как в этом примере
try{ //here trying to update email and phone in db which are unique values
DB::table('users')
->where('role_id',1)
->update($edit);
return redirect("admin/update_profile")
->with('update','update');
}catch(Exception $e){
//if email or phone exist before in db redirect with error messages
return redirect()->back()->with('phone_email','phone_email_exist before');
}
Новые обновления здесь без необходимости использовать try catch, вы можете легко сделать это в правилах проверки, так как следующий код испортился
public function update(Request $request, $id)
{
$profile = request()->all();
$rules = [
'name' => 'required|unique:users,id,'.$id,
'email' => 'required|email|unique:users,id,'.$id,
'phone' => 'required|unique:users,id,'.$id,
];
$validator = Validator::make($profile,$rules);
if ($validator->fails()){
return redirect()->back()->withInput($profile)->withErrors($validator);
}else{
if(!empty($profile['password'])){
$save['password'] = bcrypt($profile['password']);
}
$save['name'] = $profile['name'];
$save['email'] = $profile['email'];
$save['phone'] = $profile['phone'];
$save['remember_token'] = $profile['_token'];
$save['updated_at'] = Carbon::now();
DB::table('users')->where('id',$id)->update($save);
return redirect()->back()->with('update','update');
}
}
где id относится к записи, которую вы редактируете.
Ответ 4
Вы можете добавить следующий код в файл app/start/global.php, чтобы распечатать исключение
App::error(function(QueryException $exception)
{
print_r($exception->getMessage());
});
проверьте часть в документации
Ответ 5
Если вы используете Laravel version 5
и хотите глобальную обработку исключений для конкретных случаев, вы должны поместить свой код в метод report
в файле /app/Exception/Handler.php
. Вот пример того, как мы делаем это в одном из наших микро сервисов:
public function render($request, Exception $e)
{
$response = app()->make(\App\Support\Response::class);
$details = $this->details($e);
$shouldRenderHttp = $details['statusCode'] >= 500 && config('app.env') !== 'production';
if($shouldRenderHttp) {
return parent::render($request, $e);
}
return $response->setStatusCode($details['statusCode'])->withMessage($details['message']);
}
protected function details(Exception $e) : array
{
// We will give Error 500 if we cannot detect the error from the exception
$statusCode = 500;
$message = $e->getMessage();
if (method_exists($e, 'getStatusCode')) { // Not all Exceptions have a http status code
$statusCode = $e->getStatusCode();
}
if($e instanceof ModelNotFoundException) {
$statusCode = 404;
}
else if($e instanceof QueryException) {
$statusCode = 406;
$integrityConstraintViolation = 1451;
if ($e->errorInfo[1] == $integrityConstraintViolation) {
$message = "Cannot proceed with query, it is referenced by other records in the database.";
\Log::info($e->errorInfo[2]);
}
else {
$message = 'Could not execute query: ' . $e->errorInfo[2];
\Log::error($message);
}
}
elseif ($e instanceof NotFoundHttpException) {
$message = "Url does not exist.";
}
return compact('statusCode', 'message');
}
Класс Response
мы используем, представляет собой простую оболочку Symfony\Component\HttpFoundation\Response as HttpResponse
которая возвращает HTTP-ответы более Symfony\Component\HttpFoundation\Response as HttpResponse
для нас способом.