Создание моделей Laravel без таблиц базы данных

Пока я работал над пользовательским интерфейсом администратора для серверной части RESTful API, я столкнулся со следующей дилеммой: как заполнить панель администратора полезными статистическими данными?

Я думал о нескольких вариантах:

  1. Воспользуйтесь механизмом шаблонов и соберите необходимые данные напрямую (просто для полноты картины, поскольку этот вариант обычно в любом случае не подходит, хотя для небольших сайтов почему бы и нет?).
  2. Создайте отдельный контроллер с необходимыми классами действий и соберите информацию оттуда.
  3. ИЛИ создайте «пустую» модель на сервере и соберите информацию в виде вычисляемых полей в самой модели.

Поскольку запросы к серверной части через вызовы API обычно медленнее, чем запросы к базе данных (и в этом случае интерфейс администратора выполняет первое), я решил оставить тяжелую задачу на стороне серверной части.

Теперь, как вы делаете это с MVC, таким как Laravel?

К счастью, в Laravel модель Eloquent не обязательно должна поддерживаться таблицей базы данных (хотя именно так мы их используем большую часть времени).

Вы вполне можете определить новую модель без таблицы.

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

protected $table = null;

Но что будет содержать модель, если с ней не связаны фактические данные?

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

У Laravel уже давно есть геттеры и сеттеры. Они используются для извлечения данных и манипулирования ими, и они идеально подходят для создания нашей «пустой» модели.

Чтобы создать такой геттер, вам нужно добавить новый общедоступный метод в класс вашей модели, подобный этому (сеттеры не требуются в модели Summary):

public function getHighestVoteAttribute()
{
     $vote = Vote::with('question')
        ->orderByDesc('number_of_votes')
        ->limit(1)
        ->get()
        ->first();

     $keys = ['id', 'question_text', 'vote_text', 'number_of_votes'];

     return $vote 
        ? array_combine($keys, 
            [
              $vote->question->id,
              $vote->question->question_text,
              $vote->vote_text,
              $vote->number_of_votes
        ])
        : array_fill_keys($keys, null);
}

Пожалуйста, убедитесь, что вы следуете соглашениям об именах, используемым Laravel, так как они определяют, как вы можете обращаться к этому атрибуту позже (в данном случае — наивысшее_голосо).

Последний шаг — убедиться, что вычисляемые поля могут быть извлечены.

Самый простой способ — использовать защищенное свойство $appends:

protected $appends = [
   'number_of_answers',
   'number_of_questions',
   'highest_vote',
];

Все, что вы поместите в массив, будет добавлено к полученной модели при автоматическом запросе.

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

public function getSummary(Request $request)
{
    return response()->json(new Summary(), 200);
}

и получить его по такому маршруту:

$router->get('/summary', ['uses' => 'SummaryController@getSummary']);

Вы даже можете добавить специфические для модели маршруты для расчета специфической для модели статистики (например, /summary/votes).

Наслаждайтесь новой моделью Summary!