Всем привет! Я уже давно программирую на php, но т.к. в основном работаю над собственными проектами (годами), то у меня сложилась некая удобная для меня структура работы с БД, которую я использую постоянно примерно в одном и том же виде. Но боюсь, если я пойду куда-то на собеседование - меня не поймут. Поэтому спрашиваю совета, помогите понять на сколько я правильно делаю или как делать правильно.
Не подружился я с ORM, т.к. при сложных запросах, в них писанины получается в разы больше чем просто написать прямой запрос. К тому же, я люблю контролировать производительность, что сделать в конструкторе запросов сложно.
В самописных проектах или плагинах для wordpress я создаю некий класс или группу классов, в которой методы состоят из запросов к БД. Каждый метод для какой-то собственной реализации, которую нельзя выполнить условиями в одном методе (нужны дополнительные данные).
И в таком классе обязательно есть метод format($dbResult){....}, который закидывает полученные данные в объект, который в свою очередь уже обрабатывается различными классами представления в зависимости от контекста (ClassView->renderShortPost($post)). Ниже я приведу код такого класса.
Вижу преимущество в таком подходе в том, что контроллер или другой обработчик никогда не знает о каких либо таблицах в бд. Он знает только о объекте или массиве объектов который он получит. И так все скрипты в проекте. Вот что у меня получается (я упростил код, чтобы он не получился на сотни строк, но смысл думаю понятен):
// AppModel уже содержит данные о БД и разные общие для всех подобных классов плюшки
// На самом деле, AppModel содержит различные сеттеры, которые я использую как псевдоконструктор запросов. Например:
// setSelect() - через запятую я перечисляю поля, которые мне нужны. А текущий класс содержит маппер, который указывает на то, какие JOIN нужно добавить в запрос и какие достато поля для конкретного select, который мне необходим.
class PostsModel extends AppModel{
private $table = 'posts';
public function __construct(){
// inicialFields это некий маппер, который сложит все необходимые поля в свойство select,
// все необходимые join в свойство joins. Если необходимые данные, такие как author, title, countComments или что-то еще будут указаны перед запросом (в текущем методе или даже из вне. Где-то в контроллере)
$this->inicialFields();
/**
* эти данные будут выгружены из базы по умолчанию
* setFields это метод внутри AppModel, который на основе map_fields из метода
* inicialFields сложит все необходимые поля в свойство select, все необходимые join в свойство joins
*/
$this->setFields("id, title");
}
/**
* Создает правила для полей, которые указаны в качестве полей для вывода
*/
protected function inicialFields(){
$this->map_fields = [
"id" => "p.`id`",
"title" => "p.`title`",
"author" => [
"fields" => [
"u.`id` userId",
"u.`name` userName"
],
"join" => [
"LEFT JOIN `users` u ON u.`id` = p.`authorId`"
]
]
];
}
/**
* @param int $id
* @return PostEntity|null
*/
function getById(int $id){
// тут нам дополнительно понадобился автор.
$this->setFields("author");
$this->setWhere("p.`id` = {$id}");
$res = $this->db->query("
SELECT {$this->getSelect()}
FROM `{$this->table}` p
{$this->getJoins()}
{$this->getWhere()} // на основе переданных where сформирует условия либо пустоту, если условий небыло
");
if($res->num_rows){
$row = $res->fetch_assoc();
return $this->format($row);
}
return null;
}
/**
* Метод возвращает список постов
* Тут мы ничего не указываем дополнительно для setFields, а значит будут получены данные, которые переданные в конструкторе по умолчанию. т.е. id и title
* @param int $userId
* @return PostEntity[]
*/
function getByList(int $userId){
$result = [];
$this->setWhere("p.`authoId` = {$userId}");
$res = $this->db->query("
SELECT {$this->getSelect()}
FROM `{$this->table}` p
{$this->getWhere()}
");
if($res->num_rows){
$row = $res->fetch_assoc();
$result[] = $this->format($row);
}
return $result;
}
function format($row){
$post = new PostEntity($row['id'], $row['title']);
if(isset($row['userId'])){
$user = new UserEntity($row['userId']);
if(isset($row['userName'])){
$user->setName($row['userName']);
}
$post->setAuthor($user);
}
return $post;
}
}