Sergey Ilichev, в симфони возможно добавить валидацию в dto - просто там механизм валидации можно записать а уровне специальных докблоков поверх каждого свойства (validation constraints из Validator Component) и вроде там еще doctrine annotations нужно установить) получается в дто можно написать правила валидации и в контроллере вызвать валидатор для проверки данных в дто. Если использовать argument resolver/param converter, то вызов валидатора "переедет" в эти классы, а до контроллера "долетит" уже валидная дто со всеми данными
Слава, полезно будет подтянуть паттерны, прочесть чистую архитектуру, чистый код мартина... Еще PoEAA (у меня она в планах). Лично у меня после года ковыряния ее кода ентузиазма уже не так много)
И нужно много курсов на симфоникастс пересмотреть, чтобы увидеть бестпрактисы на ней
Написание подлерживаемого кода на симфони с доктриной тянет за собой огромный пласт компетенции как разработчика, плюс экосистема на симфони не настолько легкая и обновляемая, чтобы можно было выбирать пакеты не глядя, нужно дописывать решения или анализировать существующие. Платят за компетенцию, а использование симфони идет как следствие. Сильно выше платят только симфони миддл+ и синьорам, у миддлов разница зарплат не такая существенная
А в каком окружении Вы наблюдаете этот баг? Просто у меня очень похожая ситуация была с Messenger на SF4, php7.3 и ручным запуском консьюмера. Strace тогда ничего особо ценного не показал. Выяснилось, что консьюмер фризится только в штормовском терминале)
Anton B., нет, не подзапросы, я про то что у ивентов могут быть много подписчиков, и нужно в них что-то менять, когда процесс изменений прозрачен для всего запроса.
Про то, как делать валидацию до попадания в контроллер, я в прошлом ответе добавляла ссылку про ArgumentResolver.
tommy-vercetti, а отсутствие сваггера/апи блупринта это всегда жирный минус? это не карго культ?
UPD. Хотя я неправа, проще описать доку прямо в коде и генерировать на лету, чем делать это другими способами, просто еще не дошла до автоматизма в этом вопросе))
Anton B.,
по поводу валидации - ValidationHelper - тут больше проблема в том, что название хелпера наталкивает на то, что это глобальный хелпер, а внутри он решает конкретную задачу. Обычно стараются создать промежуточный класс для Request (например как ArgumentResolver или DTO класс, чтобы там описать список параметров, через аннотации констрейнтов описать проверки валидации, и в нужный момент проверить все валидатором). На худой конец можно просто взять все параметры в экшене и провалидировать через Validator на месте, но выделять для этого хелпер это не в стиле симфони. LogicValidation - этот класс лежит рядом, но он совсем не использует Validator, хотя эти ограничения тоже можно описать через него. Просто чисто интуитивно напрягают два стиля реализации. ValidationHelperInterface - интерфейс здесь неоправдан, потому что ValidationHelper решает частную проблему, низкая вероятность что понадобится такой же класс с такими же сигнатурами методов.
ScheduleRequestSubscriber - валидация это не зона ответственности реагирования на ивент. Для валидации есть другие слои/способы и этапы - до попадания данных в экшен контроллера или уже внутри него, получается что при использовании ивентов эти процессы могут пойти параллельно, а не последовательно. В доке написано (ссылка) - "Overall, the purpose of the kernel.request event is either to create and return a Response directly, or to add information to the Request (e.g. setting the locale or setting some other information on the Request attributes).".
По поводу Day, Time, TimeRange и фабрик для них - если объяснить их не как оверинжиниринг, то можно сказать что это premature optimization для проекта с минимумом логики. Я сама попадала много раз в эти ловушки, потому что хочется обернуть все в объекты, чтобы не писать лапшу "как в прошлый раз". Все лишние классы и интерфейсы потом приходится перекраивать, поэтому если наблюдаются высокоуровневые абстракции по DDD там, где этого не было в ТЗ или где бизнес-логика еще не разрослась так, чтобы их однозначно оправдать, то это засчитывают как минус, а не плюс
Anton B.,
2) тут больше было замечание что public методы чередуются с private, нужно группировать их так, чтобы одна группа была в первой части, а другая во второй (обычно private смещают вниз), как дополнительное действие можно было вынести их в базовый класс, потому что приватные методы достаточно общи для всей потенциальных экшенов контроллеров.
6) замечание было в том, что классы нужно группировать по зоне ответственности - многие классы являются сервисами в том или ином смысле, но это как базовое множество, а у подмножества конкретные задачи. Нп. от того, что Entity и Repository относятся к работе с хранилищем, то никто не скидывает их в папку Persistence) они остаются в основном неймспейсе. Если вынести их в модуль, то распределять их можно в пространстве модуля. Это может быть вкусовщина, но это более привычный путь в симфони проектах.
9) если это часть шаблона то вопрос отпадает, но тогда как проверяющему хотелось бы видеть все классы в отдельном модуле, а не в сервисах на одном уровне со всем остальным, и обозначить как-то, что это все единая реализация шаблона Builder, потому что на код ревью не хочется вспоминать академическую реализацию шаблона)) Если ревьюер загружает себе ветку в IDE вовремя код ревью, то он еще может догадаться, но если смотреть код только в браузере то внимание рассеивается, нужно делать более однозначно. Папка сервисов может быстро превратиться в свалку хелперов, если заранее четко не выделять структуру, что к чему относится
10) лучше разбить на несколько провайдеров или передавать массив с набором данных вместо строгого количества агрументов, потому что из кода это неочевидно. Меня тоже напрягло, что переменные без названия передаются, но при этом не используются
4) EntityRepository Data Mapper
Репозиторий не должен знать, откуда берутся данные, он должен получать адаптер для дерганья апи хранилища. Работа с чтением из файла напрямую в этом слое это наружение SRP. В Doctrine DBAL даже нет поддержки чтения чисто из файла (Platforms), можно было спарсить данные и загнать в SQLite. Текущий подход в тестовом можно бы было принять, если это был просто тестовый проект без симфони и без доктрины, просто репозиторий как условный класс
Роман Тонкошкуров, возможно для инфрастукрутных контейнеров другие практики (можно объединять несколько сервисов в один контейнер), но для отдельных контейнеров можно описать общий docker-compose, а список команд для его поднятия записать как набор команд в Makefile или bash-скрипте, и другому человеку достаточно будет вписать пару переменных окружения в один файлик и сделать запуск команды как второе действие (т.е. тоже действий минимум, но больше по-феншую)
jenya_zhilin, WHERE A.year = '$year' AND B.id_user = '$id_user'
у Вас точно типы данных A.year и B.id_user это строки?) Если нет, то не нужно добавлять кавычки вокруг значений.
Покажите структуру обеих таблиц
rPman, ну не знаю, Никита Попов не из тех, в чьей компетенции стоит сомневаться) и если почитать сорсы, то абстракций минимально необходимое количество