Как организовать и реализовать разделение проблем и хорошее ООП с помощью растущего списка запросов по всему моему приложению?

Где разместить растущий список запросов (в основном все запросы «SELECT») и как правильно обращаться к ним по всему моему приложению?
Я пытаюсь повторно учесть мое приложение, в котором на данный момент есть запросы, разбросанные по всем службам в моем приложении. Я начинаю сталкиваться с проблемами СУХОГО, когда у меня есть маленькие и большие запросы, которые похожи на другие запросы, которые я уже написал. У меня также есть места, где я снова и снова переписываю одинаковое форматирование для этих запросов. Хотя я не беспокоюсь о замене своего выбора базы данных, я беспокоюсь о дальнейшей оптимизации моих запросов и удивляюсь, не сделал ли я это почти невозможным, не организовав лучше все свои запросы и не оставив их где-то в центре. Я хочу следовать хорошей практике OOP и SoC.

Пример того, где у меня в данный момент есть запрос в моем приложении
Например, у меня есть служба, которая предоставляет PDF (или, скорее, контент) всем сотрудникам на определенном мероприятии. У службы есть метод, который принимает некоторые входные данные (например, «сортировка», «фильтр», «предел разбиения на страницы») и будет выполнять запрос с 10 объединениями таблиц (запрос нарезается довольно хорошо до управляемого количества строк перед большей частью СОЕДИНЕНИЯ работают над этим) и форматируют результаты желаемым способом для PDF.

Что я запланировал до сих пор
У меня возникают проблемы, когда я пытаюсь идеально подумать о потребностях моей базы данных с точки зрения объектов. Я делаю много гибких запросов, не все нерегулярные, но широкий диапазон SELECT с большим количеством JOIN и WHERE, но я стараюсь изо всех сил:

  1. Доменные объекты: Я буду создавать классы как usersEntity, eventsEntity (каждая таблица соответствий в моей базе данных) и настройки свойств в них, как id,name,phone,так далее. которые соответствуют полям таблицы базы данных. Я могу создавать методы получения / установки, чтобы я мог мутировать (форматировать такие вещи, как даты и т. Д. Или выполнять проверку). Я мог бы создать сущности, которые на самом деле не представляют собой единую таблицу в моей базе данных, но, возможно, представляют собой общую коллекцию данных, которые, как мне кажется, я многократно использую в своем приложении. Может быть, позвоните usersCollection или же usersEvents,

  2. Data Mapper:
    Поэтому я поставил все CUD (Создать обновление Удалить … не читать … кроме, может быть, findById) операции и хранить их в классах, называемых usersMapper, eventsMapper, и так далее. Сопоставители принимают только один тип объекта домена (см. № 1 выше) и будут обрабатывать постоянство (и, возможно, небольшой набор очень простых операций чтения / выбора, таких как findById($id) или же findByEvent($eventId)).

Теперь это оставляет меня с растущим списком операций чтения (запросы SELECT) и где их разместить?

Варианты, которые мне известны, но не дотягивают. Может быть, я их неправильно понимаю.

Допустим, у меня есть такой запрос

ВЫБЕРИТЕ users.first_name, users.last_name, events.name, events.date, venues.name,
venue_types.name, GROUP_CONCAT (user_friends.last_name) как «друзья»
ОТ пользователей
СОЕДИНЕНИЕ событий включено (events.id = users.event_id AND events.date =: date)
ПРИСОЕДИНЯЙТЕСЬ и т.д ....

Так что я вижу в блогах всего сообщества PHP 3 варианта:

  1. Заменить мои запросы запросов чем-то вроде Doctrine2 звонки. Их DQL, кажется, не делает вызов повторно используемым? И кажется, что все связано таким образом, что оно вернулось бы как 5 сущностей (на основе JOIN) со всеми свойствами, заполненными для пользователей, событий, мест, типов мест, друзей. Это много полей, которые мне не нужны, я просто хотел по 1 столбцу от каждого, как вы можете видеть в моем запросе выше. Кроме того, я не планирую сохранять какие-либо объекты после такого запроса.
  2. Заменить все мои запросы запросов вместилище классы, которые имеют такие методы, как: $someUserRepo->
    findNameAndEventNameAndEventDateAndVenueNameAndVenueTypeNameAndFriends()
    , Помимо действительно сумасшедшего названия метода, я не уверен, что я передаю здесь (условия как: Сортировать, предел, немного где?) или что я возвращаю (массивы? объекты?).

  3. Заменить все мои запросы запросов ORM звонки (как Eloquent Laravel) с использованием их построителей запросов. Я не вижу, как я получил что-то, заменив мой SQL-запрос please->ORM->build->this->for->me->where->andWhere->andWhere->I->dont->know->SQL, Кстати, я почти уверен, что ORM — это анти-паттерн?

Я подозреваю, что это очень сложная проблема для всего сообщества PHP. Или что мне здесь не хватает?

2

Решение

Используя хранилище это единственный вменяемый вариант, который вы рассматривали.

Вот что ты мог сделать.

Определить интерфейс репозитория

Этот интерфейс будет описывать, как вы запрашиваете определенные объекты.

interface Events
{
/**
* @return Event[]
*/
public function findUserEvents(User $user, $sort, $limit, array $filters = []);
}

или возможно:

interface Events
{
/**
* @return Event[]
*/
public function findUserEvents(User $user, Query $query);
}

class Query
{
private $sort;
private $limit;
private $filters = [];

// methods
}

Реализовать интерфейс

Используйте все, что вам нравится для реализации интерфейса — Doctrine, Eloquent, простой SQL — все, что вам удобно.

use Doctrine\ORM\EntityRepository;

class DoctrineEvents implements Events
{
private $entityRepository;

public function __construct(EntityRepository $entityRepository)
{
$this->entityRepository = $entityRepository;
}

/**
* @return Event[]
*/
public function findUserEvents(User $user, $sort, $limit, array $filters = [])
{
// query $this->entityRepostory and return a collection of Event objects
}
}

Кроме того, вы можете ввести EntityManager вместо EntityRepository.

Только для того, чтобы показать вам, как легко обеспечить альтернативные реализации, вот реализация SQL:

class SqlEvents implements Events
{
private $pdo;

public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}

/**
* @return Event[]
*/
public function findUserEvents(User $user, $sort, $limit, array $filters = [])
{
// use $this->pdo to query the database
// you'll need to convert results into a collection of Event objects
}
}

Легко. Для тестов вы можете предоставить реализацию в памяти.

Положитесь на интерфейс

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

class MyController
{
private $events;
private $view;

public function __construct(Events $events, View $view)
{
$this->events = $events;
}

public function listAction(Request $request)
{
$user = // ...

$events = $this->events->findUserEvents($user, 'ASC', 10);

return $this->view->render('list.html', ['events' => $events]);
}
}

В этом примере MyController может работать с любой реализацией События интерфейс. Это не волнует, если это доктрина, красноречивый или sql.

Выберите реализацию

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

0

Другие решения

Других решений пока нет …