В последние несколько дней я широко читал книги и веб-страницы об ООП и MVC в PHP, чтобы я мог стать лучшим программистом. Я столкнулся с небольшой проблемой в моем понимании MVC:
Где я могу разместить mysql_query
?
Должен ли я помещать его в контроллер и вызывать метод на модели, которая возвращает данные на основе предоставленного запроса? Или я должен положить его в саму модель? Являются ли оба варианта, которыми я предоставляю полный мусор?
Вы могли бы перечислить книги, которые вы читали, потому что большинство (если не все) PHP-книг, которые касаются MVC, ошибочны.
Если вы хотите стать лучшим разработчиком, я бы рекомендовал вам начать с статьи Мартинга Фаулера – GUI Architectures . Далее следует книга от того же автора – «Шаблоны архитектуры корпоративных приложений» . Затем следующим шагом будет изучение принципов SOLID и понимание того, как писать код, который следует за Законом Деметры . Это должно охватывать основы =]
На самом деле, нет. По крайней мере, не классический MVC, как он был определен для Smalltalk .
Вместо этого в PHP у вас есть еще 4 шаблона, которые нацелены на одну и ту же цель: MVC Model2, MVP, MVVM и HMVC. Опять же, я слишком ленив, чтобы писать о различиях еще раз, поэтому я просто свяжусь со старым комментарием .
Первое, что вы должны понимать, это то, что модель в MVC не является классом или объектом. Это слой, который содержит множество классов. В основном слой модели – это все слои, объединенные (хотя второй слой должен называться «Object Object Layer», поскольку он содержит «Объекты модели домена»). Если вы хотите прочитать краткое резюме о том, что содержится в каждой части слоя модели, вы можете попробовать прочитать этот старый комментарий (перейдите к разделу «сторона примечания»).
Изображение взято из статьи Service Layer на сайте Фаулера.
Контроллер имеет одну важную ответственность в MVC (я расскажу о реализации Model2 здесь):
Выполнять команды по структурам из уровня модели (сервисы или объекты домена), которые изменяют состояние указанных структур.
Обычно у него есть второстепенная ответственность: привязывать (или иначе передавать) структуры от уровня модели к представлению, но это становится сомнительной практикой, если вы следуете за SRP
Хранение и извлечение информации обрабатывается на уровне источника данных и обычно реализуется как DataMapper (не путайте с ORM, которые злоупотребляют этим именем).
Вот как упростило бы его использование:
$mapper = $this->mapperFactory->build(Model\Mappers\User::class); $user = $this->entityFactory->build(Model\Entities\User::class); $user->setId(42); $mapper->fetch($user); if ($user->isBanned() && $user->hasBannExpired()){ $user->setStatus(Model\Mappers\User::STATUS_ACTIVE); } $mapper->store($user);
Как вы видите, ни в коем случае объект домена не знает, что информация из него была сохранена. И ни то, ни другое, о том, где вы помещаете данные. Он может храниться в MySQL или PostgreSQL или некоторой базе данных noSQL. Или, возможно, нажата на удаленный REST API. Или, может быть, картограф был манерой для тестирования. Все, что вам нужно будет сделать, чтобы заменить картограф, предоставляет этот метод на разных фабриках.
Model и Entity Classes представляют данные и логику приложения, что многие называют бизнес-логикой. Обычно он несет ответственность за:
Вот диаграмма последовательности MVC, которая показывает поток во время HTTP-запроса:
В этом случае модель – лучшее место для реализации кода, доступного для доступа к базе данных.
Модель содержит объекты домена или структуры данных, которые представляют состояние приложения. [википедия] . Таким образом, модель будет местом для вызова базы данных.
В «классическом» (отсутствие лучшего слова atm) шаблоне MVC представление получило бы текущее состояние из модели.
Не делайте ошибку, говоря, что модель предназначена для доступа к базе данных. Это больше, чем просто доступ к базе данных.
Во- mysql_query()
, не используйте mysql_query()
и family; они устарели, поэтому рассмотрите также изучение PDO и / или mysqli.
Модель заботится об обработке данных; он обеспечивает интерфейс к контроллеру, посредством которого он извлекает и / или сохраняет информацию. Таким образом, это будет основное место, где происходят действия с базой данных.
Обновить
Чтобы ответить на вопрос, заданный OP в комментариях: «одна общая модель для всего db или модель для каждой таблицы / действия?»
Модели предназначены для абстрагирования отдельных таблиц (хотя существуют модели, которые обрабатывают только одну таблицу); например, вместо того, чтобы запрашивать все статьи и затем запрашивать имена пользователей для авторов, у вас будет одна функция:
function getArticles() { // query article table and join with user table to get username }
Сколько моделей, которые вы создадите, в значительной степени зависит от того, насколько велик проект и как взаимосвязаны данные. Если вы можете идентифицировать независимые группы данных, вероятно, вы создадите модель для каждой группы; но это не сложно и быстро.
Манипуляции данными могут быть частью одной и той же модели, если вам не требуется четкое разделение между моделями только для чтения и только для записи (я бы не знал ситуации, которая оправдывает это, но кто знает).
Чтобы идти еще дальше, ваша модель не должна содержать код доступа к базе данных. Это относится к другому уровню за пределами Model / View / Controller: это называется уровнем persistence , который может быть реализован с использованием Object-Relational Mapper, такого как популярная Doctrine 2 для PHP.
Таким образом, вы никогда не трогаете какой-либо (мой) код SQL. Настойчивость слой заботится об этом за вас. Я действительно советую вам взглянуть на учебник Doctrine, это действительно профессиональный способ создания ваших приложений.
Вместо работы с необработанными данными, загруженными из базы данных, вы создаете объекты, которые содержат ваши данные, и поведение, связанное с ним.
Например, у вас может быть класс User
, например:
class User { protected $id; protected $name; protected $privileges; public function setName($name) { ... } public function getName() { ... } public function addPrivilege(Privilege $privilege) { ... } public function getPrivileges() { ... } }
Контроллер будет взаимодействовать только с объектами:
class UserController { public function testAction() { // ... $user = $em->getRepository('User')->find(123); // load User with id 123 $user->setName('John'); // work with your objects, echo $user->getName(); // and don't worry about the db! $em->flush(); // persist your changes } }
За кулисами ORM берет на себя всю низкоуровневую работу по выдаче запроса SELECT
, создавая экземпляр объекта, обнаруживая изменения в вашем объекте и выдавая необходимый оператор UPDATE
!