Репозитории и DRY

107
06 мая 2021, 10:00

вопрос по репозиторям, их аналогам и DRY. Берем простой пример:

$articles = $articleRepository->getByCategory(Category $category); 

По правилам хорошего кода, нужно указывать поля для выборки, никак не * . В одном месте может понадобиться 2 поля, в другом 3, в третьем вообще только id. И тут возникает проблема, как это организовать по DRY и без проблем с неймингом ? Ведь это явно не вариант:

$articles = $articleRepository->getFullListByCategory(Category $category);
$articles = $articleRepository->getShortListByCategory(Category $category);

Или Передавать поля в виде массива вторым параметром?

$articleRepository->getByCategory(Category $category, array $columns = ['id','name']);

А если будет разница только в сортировках? Или Limit? Причем ладно тут запрос будет легкий. А представим какой-нибудь сложный запрос, у которого будут только order by в конце отличаться, или поля select. Это же будет большое количество повторений, да и проблемы с неймингом.

getByCategoryIdAsc(), getByCategoryIdDesc(), getByCategoryIdAscNameDesc()

Как на счет варианта ко всем малоотличающимся запросам добавлять возможность объекта Criteria который устанавливает простые правила select, order, offset, limit?

$criteria =  (new Criteria())->select(['id','name'])->orderBy('id','asc');
$articles = $articleRepository->getByCategory(Category $category, criteria);  

Или это нарушает правила репозитория?

Answer 1

На мой взгляд, задача репозитория - отдать данные по запросу, который не имеет отношения к реализации самого репозитория. SQL это или может быть простое файловое хранилище, или может быть из конфига что берет.

Когда вы составляете подобные criteria - вы как будто пишете sql, что означает только одну реализацию репозитория.

Подавляющее большинство репозиториев в наших проектах выглядят примерно так:

interface IRepository
{
  public function getItem($filter = null);
  public function getList($filter = null);
  public function getCount($filter = null);
  ...
}

То есть есть лишь один метод для получения одного элемента, один метод для получения списка и тд. Есть конечно исключения.

$filter - это параметры выборки, включает "человекопонятные" условия. Может быть объект или массив или что-нибудь еще.

Как применить эти условия - решает репозиторий внутри себя.

Пример использования:

$articles = $articleRepository->getList([
  'category' => $category
]);
$articles = $articleRepository->getList([
  'category' => $category,
  'sort' => 'asc'
]);
$articles = $articleRepository->getList([
  'category' => $category,
  'another_field' => $value,
  'sort' => 'superspecialsort', // в репозитории строится супер ORDER BY
  'limit' => 20,
  'dataset' => 'short' // репозиторий знает какие это поля
]);

Переданный фильтр строится для всех методов, getItem, getList, getCount и тд.

Не сильно вижу смысл перечислять какие вам поля нужно от репозитория. Только если в табличке есть очень тяжелые поля которые вам не нужны, но в этом случае можно обойтись dataset=short|full. Если вам нужны только 2 поля, то вы просто их потом и используете.

READ ALSO
Call to undefined function Wordpress

Call to undefined function Wordpress

Есть функции внутри плагина(save,get_data,get_image)В файл категория

83
Как отобрать пропуски значений чисел по порядку в массиве?

Как отобрать пропуски значений чисел по порядку в массиве?

Есть массив такого видаОн содержит числа меньшего к большему

89
php base64 decode image

php base64 decode image

Использую Symfiny 4, получаю uploaded files $files = $request->files->get('file');

87
Symfony 4 не работает сервис контейнер

Symfony 4 не работает сервис контейнер

Создаю сервисный класс App\Http\OpenWeather Пишу в servicesyml типа того

101