Laravel - где последнее отношение = «вручную» - PullRequest
4 голосов
/ 14 февраля 2020

У меня есть потенциальная возможность модели, статус которой «принадлежит» через таблицу lead_has_status.

Я хочу получить все потенциальные возможности, где последний (текущий) статус этого отведения - «ручной».

Я пробовал это

$leads = Lead::whereHas('statuses', function ($query) use ($q) {
  $query->where('description', 'LIKE', '%' . $q . '%');
})->get();

Но, так как Лид все еще имеет свои старые статусы, связанные с ним, он возвращает каждый Лид, который в какой-то момент имел Статус «ручной». Но я хочу только тех потенциальных клиентов, у которых текущий статус «ручной». Поэтому я хочу сделать что-то вроде

$leads = Lead::whereLast('statuses', function ($query) use ($q) {
  $query->where('description', 'LIKE', '%' . $q . '%');
})->get();

или

$leads = Lead::whereLast('statuses', function ($query) use ($q) {
  $query->latest()->first()->where('description', 'LIKE', '%' . $q . '%');
})->get();

(я знаю, что это не способ сделать это, просто просто express, что я пытаюсь do)

Надеюсь, вопрос имеет смысл, я сейчас очень запутался.

Ответы [ 3 ]

3 голосов
/ 14 февраля 2020

AFAIK нет встроенной красноречивой функции, которая дает вам такое поведение. Если вы хотите решить эту проблему только с SQL, вам придется посмотреть на другой ответ, используя SQL function MAX в подзапросе, и добавить необработанные запросы в Laravel code (возможно, немного эффективнее, чем отказ от несоответствия) .

Однако вы можете отфильтровать свою коллекцию после извлечения и отклонить элементы, которые не соответствуют вашим критериям.

Предполагая переменную $q имеет тип string и содержит состояние, например «manual», что-то вроде этого должно сделать работу (код не проверен).

$leads = Lead::whereHas('statuses', function ($query) use ($q) {
    $query->where('description', 'LIKE', '%' . $q . '%');
})
->with('statuses')
->get()
->reject(function($element) use($q) {
    $lastStatus = $element->statuses[count($element->statuses)-1];
    return (strpos($lastStatus->description, $q) === false);
});

Если вы столбец description должен содержать точное Строка "manual" Я бы сделал это вместо этого:

$leads = Lead::whereHas('statuses', function ($query) {
    $query->where('description', 'manual');
})
->with('statuses')
->get()
->reject(function($element) {
    $lastStatus = $element->statuses[count($element->statuses)-1];
    return $lastStatus->description !== 'manual';
});

Метод whereHas не удалит любые отношения, которые вам нужны. Метод whereHas только скажет «выбрать записи, у которых есть один или несколько дочерних элементов, соответствующих этому критерию», однако все дочерние записи будут доступны, даже если они не соответствуют вашим критериям, если поскольку у родителя есть тот, который соответствует.

То, что вы хотели бы сказать, это "выберите записи, у которых есть один или несколько дочерних элементов, которые соответствуют этому критерию (whereHas), ТО удалите всех родителей где последняя дочерняя запись не соответствует записи, которую я ищу (reject) "

Редактировать: обновлен код с использованием ->with('statuses') для повышения производительности.

1 голос
/ 14 февраля 2020

Мое решение состоит в том, чтобы определить новые отношения в таблице Lead.

class Lead extends Model
{
    public function lastStatus()
    {
        return $this->statuses()->latest()->limit(1);
    }
}

Таким образом, окончательный запрос может быть немного проще.

$leads = Lead::whereHas(‘lastStatus’, function ($query) use ($q) {
    $query->where(‘description’, ‘LIKE’, $q);
}
1 голос
/ 14 февраля 2020

Похоже, у вас уже есть отличный ответ Laravel, но в случае, если вы в конечном итоге выберете опцию нативного запроса, которую затем можете гидрировать, вот необработанный вариант sql ... По крайней мере, я надеюсь, это поможет вам визуализировать то, что вы пытаетесь достичь.

CREATE TABLE leads (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `info` varchar(100) NULL default NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE statuses (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `leads_id` int(11) null default null,
  `description` varchar(100) NULL default NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `leads` (`info`) VALUES ('foo'), ('bar'), ('test');

INSERT INTO `statuses` (`leads_id`, `description`) VALUES
(1, 'manual'),
(1, 'auto'),
(1, 'auto'),
(2, 'auto'),
(2, 'auto'),
(2, 'manual'),
(3, 'manual'),
(3, 'manual'),
(3, 'manual');

SELECT l.*
FROM statuses s 
JOIN leads l ON l.id = s.leads_id
WHERE s.id IN (
    SELECT MAX(s.id)
    FROM leads l
    JOIN statuses s ON s.leads_id = l.id
    GROUP BY l.id
)
AND s.description LIKE '%manual%'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...