Область действия Laravel с использованием рассчитанного значения - PullRequest
0 голосов
/ 28 сентября 2018

У меня следующая проблема в 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());

Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 28 сентября 2018

Спасибо, ребята, за ваши быстрые ответы.Я понял это, используя другой подход, основанный на ваших идеях.Поскольку я не могу использовать вычисляемые поля в запросе, я вернулся к полю, которое действительно существует в БД, это renewalDueDate, то есть год с даты платежа;обе известные и фиксированные даты.Затем в запросе я передаю $ 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 ▼ # элементов: массив: 2 [▼ 0 => 83 1=> 6]}

Конечно, вы также можете передать $ friendsDaysRemaining вместо $ user, но это также далеко от элегантности.

Еще раз спасибо.

0 голосов
/ 28 сентября 2018

Вы можете передать переменную в область, например, вы можете определить область следующим образом:

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, если это более удобно использовать в вашем случае.

0 голосов
/ 28 сентября 2018

С помощью API, который вы определили для себя:

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

Ваш метод scopeActive не сможет увидеть связанные переменные User и friendsDaysRemaining, необходимые для вычисления даты истечения срока действия.Вы можете попробовать это сами:

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
}

На вашем месте я бы, вероятно, пошел с постоянным столбцом expiration_date в таблице memberships и обновил бы его при необходимости.Это позволит вам сделать что-то вроде:

public function scopeActive($query) {
    return $query->where('expiration_date', '>', Carbon::now());
}
0 голосов
/ 28 сентября 2018

У вас есть две проблемы:

  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();
}
...