【问题标题】:Laravel scope using calculated value使用计算值的 Laravel 范围
【发布时间】:2018-09-29 03:58:01
【问题描述】:

我在 Laravel 5.4 中遇到以下问题: 有一个用户表和一个成员表,其中一个用户可以有多个成员,一个成员属于一个用户。会员资格为年度期限,但会员每推荐一位在我的网站上注册的朋友,都会获得额外的免费天数,因此免费天数是不断变化的;这反过来又会更改会员资格的到期日期。 所以问题是:如果到期日期是一个变量,如何确定给定用户的活动成员资格? 我需要做这样的事情:

首先是Membership.php中的过期日期:

这会计算每个成员的总天数: 请注意,friendsDays 是在 User.php 中按用户计算的

public function getTotalDaysAttribute() {
        $days = $this->paidDays + $this->user->friendsDaysRemaining;
        return $days;
    }

这会计算每个成员的到期日期:

public function getExpirationDateAttribute() {
    $date = $this->startDay->addDays($this->TotalDays);
    return $date;
}

到目前为止一切顺利......现在,这就是我卡住的地方(伪代码):

public function scopeActive($query, $dateToCheck = Null) {
   $query->where($dateToCheck >= $this->expirationDate);
}

如何正确编码以获得:

dump($user->membership()->active()->get());

提前致谢。

【问题讨论】:

    标签: php laravel laravel-5 eloquent laravel-5.4


    【解决方案1】:

    你有两个问题:

    1. 您正在尝试在您的范围内使用模型值。范围发生在模型值设置之前。这是因为为了获取要设置的模型中的值,必须首先执行获取数据的查询。

    2. 很遗憾,由于您的数据库设计,您将无法创建一个范围来获得您想要的答案。这是因为您使用不同表上的值来计算您的 TotalDays 值。

    我建议你在数据库中更改expirationDate的值,并在邀请朋友时调用它。

    类似:

    function addDaysToExpiration(User $user) {
        $user->expirationDate = date('Y-m-d h:m:s', strtotime('2008-10-05' . '+1 day'));
        $user->save();
    }
    

    【讨论】:

      【解决方案2】:

      您可以将变量传递给范围,例如,您可以像这样定义范围:

      public function scopeActive($query, \Carbon\Carbon $dateToCheck = Null) 
      {
         $query->where('some_date_field',  '>=' ($expirationDate ?? now())->toDateTimeString());
      }
      

      然后你可以这样做:

      $dateToCheck = now()->addDays(30);
      
      dump($user->membership()->active($dateToCheck)->get());
      

      如果在您的情况下使用更方便,您也可以只将天数传递给范围而不是 Carbon 实例。

      【讨论】:

      • 对不起马辛;我原来的帖子有错误。这一行: $query->where($dateToCheck >= $expirationDate);应该是:$query->where($dateToCheck >= $this->expirationDate);。我已经纠正了。我遇到的问题是表中没有“some_date_field”可供比较,因为日期字段是使用上面编写的 scopeActive() 函数计算的。
      • 每个模型的$this->expirationDate 是否相同,并且所有模型都手动设置为例如'2018-05-23 08:12:23`?
      【解决方案3】:

      使用您为自己定义的 API:

      $user->membership()->active()->get();
      

      您的方法scopeActive 将无法看到计算到期日期所需的相关UserfriendsDaysRemaining 变量。你可以自己试试:

      public function scopeActive($query) {
         var_dump($this->id); // null
         var_dump($this->user); // null, this part will try to do the query: select * from users where id = null
      }
      

      在您的位置上,我可能会在 memberships 表上保留一个 expiration_date 列,并在需要时对其进行更新。然后,这将允许您执行以下操作:

      public function scopeActive($query) {
          return $query->where('expiration_date', '>', Carbon::now());
      }
      

      【讨论】:

        【解决方案4】:

        谢谢你们的及时回答。根据您的想法,我使用不同的方法解决了这个问题。由于我不能在查询中使用计算字段,所以我回到了数据库中确实存在的字段,即renewedDueDate,即从付款日期算起的一年;两者都是已知的和固定的日期。然后,在查询中,我将 $user 和 $dateToCheck 作为参数传递,减去剩余的朋友天数并与该值进行比较,如下所示:

        public function scopeActive($query, $user, $dateToCheck = Null) {
            // If no date is passed, use today()
            $dateToCheck = is_null($dateToCheck) ? Carbon::today() : Carbon::parse($dateToCheck);
        
            //Substract the friendsDaysRemaining from the dateToCheck
            $AdjustedEndDate = $DateToCheck->copy()->subDays($user->friendsDaysRemaining);
        
            //Build the query 
            $query  ->where('paid', 1) //its been paid for
                    ->where('startDay', '<=', $DateToCheck) //It has started
                    ->where('renewalDueDate', '>=', $AdjustedEndDate); //It has not expired
        
            return $query;
        }
        

        虽然必须通过用户才能获得剩余的朋友天数很麻烦,但现在可以正常工作:

        $dateToCheck= '2018-09-01';
        dump($user->membership()->active($user, $dateToCheck)->pluck('id'));
        

        结果:

        集合 {#299 ▼ #items: array:2 [▼ 0 => 83 1 => 6] }

        当然你也可以传递 $friendsDaysRemaining 而不是 $user,但也远非优雅。

        再次感谢。

        【讨论】:

        • 这是不久前的事了,但您能否接受自己的答案,以免人们对未回答的问题关注。干杯!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-04
        • 1970-01-01
        • 1970-01-01
        • 2011-06-16
        相关资源
        最近更新 更多