2. Data driven design (а може MVC?)
Не заморочуємся щодо бази даних
ЮІ повинно якомога меньше містити бізнес-логіки
Тримати всі наші слої такими як задумувалося
Замінити в будь-який час будь-який рівень
9. Постановка завдання
Cоціальна мережа для поціновувачів літератури надає своїм
користувачам зручний розширений пошук, який містить такі
поля, як:
ISBN
назва (точна або частково точна)
автор твору
видавець
рік видання (перевидання)
...
10. Реалізація даного функціоналу
Створити форму з великою кількість UI елементів під кожен з
критеріїв;
Прийняти запит на пошук від користувача у вигляді GET або
POST
Провалідувати кожен з цих пошукових критеріїв
У разі валідності запиту передати список цих критеріїв на
рівень нижче і вибрати дані з БД
...
11.
12. Целі
знизити до нуля дублювання коду
максимально наблизитись до SOLID, розбиваючи код на
невеликі і абсолютно прозорі шматки функціоналу
домогтися реюзабельності написаного коду в інших
частинах програми
забезпечити максимальну простоту додавання нових
критеріїв, а також внесення змін в обробку існуючих
повністю абстрагуватися від персістентного сховища (БД та
ін)
14. Що отримаємо?
довге полотно коду форми і сервісу
валідація даних на рівні сервісу
велика кількість залежностей у випадку складних критеріїв
відсутність будь-якої гнучкості - а що якщо завтра доведеться
підключити в цю схему Sphinx або інший пошуковий движок
а що робити якщо таку ж фільтрацію потрібно застосувати для масиву
(колекції) books, без участі репозиторію - знову доведеться дублювати
код
непрозорість інтерфейсу функції findAll() - ми не дізнаємося які можуть
бути $ params, якщо явно не заліземо в код сервісу
...
16. Кусень коду
use DomainBookFilter as BookFilter;
/// ....
$filter = new BookFilterChain();
$filter->appendFilter(new BookFilterIsbn('978-5-8459-1597-9'))
->appendFilter(new BookFilterTitle('Domain Driven', BookFilterTitle::CONTAINS))
->appendFilter(new BookFilterPublisher('Вильямс', BookFilterPublisher::EQUALS))
->appendFilter(new BookFilterPrice(100, 10.000))
->appendFilter(new BookFilterEbook(true));
// фантазування на тему вітаються
// ...
$bookCollection = $bookSearchService->findAllByFilter($filter);
17. Використання фільтрів на рівні
репозиторію
Перевірити, що фільтр реалізує потрібний інтерфейс і може
бути використаний;
Перевірити, що поточний користувач має право на
фільтрацію об'єктів у сховищі;
Знайти потрібний репозітрій і передати цьому репозиторію
фільтр.
Функції сервісу
18. Рефлекції, медіатор, QueryBuilder
Структура сховища інкапсулюється в невеликих і легко
тестованих об'єктах, відокремлена від фільтрів та сервісу
Ми можемо використовувати кілька різних варіантів
технічної реалізації вибірки, просто додавши новий
QueryBuilder зі своїми рефлекціями (наприклад, додати
Sphing SE Query Builder)