Laravel - Eloquent - Фильтр, основанный на последних отношениях HasMany. - PullRequest
0 голосов
/ 07 мая 2018

У меня есть две модели: Leads и Status.

class Lead extends Model
{
    public function statuses() {
        return $this->hasMany('App\LeadStatus', 'lead_id', 'id')
            ->orderBy('created_at', 'DESC');
    }

    public function activeStatus() {
        return $this->hasOne('App\LeadStatus', 'lead_id', 'id')
            ->latest();
    }


}

class LeadStatus extends Model
{
    protected $fillable = ['status', 'lead_id'];
}

Это работает нормально, теперь я пытаюсь получить все потенциальные возможности на основе «статуса» последнего LeadStatus.

Я пробовал несколько комбинаций, но безуспешно.

if ($search['status']) {
            $builder = $builder
                ->whereHas('statuses', function($q) use ($search){
                    $q = $q->latest()->limit(1);
                    $q->where('status', $search['status']);
                });
        }



 if ($search['status']) {
            $builder = $builder
                ->whereHas('status', function($q) use ($search){
                    $q = $q->latest()->Where('status', $search['status']);
                });
        }

Кто-нибудь делал это с Eloquent? Нужно ли писать какие-то необработанные SQL-запросы?

РЕДАКТИРОВАТЬ 1: я попытаюсь объяснить снова: D

В моей базе данных статус отведения не является отношением 1 к 1. Это потому, что я хочу получить исторический список всех статусов, которые имел Лидер.

Это означает, что при создании Lead создается первый LeadStatus со статусом «new» и текущей датой.

Если приходит продавец, он может изменить статус ведущего, но это НЕ обновляет предыдущий LeadStatus, вместо этого он создает новый связанный LeadStatus с текущей датой и статусом «открыто».

Таким образом, я вижу, что Лид был создан 05/05/2018, и что он изменился на статус "открыт" 05.05 2018.

Теперь я пытаюсь написать запрос, используя eloquent, который учитывает только последний статус, связанный с Lead.

В предыдущем примере, если я отфильтрую по потенциальному запросу со статусом «новый», этот потенциальный запрос не должен отображаться, так как к настоящему времени он имеет статус «открытого».

Надеюсь, это поможет

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Попробуйте это:

Lead::select('leads.*')
    ->join('lead_statuses', 'leads.id', 'lead_statuses.lead_id')
    ->where('lead_statuses.status', $search['status'])
    ->where('created_at', function($query) {
        $query->selectRaw('max(created_at)')
            ->from('lead_statuses')
            ->whereColumn('lead_id', 'leads.id');
    })->get();

Решение с использованием первичного ключа (от Borjante):

    $builder->where('lead_statuses.id', function($query) {
        $query->select('id')
            ->from('lead_statuses')
            ->whereColumn('lead_id', 'leads.id')
            ->orderBy('created_at', 'desc')
            ->limit(1);
    });
0 голосов
/ 24 января 2019

У меня была такая же проблема, и я опубликовал мое решение здесь , но я думаю, что стоит опубликовать повторно, поскольку это улучшает возможность повторного использования. Это та же идея, что и принятый ответ, но избегает использования объединений, которые могут вызвать проблемы, если вы хотите установить отношения загрузки или использовать его в области.

Первый шаг включает добавление макроса к запросу Builder в AppServiceProvider.

use Illuminate\Database\Query\Builder;

Builder::macro('whereLatestRelation', function ($table, $parentRelatedColumn) 
{
    return $this->where($table . '.id', function ($sub) use ($table, $parentRelatedColumn) {
        $sub->select('id')
            ->from($table . ' AS other')
            ->whereColumn('other.' . $parentRelatedColumn, $table . '.' . $parentRelatedColumn)
            ->latest()
            ->take(1);
    });
});

Это в основном делает часть подзапроса принятого ответа более общей, позволяя вам указать таблицу соединений и столбец, к которому они присоединяются. Он также использует функцию latest(), чтобы избежать прямой ссылки на столбец created_at. Предполагается, что другой столбец является столбцом id, поэтому его можно улучшить еще больше. Чтобы использовать это, вы сможете:

$status = $search['status'];
Lead::whereHas('statuses', function ($q) use ($status) {
    $q->where('status', $userId)
        ->whereLatestRelation((new LeadStatus)->getTable(), 'lead_id');
});

Это та же логика, что и принятого ответа, но немного проще для повторного использования. Это будет, однако, немного медленнее, но это должно стоить повторного использования.

0 голосов
/ 07 мая 2018

Если я правильно понимаю, вам нужно / хотите получить всех потенциальных клиентов с определенным статусом.

Так что вы, вероятно, должны сделать что-то вроде этого:

    // In your Modal

    public function getLeadById($statusId)
    {
        return Lead::where('status', $statusId)->get();
        // you could of course extend this and do something like this:
        // return Lead::where('status', $statusId)->limit()....->get();
    }

По сути, я делаю где и возвращаю каждое лидерство с определенным идентификатором.

Затем вы можете использовать эту функцию в вашем контроллере следующим образом:

Lead::getLeadById(1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...