Все так, о чем и речь, нет смысла делать разделение ради разделения, архитектору нужно взвесить возможное развитие проекта. К примеру, кэш вероятно придется однажды заменить с Redis на Memcached — вероятный сценарий, но вряд ли кто-то и когда-то будет значительно менять поток получения данных пользователя user($id)
в контроллере, настолько, что придется подменять репозиторий или сервис, скорее всего смысл выносить логику в обычной жизни придется лишь тогда, когда захочется избежать повторения (скажем, если данные пользователя получаются разными действиями контроллера, нет смысла дублировать код, можно реализовать один метод getUser
). При этом, бизнес-логика (логика домена) как правило уже значительно разделена на слои фреймворком…
«В Вашем примере, видимо, UserRepository будет иметь методы addAddress($userId, $address), getAddress ($userId), saveUser($user, $address, $photos) или getUser($id, $fields) — чтобы получить пользователя с зависимыми сущностями»
ок. Допустим. Я лишь хочу напомнить, что Пользователь — это актор. На него примерно 99.9% всего завязано, при таком подходе в UserRepository будет чуть менее чем всё, что касается пользователя(а его касается вообще всё) и поверьте, я видел такой трындец, получался классический God-class который назывался или UserController или UserRepository, не важно.
И Вы правильно подметили, что ActiveRecord — это уже абстракция которая уже содержит необходимое разделение, если так уж хочется иметь слои, а не модели — всегда можно вынести запросы в билдер, при этом остается гибкость композиции и нет мешанины методов. Тогда логику работы с моделью/билдером можно вынести в сервис, связи таблиц, если не требуется запись, можно сделать в релейшенах модели и использовать with, а вот уже для записи создать отдельный сервис.