Я хочу создать поток уведомлений на главной странице приложения. Прямо сейчас у меня есть модели для новостей, встреч и презентаций. Я хочу объединить эти элементы в один объект, возможно, под названием «События», чтобы затем взять 5 последних событий и отобразить их на главной странице. Результат будет примерно таким:

News Article: Submissions open starting April 1
Presentatiion: How to do stuff, the PDF
Meeting: April 15, Foo High School Gymnasium

Все объекты реализуют интерфейс, который требует getTitle, getBody и getCreationDate, поэтому эти функции доступны для каждого объекта.

Я не хочу просто объединять коллекции, так как это становится беспорядочным. Есть ли способ объединить эти объекты в один объект?

2
KinsDotNet 11 Май 2016 в 16:27

2 ответа

Лучший ответ

Похоже на классический случай наследования. Вы можете создать модель под названием Event.

class Event extends Model

Тогда ваши упомянутые классы расширили бы событие.

class Article extends Event
class Presentation extends Event
class Meeting extends Event

Затем вы можете создать собственный метод для класса Event. Я думаю, что в вашем случае было бы проще написать простой SQL, чем возиться с Eloquent, если вы хотите избежать слияния коллекций.

public function getUpcomingEvents()
{
    // something like that, you get the idea
    return DB::select('
        (SELECT title, body, CreationDate FROM articles LIMIT 5)
        UNION 
        (SELECT title, body, CreationDate FROM meetings LIMIT 5)
        ORDER BY CreationDate DESC LIMIT 5')->get();
}

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

1
Tadas Paplauskas 11 Май 2016 в 13:53

Я собираюсь пойти против того, что сказал @Tadas, и скажу, что Eloquent по-прежнему может быть лучшим вариантом, используя полиморфизм. Таким образом, все ваши события могут быть в одной таблице, легко выбираемой, а затем ваши модели могут содержать любую специальную информацию, которая вам нужна.

Настройте свои таблицы следующим образом:

event
    title
    body
    creation_date
    eventable_id
    eventable_type

news
    some_other_field1

meeting
    some_other_field2

И ваши модели:

class Event extends Model
{
    /**
     * Get all of the owning imageable models.
     */
    public function eventable()
    {
        return $this->morphTo();
    }
}

class News extends Model
{
    /**
     * Get all of the staff member's photos.
     */
    public function events()
    {
        return $this->morphMany('App\Event', 'eventable');
    }
}

class Meeting extends Model
{
    /**
     * Get all of the product's photos.
     */
    public function events()
    {
        return $this->morphMany('App\Event', 'eventable');
    }
}

Этот метод поможет вам несколькими способами:

  1. Получать события действительно легко. Хотите, чтобы впереди следующие 5 событий? Event::where('event_date', '=>', new DateTime('today'))->orderBy('event_date', 'asc')->take(5);
  2. Легко получайте ближайшие события для разных моделей многоразовым способом:

    News:whereHas('events', function($query) {
        $query->where('event_date', '=>', new DateTime('today'))->orderBy('event_date', 'asc')->take(5);
    })->get();
    
  3. Вы также получаете преимущество наследования, когда у вас могут быть разные поля во всех ваших моделях, но базовая модель Event может содержать всю вашу общую информацию. А когда вам нужна информация о модели из объекта события, вы просто вызываете $event->eventable-><whatever field you need>

  4. Никаких сырых запросов не требуется. Просто продолжайте использовать обычный синтаксис Laravel для всего.

3
Samsquanch 11 Май 2016 в 17:09