简体   繁体   English

Laravel检查约束是否违反

[英]Laravel check for constraint violation

I was curious if there is a way we can check if there is a constraint violation error when delete or insert a record into the database. 我很好奇,是否有一种方法可以在删除记录或将记录插入数据库时​​检查是否存在约束冲突错误。

The exception thrown is called 'QueryException' but this can be a wide range of errors. 引发的异常称为“ QueryException”,但这可能是多种错误。 Would be nice if we can check in the exception what the specific error is. 如果我们可以检查异常的具体错误,那就太好了。

You are looking for the 23000 Error code (Integrity Constraint Violation) . 您正在寻找23000 Error code (Integrity Constraint Violation) If you take a look at QueryException class, it extends from PDOException , so you can access to $errorInfo variable. 如果您看一下QueryException类,它是从PDOException扩展的,因此您可以访问$errorInfo变量。

To catch this error, you may try: 要捕获此错误,您可以尝试:

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 (...)'

To be more specific (Duplicate entry, not null, add/update child row, delete parent row...), it depends on each DBMS: 更具体地说(重复条目,不为null,添加/更新子行,删除父行...),它取决于每个DBMS:

  • PostgreSQL and SQL server follow the SQL standard's conventions for SQLSTATE code, so you may return the first value from the array $e->errorInfo[0] or call $e->getCode() directly PostgreSQLSQL Server遵循SQL标准的SQLSTATE代码约定,因此您可以从数组$e->errorInfo[0]返回第一个值,或直接调用$e->getCode()
  • MySQL , MariaDB and SQLite do not strictly obey the rules, so you need to return the second value from the array $e->errorInfo[1] MySQLMariaDBSQLite并不严格遵守规则,因此您需要从数组$e->errorInfo[1]返回第二个值。

For laravel, handling errors is easy, just add this code in your "app/start/global.php" file ( or create a service provider ): 对于laravel,处理错误很容易,只需将以下代码添加到您的“ app / start / global.php”文件中(或创建一个服务提供商 ):

App::error(function(\Illuminate\Database\QueryException $exception)
{
    $error = $exception->errorInfo;
    // add your business logic
});

You may also try 您也可以尝试

try {
       ...
    } catch ( \Exception $e) {
         var_dump($e->errorInfo );
    }

then look for error code. 然后寻找错误代码。

This catches all exception including QueryException 这捕获了所有异常,包括QueryException

first put this in your controller 首先把它放在你的控制器中

use Exception;

second handle the error by using try catch like this example 第二个通过使用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');
            }

New updates here without need to use try catch you can easily do that in validation rules as the following code blew 此处的新更新无需使用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');
    }
}

where id related to record which you edit. 与您要编辑的记录相关的ID。

You can add the following code in app/start/global.php file in order to print the exception 您可以在app / start / global.php文件中添加以下代码以打印异常

App::error(function(QueryException $exception)
{
  print_r($exception->getMessage()); 
 });

check this part in the documentation 在文档中检查此部分

If you are using Laravel version 5 and want global exception handling of specific cases you should put your code in the report method of the /app/Exception/Handler.php file. 如果您使用的是Laravel version 5并且希望对特定情况进行全局异常处理,则应将代码放在/app/Exception/Handler.php文件的report方法中。 Here is an example of how we do it in one of our micro services: 这是我们如何在其中的一个微服务中执行此操作的示例:

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

The Response class we use is a simple wrapper of Symfony\\Component\\HttpFoundation\\Response as HttpResponse which returns HTTP responses in a way that better suits us. 我们使用的Response类是Symfony\\Component\\HttpFoundation\\Response as HttpResponse的简单包装, Symfony\\Component\\HttpFoundation\\Response as HttpResponse ,它以更适合我们的方式返回HTTP响应。

Have a look at the documentation , it is straightforward. 看一下文档 ,很简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM