【问题标题】:How to force Laravel Eloquent to play nicely with a query which returns no results?如何强制 Laravel Eloquent 很好地处理不返回结果的查询?
【发布时间】:2015-03-23 05:45:45
【问题描述】:

我在我的一个模型中将数据库查询设置为范围查询,在某些情况下可能不会返回任何结果,这样做完全没问题:

public function scopeLastFromLaunchSite($query, $site) {
    return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
        $q->where('name',$site);
    })->orderBy('launch_order_id','DESC')->first();
}

这个函数的调用方式很简单:

Mission::LastFromLaunchSite('someSite');

如果结果中至少有一行,则此查询非常好,但是一旦没有,它就会返回一个非常冗长的 Builder 对象,其中充满了递归,这实际上使我的浏览器。

我的问题是……

如何检测到这一点并简单地返回 false"No results were found." 之类的内容?

我尝试过的...

我尝试使用firstOrFail() 方法代替first(),但这只是返回一个ModelNotFoundException,这给了我两个解决方案:

  1. App:errorglobal.php 中处理它。这是不可取的,因为没有返回结果不是错误。只是众多可能结果中的一种。

  2. 在每个方法中捕获异常,这会导致代码重复。我实际上也无法让它工作。我尝试using ModelNotFoundException 类并抓住它,但它永远不会被抓住:

    use Illuminate\Database\Eloquent\ModelNotFoundException;
    
    // ...
    
    try {
        //my query
    } catch (Illuminate\Database\Eloquent\ModelNotFoundException $e) {
        return false;
    }
    
    // otherwise, return as normal
    

当对我的模型的查询未返回任何结果时,我如何才能简单地返回 false 或一些虚假值,而不是简单地打印出这个冗长的错误?

【问题讨论】:

  • 你如何调用这个函数?
  • 已添加到问题中。

标签: php mysql exception laravel eloquent


【解决方案1】:

范围不应该返回查询结果,这就是为什么你会得到永无止境的递归或其他错误,具体取决于你的代码。

将范围更改为:

public function scopeLastFromLaunchSite($query, $site) {
    $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
        $q->where('name',$site);
    })->orderBy('launch_order_id','DESC');
}

然后就地执行它:

$result = $yourQuery->lastFromLaunchSite($site)->first();

// then do whatever you need with the result
return ($result) ?: 'nothing found!';

说明:作用域不需要返回值。如果 scopeWhatevermethod returns anything that evaluates totrue`,那么它将替换基本查询,否则返回查询本身。也就是说,如果您希望返回单个模型,但没有行匹配条件,那么您会意外得到查询对象。

你也可以这样做(我不会,但它也可以):

public function scopeLastFromLaunchSite($query, $site) {
    $row = $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
        $q->where('name',$site);
       })->orderBy('launch_order_id','DESC')->first();

    return $row ?: 'nothing found!';
}

但是您需要期待Modelstring 并相应地调整您的代码以避免可能的Trying to get property of non-object 错误。

【讨论】:

    【解决方案2】:

    这里的问题是你没有像 Laravel 想要的那样使用范围。 Laravel 实际上并不期望您实际在范围内执行查询。它是一个应用过滤器的工具。因此,当您的作用域函数返回 NULL(或任何虚假值)时,Laravel 无论如何都会返回当前的 Builder 对象:

    Illuminate\Database\Eloquent\Builder

    protected function callScope($scope, $parameters)
    {
        array_unshift($parameters, $this);
    
        return call_user_func_array(array($this->model, $scope), $parameters) ?: $this;
    }
    

    这里有三个解决方案:

    1。使用异常(但在您的控制器中)

    我不太喜欢这个,但这是可能的。使用firstOrFail 并在您的控制器中执行此操作:

    try {
        $result = Mission::LastFromLaunchSite('someSite');
    } catch (Illuminate\Database\Eloquent\ModelNotFoundException $e){
        $result = null;
    }
    

    2。使用范围权

    不要在范围内执行查询,而是在您的控制器中执行:

    public function scopeLastFromLaunchSite($query, $site) {
        return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name',$site);
        })->orderBy('launch_order_id','DESC');
    }
    

    用法:

    Mission::LastFromLaunchSite('someSite')->first();
    

    3。只需在您的模型中添加一个正常功能即可

    public static function LastFromLaunchSite($site){
        return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name',$site);
        })->orderBy('launch_order_id','DESC')->first();
    }
    

    用法:

    Mission::LastFromLaunchSite('someSite');
    

    【讨论】:

      【解决方案3】:

      我从来没有做过这样的事情,但我首先想到的是……。喜欢:

      public function scopeLastFromLaunchSite($query, $site) {
          $retVal = $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
              $q->where('name', $site);
          })->orderBy('launch_order_id', 'DESC');
      
          if ($retVal->count() > 0) {
              return $retVal->first();
          }
      
          return "No results found";
      }
      

      【讨论】:

      • 您不需要调用两次查询。只需检查结果是否为true
      猜你喜欢
      • 2020-02-18
      • 1970-01-01
      • 1970-01-01
      • 2019-10-09
      • 2015-01-08
      • 1970-01-01
      • 2020-09-24
      • 2021-03-02
      • 2018-10-22
      相关资源
      最近更新 更多