Нужно ли разделять модель с выводом данных и поиском?
Есть модель клиенты (class Customer)
Методы управления: create(), update(), delete()
Методы вывода даных: getAll(), getSome(array()), getOne(id) (вывод всех записей, некоторых, одной. По ID).
Есть еще поиск getByName, getByRegion и др методы.
Вопрос 1. Основой. Нужно ли создать класс CustomerSearch. В нем городить всё что угодно, возвращая только массив ID, который потом передавать в главный класс Customer. Или лучше "бесконечно наполнять" класс Customer?
Вопрос 2. Появилось желание методы create(), update(), delete() вытащить в класс CustomerEdit или CustomerAdmin. стоит так делать?
Max Ba, это класс, где у вас лежит вся работа с БД (создание, удаление, поиск), которая относится к сущности Customer. В вашем случае, все методы, которые вы описали в вопросе, надо будет перенести в репозиторий.
Репозитории это имплиметация интерфейса доменной области,по работе с хранилищем домена
это вот не тоже самое разве?
Они не описывают хранение в базах данных или кэширование или решение любой другой технической проблемы. Репозитории представляют коллекции. Как вы храните эти коллекции — это просто деталь реализации.
BoShurik, если мой класс Customer только и умеет, что работать с бд (создавать, удалять и тд) то есть он репозиторий то зачем кудато что-то переносить?))
Вероятно, наиболее важным отличием репозиториев является то, что они представляют собой коллекции объектов.
, то есть репозиторий это и есть коллекция, хотя в моем понимании коллекция объектов это объект для хранения сущностей. Прошелся еще раз по статье далее реализация такая же, ставлю лайк
Возможно имеет смысл создать контроллеры , которые отвечают за поиск и за вывод данных(Если это повысит читаемость и понятность кода). Как по мне лучше не делать много моделей если они работают с одной и той же сущностью
Max Ba, по уму пустой конструктор должен возвращать пустой объект, плохо когда объект (подразумевающий единицу сущности) возвращает коллекцию. Если нужно создать объект по каким то параметрам кроме ид то сначала что - создаете все объекты?
ThunderCat, мой класс возвращает всегда массив, либо исключение, если ошибка. Он для этого и создан в общем-то. Просто он еще умеет СВОИ данные сохранять.
Max Ba, существует несколько подходов:
Как выше написал dmitriy - (упрощенно)создать на каждую сущность несколько объектов - репозиторий и бизнеслогику(иногда еще вспомогательные какие-то), в репозитории практически чистый круд, ну и логика отдельно. Это дата маппер + репозиторий.
И есть актив рекорд - круд и логика в одном объекте.
И в обоих случаях есть масса разных реализаций и ответвлений. Но всегда объект сущности это именно экземпляр сущности(в вашем случае отдельный кастомер). Хотите много сущностей - создайте отдельный объект коллекцию - передайте в нее объект который нужно получить в нескольких экземплярах. Из него коллекция вытягивает имя таблицы (и список полей если нужно), далее строит запрос и выбирает список из бд, построчно проходит по полученной выборке и создает объекты на основе строчек. Туда же можно впихнуть получение счетчиков для пагинации и манипуляции с массивом объектов.
класс Customer работатет со своей таблицей в бд. Делает в ней все сам и возвращает данные в виде массива. Разве не такая должна быть идея?
нет, идея взять таблицу, получить из нее данные, данные хранить в свойствах объекта, ничего возвращать не нужно, данные и так будут доступны из свойств объекта.
ThunderCat, Спасибо за информацию))
Как же сложно всё... И тем не менее начинаю вроде понимать.
А вообще, я понял идею про коллекции. Смысл таков, что обьект коллекция создает на основе обьекта кастомер множество других обьектов. Тоесть уже не массив данных, а массив обьектов.
А есть совсем лайтовые примеры для школьников на эту тему? Без интерфейсов) а то мне еще с ними разбираться)))
Вот набросал что в голову пришло. Правильное направление?
class Customer {
protected $db;
//public $data = [];
public function __construct(PDO $db){
$this->db = $db;
}
public function create(array $data){
$query = "INSERT INTO `customers` VALUE (?, ?, ?, ?)";
$stmt = $this->db->prepare($query);
//$data check
return $stmt->execute($data);
}
public function update(array $data){
//return bool
}
public function delete(int $id){
//return bool
}
public function get($query, array $params = []){
$stmt = $this->db->prepare($query);
$stmt->execute($params);
//$this->data = $stmt->fetchAll();
return $stmt->fetchAll();
}
}
class CollectionCustomer {
protected $obj;
public function __construct(Customer $obj){
$this->obj = $obj;
}
public function getAll(){
$query = "SELECT * FROM `customers`";
return $this->obj->get($query);
}
public function getById(int $id){
$query = "SELECT * FROM `customers` WHERE `id` = :id";
return $this->obj->get($query, [':id' => $id]);
}
public function getByName($str){
$query = "SELECT * FROM `customers` WHERE `name` LIKE :name";
return $this->obj->get($query, [':name' => '%'.$str.'%']);
}
//и тд.
}
$db = new PDO();
$customer = new Customer($db);
$collection = new CollectionCustomer($customer);
//var_dump($collection->getAll());
var_dump($collection->getById(1));
Max Ba, что то типо такого, да, только совет по архитектуре:
Нет смысла именно в объекте кастомера писать методы CRUD. Если делать модно и красиво - передавайте набор данных для сохранения в объект который будет заниматься чисто работой с данными(обычно это надстройка над пдо), типа
public function save(){
return $this->db->save($this->getDataSet());
}
1) $this->getDataSet() возвращает массив из данных объекта в виде ['имя_поля_в _бд'=>значение] и из него просто построить подготовленный запрос.
2) public function save() лучше вынести в базовый объект и от него наследовать кастомера и все остальное что с базой работает(class Customer extends BaseObject{...). Так как данные для всех примерно одинаково читаются/сохраняются. Как выше написал dmitriy, креэйт и упдэйт по сути отличаются мало, в модели их не нужно разделять, а в объекте дб уже смотрите - если есть поле id - то упдэйт, если нет - инсерт.
3) Я обычно свойства класса полученные из бд храню в отдельном свойстве, дабы не путать с настроечными и другими свойствами (типа $this->fields['id'],$this->fields['name']...) тогда и getDataSet() в самом простом виде просто вернет массив из этого свойства.
public function save(){
return $this->db->save($this->getDataSet());
}
в данном методе вы зависите от ответа адаптера бд
седня там один ответ завтра другой, лучше
public function save(){
try{
$this->db->save($this->getDataSet());
}
catch(\DbDriverException $ex){
throw new RepositoryException($ex->getMessage(),$ex->getCode(),$ex);
}
}