Я читал и смотрел видео уроки, и понял, что надо делить код на несколько классов. Например, класс User это модель, которая содержит в себе свойства id, email, etc. В этом классе нельзя реализовывать методы save (сохранить в базу данных), getByID, etc. Эти методы надо реализовывать в классе UserRepository.
И в этом месте вопросы. Репозиторий может иметь переменную массив, в которую складывать объекты. Теперь это похоже на коллекции. Но коллекции не могут сохранять (менять) данные в базе данных. Я не до конца понимаю как использовать коллекции и репозитории (смысл понятен, но что и когда использовать непонятно). Иногда в примерах используют всё вместе и добавляется ещё active records. Подскажите пожалуйста самый простой вариант реализации (представления простых данных из базы данных в объект в простом проекте, кто может сохранять в базу данных, кто может от туда взять и сделать объект, ведь репозиторий не может создавать объекты, как пишут в статьях) для обычной cms, который соответствует SOLID. Можете без примера кода. Просто логику действий.
И просто вопросы.
Может ли сам репозиторий делать изменения в базе данных?
Может ли модель делать изменения в базе данных (сохранять)?
Может ли модель иметь метод getByID и устанавливать все свойства в соответствии с базой данных (id, email, etc), и возвращать саму себя, чтобы это были не просто данные, а объект (return this) или это должен делать репозиторий?
Может ли репозиторий создавать объект на основе полученных данных (return new User)?
На хабре полно подобных статей, так же полно всяких самописных велосипедов на этот счёт на гитхаб
Попробуйте сначала сделать сущности и работу с базой, потом добавите репозиторий и драйверы
Типо фетч результата в объекты, делается какая то абстрактная сущность, при фетче набиваете свойствами, возвращаете массив или коллекцию, можете сделать деструктор у сущности, чтоб сама сохраняла, получится простейший AR
Если тут так и не будет лаконичного объяснения - советую поискать
ответы на эти вопросы в книге:
Implementing Domain Driven Design, Vaughn Vernon
Там есть целые разделы посвященные как моделям так и репозиториям.
нужен и должен быть., это геттер, его суть - отдать свойство. А само свойство(а) класса нужно делать закрытыми.
В этом классе нельзя реализовывать методы save (сохранить в базу данных)
нет никакой правильной точки зрения. почему нет?
abstract class Repo {
public function save($model) {
class UserRepo extends Repo
class User extends Model {
public function save($model) {
$this->repository->save($model); // или
$this->repositoryManager->getUserRepository()->save($model);
Репозиторий может иметь переменную массив, в которую складывать объекты
зачем туда что-то складывать? Его цель - принять модель/модели и сделать CRUD
Подскажите пожалуйста самый простой вариант реализации
нужен и должен быть., это геттер, его суть - отдать свойство. А само свойство(а) класса нужно делать закрытыми.
Спасибо за ответ. Я имел в виду, что может ли модель иметь метод get, который делает запрос в базу данных, например SELECT * FROM users WHERE id = :id
Ведь по смыслу модель содержит в себе данные, а как сложить эти данные в модель? Кто должен делать new User и передавать все поля из базы данных, чтобы экземпляр класса User содержал соответствующие свойства?
OneTwoThreeFourFive, нет, сами сущности — бизнес-объекты, они ничего общего с логикой сохранения состояния приложения не имеют... если подмешать логику сохранения, то у вас лапша быстро появляется в проекте, высокая свзанность вам помешает и тестировать и поддерживать код
AR заявлет о простоте, по факту усложняет
Нет ничего проще, чем отдельно подгрузить состояние приложения, а логика приложения живет раздельно
Реализация такого паттерна может быть несколько сложной, но работа в разы проще и легче. С AR все наоборот: паттерн простой, но написание кода с ним — костыли и какашки
get - взять, обычно методы с префиксом get именуются те, которые берут данные из класса, они там должны быть в виде свойств. для методов поиска в бд обычно используют префикс find.
может ли модель иметь метод ... который делает запрос в базу данных
это холиварный вопрос. сейчас может набежать 100 человек которые с будут кричать о SOLID, паттернах и тп, ориентируясь на популярные фреймворки и накатанные практики.
по факту - нет. сама модель не должна иметь в в себе механизмов поиска, это должен делать отдельный объект/слой по. поэтому я тебе и написал пример, когда модель знает о своем создателе. и вызывая метод save данные уходят в слой, который их сохранит в бд.
Кто должен делать new User и передавать все поля из базы данных, чтобы экземпляр класса User содержал соответствующие свойства
Максим Федоров, спасибо за ответ. Тогда модели содержат просто свойства и методы get, set для каждого свойства. Как тогда получить пользователя из базы данных по id?
Это похоже на бизнес логику, тогда создать отдельный класс. Допустим этот класс UserRepository и в нём реализовать метод getUserByID (я читал статьи и в этом методе можно реализовать разные методы getUserByEmail, getRandomUserи т.д). Также в статьях говорилось, что репозиторий не может создавать объекты, то есть нельзя new User() в методе getUserByID.
Или можно и я неправильно понял?
А если нельзя, то тогда где создавать new User?
Северное Сияние, спасибо за примеры.
А если я выбрал паттерн репозиторий вместо active records?
Или так нельзя и это разные вещи и оба паттерна применяются одновременно?
OneTwoThreeFourFive, мне лень писать. Скажу вот что.
Есть сухая теория. А есть реальная практика. Если ты пишешь свои собственные велосипеды, то не бойся экспериментировать и создавать для себя удобную архитектуру. Я, в отличие от множества теоретиков, в своё время написал и свой фреймворк и ORM систему, что в сумме до сих пор успешно работает на одном проекте. И минимально рабочий продукт вышел лишь со 2 или 3 попытки, те пришлось около 3 раз кардинально изменить код, на это ушло много времени.
По архитектурным паттернам есть книга Мартина Фаулера "Архитектура корпоративных программных приложений", там описаны AR, DataMapper, шлюзы и многое другое, что занимается сохранением данных в базу и обратно.
Просто тебе нужно немного выдохнуть и перестать зацикливаться над формулировкам и в стиле
Также в статьях говорилось, что репозиторий не может создавать объекты, то есть нельзя new User() в методе getUserByID.
эти статьи не часть библейских книг, любое утверждение можно опровергать бесконечно. У меня, например, в моем велосипеде, как раз getfindUserByID возвращает объект, а код продолжает исправно работать. Почему не должен и кто это сказал - я хз. Я просто написал систему с четкой архитектурой, а как она работает со стороны статейных писак мне похрен.
На собеседованиях спрашивают про SOLID, а потом ты открываешь проект и видишь, что там черт ноги поломает., а все эти теоретики сами пишут откровенное гамно. Прекрати молиться на теорию и займись практикой.
Максим Федоров, а как выглядит идеальная модель для вас? Допустим модель User в простом проекте. Пользователь может создать статью, имеет id, email, nickname, role.
OneTwoThreeFourFive, идеальная модель не должна содержать ни каких геттеров и тем более сеттеров, только методы работающие с сущностью. А сами поля получать через так называю ReadModel. Но конечно мы живём не в идеальном мире, и геттеры просто проще, чем создавать отдельную модель для чтения базы данных. ReadModel используется чаще для сложный запросов, когда обычная сущность является бутылочным горлышком и нужно вручную делать оптимальные SQL запросы.
tukreb, read model нужна для отделения логики чтения от юзера, соответственно когда мы проводим разделение — юзер превращается в несколько моделей (юзер который для авторизации (с ролями), юзер который автор, юзер который сотрудник и прочее)
лишение доменной модели логики чтения — мы упрощаем сильно домен и понижаем связанность (каплинг)