Запрос Laravel вложенные отношения [Laravel 6.x] - PullRequest
2 голосов
/ 22 декабря 2019

У меня есть страница в приложении Laravel, где я выбираю категории и с нетерпением жду загрузки событий в этой категории. Работает нормально. Что я хочу сделать сейчас, так это выбрать категории, но на этот раз выбрать события на основе региона / местоположения, выбранного пользователем. Это модели, с которыми я работаю;

1.Регион класса

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Region extends Model
{
    /**
     * Get events within region
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */

    public function events()
    {
        return $this->hasMany(Event::class);
    }
}

Категория Класс

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'category_name', 'description', 'type', 'slug'
    ];

    /**
     * Get all events that belong to a category
     *
     * @return Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function events()
    {
        return $this->hasMany(Event::class)->where('start_date', '>=', today())->orderBy('start_date', 'asc');
    }
}

3.Event

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
     /**
     * Get an event's category
     *
     * @return Illuminate\Database\Eloquent\Relations\BelongsTo;
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * Get region of event
     *
     * @return [type] [description]
     */
    public function region()
    {
        return $this->belongsTo(Region::class);
    }
}

Это запрос, который возвращает категории с событиями;

if (session()->has('region')) {
            $region_name = session()->get('region');

            $region = Region::where('region_name', $region_name)->firstOrFail();

            $categories = Category::withCount('events')
                                ->with('events')
                                ->whereHas('events', function (Builder $query) use ($region) {
                                    $query->where('region_id', $region->id);
                                })
                                ->orderBy('events_count', 'desc')
                                ->take(5)
                                ->get();
}

Сводка : Я хочу получить 5 лучших категорий с событиями в выбранном пользователем месте.

Заранее благодарен за помощь.

Ответы [ 2 ]

1 голос
/ 23 декабря 2019

Попробуйте это для запроса категорий:

$categories = Category::with(['events' => function ($query) use ($region) {
    $query->where('region_id', $region->id);
}])->take(5)->get();

Проверьте документацию по ограничению активных нагрузок

0 голосов
/ 22 декабря 2019

Вы смотрели на отношения hasManyThrough? https://laravel.com/docs/5.8/eloquent-relationships#has-many-through

Если вы дадите своей Region модели много Categories через Event класс:

public function categories()
{
    return $this->hasManyThrough('App\Category', 'App\Event');
}

Вы сможете позвонить:

$region->categories;

Который должен возвращать все категории, которые имеют события для этого региона. Затем вы можете загрузить события в каждой категории, отсортировать по количеству событий и взять первые 5, прежде чем выводить на экран.

Альтернатива

Альтернативой может быть просто получить все события, где region_id является выбранным регионом, и добавить groupBy для категории:

$eventsByCategory = Event::where('region_id', $selectedRegion)->groupBy('category_id);

Затем, когда у вас есть события, сгруппированные по категориям, вы можете отсортировать поподсчитайте и возьмите верхнюю 5.

$eventsByCategory->sort()->take(5);

Side Note:

Я буду осторожен с вашими отношениями событий на модели категории. Я думаю, что добавление where к возвращенному значению вернет экземпляр Builder, а не Relation, что означает, что вы не сможете использовать некоторые функции отношений. Вместо этого я бы посоветовал взглянуть на область действия модели Event, которую можно применять глобально или локально, в зависимости от того, как часто вы хотите получать прошедшие события.

...