Laravel JSON API: Как создать собственный виртуальный ресурс из базы данных (для агрегированных значений)? - PullRequest
1 голос
/ 17 апреля 2020

с тех пор я пытаюсь выяснить, как добавить "виртуальный" ресурс в мой Laravel JSON API ("cloudcreativity/laravel-json-api": "~2.0"). Для объяснения:

Допустим, у меня есть записи времени в таблице базы данных и модель Eloquent, которая используется пакетом API JSON для автоматического преобразования его в ресурс, отображаемый в /api/v1/timerecords. Это отлично работает из коробки, просто добавив адаптер, схему и небольшую конфигурацию! Пример временных записей:

id | customer_id | user_id | ts_start | ts_end | hours | amount_xy | ...
1  | 123         | 5       | 2020-0...| 2020...| 4.5   | 95.2      | ...
2  | 987         | 5       | 2020-0...| 2020...| 2.75  | 32.8      | ...

Но теперь я хочу иметь конечную точку API /api/v1/timeaggregates с вычисленными значениями, такими как COUNT(id) AS num_records, SUM(hours) AS sum_hours, AVG(amount_xy) AS avg_xy, где эти записи могут быть агрегированы по различным параметрам (или фильтру, чтобы остаться в терминах API? !), например:

  • "Агрегированные значения между DATE-FROM и DATE-TO для CUSTOMER = 123"
  • "Агрегированные значения для CUSTOMER = 123"
  • "Совокупные значения для CUSTOMER = 123 и USER = 5"

Конечно, этот ресурс должен быть только для чтения (GET), потому что он "виртуальный". Но я не мог даже приблизиться к чему-либо работающему. Кроме того, поиск во всей сети ничего не дает, что еще больше удивляет меня, поскольку я считаю, что такая функция является довольно распространенной задачей для API, не так ли ?! Что я пробовал до сих пор:

  • Пытался создать Eloquent\Collection. Проблема в том, что я не смог где-то использовать эту коллекцию, поскольку есть только универсальный c JsonApiController.
  • Пытался использовать виртуальную модель ( jenssegers / laravel -model ), но API JSON ожидает получить модель Eloquent
  • . Из других структур я знаю шаблон Repository, в котором я реализую такие агрегатные функции, но Laravel, похоже, не реализует этот шаблон, и даже если бы я сделал это сам, опять же, где вызывать функции репозитория?
  • ... бесчисленное множество других попыток

Может быть, я упускаю что-то огромное здесь, или проблема возможно, используется пакет CloudCreativity, который не поддерживает такие вещи (опять же, это заставляет меня задуматься, поскольку пакет кажется очень профессиональным с отличной документацией).

Я бы оценил, если бы кто-то из вас мог дать мне Намек. Спасибо вперед!

1 Ответ

1 голос
/ 19 апреля 2020

Я создал какой-то уродливый обходной путь. Если есть более чистое решение, не стесняйтесь просветить меня ^^

Сначала я создал «виртуальную» модель, которая не является действительно виртуальной, поскольку я использую существующую таблицу «timerecords»:

class Timeaggregate extends Model {
    protected $table = 'timerecords';
}

В адаптере ресурсов я перезаписываю метод queryAll() для вычисления агрегированных значений:

    protected function queryAll($query, EncodingParametersInterface $parameters) {
        $this->with($query, $parameters);
        $this->applyFilters($query, collect($parameters->getFilteringParameters()));

        $query->selectRaw('COUNT(id) as count_records')
            ->selectRaw('SUM(hours) AS sum_hours');

        return $query->first();
    }

Чем в методе getAttributes () схемы ресурса я могу просто добавить вычисляемые поля в ответ с использованием, например, $resource->sum_hours.

. Другим решением может быть создание не красноречивого ресурса и выполнение запроса к базе данных вручную для заполнения необходимых атрибутов. Но я этого не проверял, поскольку обнаружил, что мои потребности настолько тесно связаны с реально существующим ресурсом, поэтому, по моему мнению, он все еще должен быть ресурсом Eloquent.

...