Я только начинаю понимать MVC-фреймворк и часто задаюсь вопросом, сколько кода должно идти в модели. Я склонен иметь класс доступа к данным, который имеет такие методы:
public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;
//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";
//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}
Мои модели, как правило, представляют собой класс сущностей, который отображается в таблицу базы данных.
Должен ли объект модели иметь все свойства сопоставленной базы данных, а также код, приведенный выше, или это нормально, чтобы отделить тот код, который фактически работает с базой данных?
Я получу четыре слоя?
php
oop
model-view-controller
architecture
model
Dietpixel
источник
источник
Exception
не имеет большого значения документации. Лично, если бы я пошел по этому пути, я бы выбрал PHPDoc@exception
или какой-то подобный механизм, так что это будет показано в сгенерированной документации.Ответы:
Первое, что я должен прояснить: модель - это слой .
Второе: есть разница между классическим MVC и тем, что мы используем в веб-разработке. Вот немного более старого ответа, который я написал, который кратко описывает, как они отличаются.
Какая модель НЕ является:
Модель не является классом или каким-либо отдельным объектом. Это очень распространенная ошибка (я тоже сделал, хотя первоначальный ответ был написан, когда я начал учиться иначе) , потому что большинство фреймворков увековечивают это заблуждение.
Это не методика объектно-реляционного отображения (ORM) и не абстракция таблиц базы данных. Любой, кто говорит вам обратное, скорее всего, пытается «продать» другой новый ORM или целую платформу.
Что это за модель:
При правильной адаптации MVC M содержит всю бизнес-логику домена, а уровень модели в основном состоит из трех типов структур:
Доменные объекты
В этом месте вы определяете, как проверять данные перед отправкой счета или рассчитывать общую стоимость заказа. В то же время доменные объекты полностью не знают о хранилище - ни откуда (база данных SQL, REST API, текстовый файл и т. Д.), Ни даже если они сохранены или получены.
Data Mappers
Эти объекты несут ответственность только за хранение. Если вы храните информацию в базе данных, это то место, где живет SQL. Или, может быть, вы используете файл XML для хранения данных, и ваши Data Mappers анализируют файлы XML и обратно.
Сервисы
Вы можете думать о них как о «доменных объектах более высокого уровня», но вместо бизнес-логики Сервисы отвечают за взаимодействие между доменными объектами и Mappers . Эти структуры в конечном итоге создают «открытый» интерфейс для взаимодействия с бизнес-логикой домена. Вы можете избежать их, но за счет утечки некоторой логики домена в контроллеры .
Существует ответ на этот вопрос в вопросе реализации ACL - это может быть полезно.
Связь между уровнем модели и другими частями триады MVC должна происходить только через Сервисы . Четкое разделение имеет несколько дополнительных преимуществ:
Как взаимодействовать с моделью?
Получение доступа к экземплярам сервисов
Для обоих экземпляров View и Controller (то, что вы могли бы назвать «уровнем пользовательского интерфейса») для доступа к этим службам, существует два основных подхода:
Как вы можете подозревать, DI-контейнер - намного более элегантное решение (хотя и не самое простое для новичка). Две библиотеки, которые я рекомендую рассмотреть для этой функциональности, будут автономным компонентом DependencyInjection от Syfmony или Auryn .
Оба решения, использующие фабрику и контейнер DI, позволили бы вам также совместно использовать экземпляры различных серверов, которые будут совместно использоваться выбранным контроллером, и просматривать для данного цикла запрос-ответ.
Изменение состояния модели
Теперь, когда вы можете получить доступ к слою модели в контроллерах, вам нужно начать использовать их:
Ваши контроллеры имеют очень четкую задачу: принять пользовательский ввод и, основываясь на этом вводе, изменить текущее состояние бизнес-логики. В этом примере изменяются состояния между «анонимный пользователь» и «зарегистрированный пользователь».
Контроллер не несет ответственности за проверку вводимых пользователем данных, поскольку это является частью бизнес-правил, и контроллер определенно не вызывает SQL-запросы, как то, что вы увидите здесь или здесь (пожалуйста, не ненавидьте их, они ошибочны, а не злы).
Показывает пользователю изменение состояния.
Хорошо, пользователь вошел в систему (или не прошел). Что теперь? Указанный пользователь все еще не знает об этом. Таким образом, вы должны на самом деле произвести ответ, и это является обязанностью представления.
В этом случае представление создало один из двух возможных ответов на основе текущего состояния слоя модели. Для другого варианта использования у вас будет представление, выбирающее различные шаблоны для рендеринга, основанные на чем-то вроде «текущий выбранный из статьи».
Уровень представления может быть довольно сложным, как описано здесь: Понимание MVC Views в PHP .
Но я просто делаю REST API!
Конечно, бывают ситуации, когда это перебор.
MVC - это просто конкретное решение принципа разделения интересов . MVC отделяет пользовательский интерфейс от бизнес-логики, а в пользовательском интерфейсе он разделяет обработку пользовательского ввода и представление. Это очень важно. Хотя люди часто называют это «триадой», на самом деле она не состоит из трех независимых частей. Структура больше похожа на это:
Это означает, что, когда логика вашего уровня представления почти не существует, прагматический подход заключается в том, чтобы сохранить их как один уровень. Это также может существенно упростить некоторые аспекты модельного уровня.
Используя этот подход, пример входа в систему (для API) можно записать так:
Хотя это не является устойчивым, когда у вас сложная логика для отображения тела ответа, это упрощение очень полезно для более тривиальных сценариев. Но будьте осторожны , такой подход станет кошмаром, когда вы попытаетесь использовать большие кодовые базы со сложной логикой представления.
Как построить модель?
Поскольку не существует ни одного класса «Модель» (как описано выше), вы действительно не «строите модель». Вместо этого вы начинаете создавать Сервисы , которые могут выполнять определенные методы. А затем реализовать доменные объекты и Mappers .
Пример метода обслуживания:
В обоих вышеописанных подходах использовался метод входа в систему для службы идентификации. Как бы это на самом деле выглядело. Я использую слегка измененную версию той же функциональности из библиотеки , которую я написал .. потому что я ленивый:
Как вы можете видеть, на этом уровне абстракции нет указания на то, откуда были получены данные. Это может быть база данных, но это также может быть просто фиктивный объект для тестирования. Даже средства отображения данных, которые фактически используются для этого, скрыты в
private
методах этого сервиса.Способы создания картографов
Чтобы реализовать абстракцию постоянства, наиболее гибким подходом является создание пользовательских картографических данных .
От: книга PoEAA
На практике они реализуются для взаимодействия с конкретными классами или суперклассами. Допустим, у вас есть
Customer
иAdmin
в вашем коде (оба наследуются отUser
суперкласса). Вероятно, оба получат отдельный сопоставитель, так как они содержат разные поля. Но вы также будете иметь общие и часто используемые операции. Например: обновление времени «последний раз онлайн» . И вместо того, чтобы сделать существующие средства отображения более запутанными, более прагматичный подход состоит в том, чтобы иметь общий «User Mapper», который обновляет только эту временную метку.Некоторые дополнительные комментарии:
Таблицы базы данных и модель
Хотя иногда существует прямая связь 1: 1: 1 между таблицей базы данных, Domain Object и Mapper , в более крупных проектах это может быть менее распространенным, чем вы ожидаете:
Информация, используемая одним доменным объектом, может отображаться из разных таблиц, тогда как сам объект не хранится в базе данных.
Пример: если вы генерируете ежемесячный отчет. Это позволит собирать информацию из разных таблиц, но
MonthlyReport
в базе данных нет волшебных таблиц.Один Mapper может влиять на несколько таблиц.
Пример: когда вы храните данные из
User
объекта, этот объект домена может содержать коллекцию других объектов домена -Group
экземпляров. Если вы измените их и сохранитеUser
, Data Mapper должен будет обновить и / или вставить записи в несколько таблиц.Данные из одного доменного объекта хранятся в нескольких таблицах.
Пример: в больших системах (например, социальная сеть среднего размера) может быть прагматичным хранить данные аутентификации пользователя и часто используемые данные отдельно от больших кусков контента, что редко требуется. В этом случае у вас все еще может быть один
User
класс, но информация, которую он содержит, будет зависеть от того, были ли получены полные сведения.Для каждого доменного объекта может быть несколько картографов
Пример: у вас есть новостной сайт с общим кодовым кодом как для публичного, так и для управляющего программного обеспечения. Но, хотя оба интерфейса используют один и тот же
Article
класс, для управления необходимо заполнить его большим количеством информации. В этом случае у вас будет два отдельных преобразователя: «внутренний» и «внешний». Каждый выполняет разные запросы или даже использует разные базы данных (как в master, так и в slave).Представление не шаблон
Просмотр экземпляров в MVC (если вы не используете вариацию шаблона MVP) отвечают за логику представления. Это означает, что в каждом представлении обычно используется как минимум несколько шаблонов. Он получает данные с уровня модели, а затем на основе полученной информации выбирает шаблон и устанавливает значения.
Одним из преимуществ, которые вы получаете от этого, является возможность повторного использования. Если вы создаете
ListView
класс, то с хорошо написанным кодом у вас может быть тот же класс, который передает представление списка пользователей и комментарии под статьей. Потому что они оба имеют одинаковую логику представления. Вы просто переключаете шаблоны.Вы можете использовать либо собственные шаблоны PHP, либо использовать сторонний шаблонизатор. Также могут быть некоторые сторонние библиотеки, которые могут полностью заменить экземпляры View .
Как насчет старой версии ответа?
Единственное существенное изменение заключается в том, что то, что в старой версии называется Model , на самом деле является Сервисом . В остальном «библиотечная аналогия» держится довольно неплохо.
Единственный недостаток, который я вижу, это то, что это будет действительно странная библиотека, потому что она вернет вам информацию из книги, но не позволит вам прикоснуться к самой книге, потому что в противном случае абстракция начнет «просачиваться». Возможно, мне придется подумать о более подходящей аналогии.
Какова связь между экземплярами View и Controller ?
Структура MVC состоит из двух слоев: пользовательского интерфейса и модели. Основными структурами на уровне пользовательского интерфейса являются представления и контроллер.
Когда вы имеете дело с веб-сайтами, использующими шаблон проектирования MVC, наилучшим способом является соотношение 1: 1 между представлениями и контроллерами. Каждое представление представляет целую страницу на вашем сайте, и у него есть специальный контроллер для обработки всех входящих запросов для этого конкретного представления.
Например, чтобы представить открытую статью, вы должны иметь
\Application\Controller\Document
и\Application\View\Document
. Он будет содержать все основные функциональные возможности для уровня пользовательского интерфейса, когда речь идет о работе со статьями (конечно, у вас могут быть некоторые компоненты XHR , которые не имеют прямого отношения к статьям) .источник
Все, что является бизнес-логикой, принадлежит модели, будь то запрос к базе данных, вычисления, вызов REST и т. Д.
Вы можете иметь доступ к данным в самой модели, шаблон MVC не ограничивает вас в этом. Вы можете приукрашивать это услугами, картографами и т. Д., Но фактическое определение модели - это слой, который обрабатывает бизнес-логику, ни больше, ни меньше. Это может быть класс, функция или полный модуль с gazillion объектов, если вы этого хотите.
Всегда проще иметь отдельный объект, который фактически выполняет запросы к базе данных, вместо того, чтобы выполнять их непосредственно в модели: это особенно пригодится при модульном тестировании (из-за простоты внедрения фиктивной зависимости базы данных в вашей модели):
Кроме того, в PHP вам редко нужно перехватывать / перебрасывать исключения, потому что обратная трассировка сохраняется, особенно в случае, подобном вашему примеру. Просто позвольте выбросить исключение и вместо этого перехватите его в контроллере.
источник
User
Класс в основном расширяет модель, но itsn't объект. Пользователь должен быть объектом и иметь такие свойства, как: идентификатор, имя ... РазвертываниеUser
класса является помощником.User
обозначает объект, и он должен иметь свойства пользователя, а не такие методы, какCheckUsername
, что вы должны делать, если вы хотите создать новыйUser
объект?new User($db)
В Web- «MVC» вы можете делать все, что угодно.
Первоначальная концепция (1) описывала модель как бизнес-логику. Он должен представлять состояние приложения и обеспечивать некоторую согласованность данных. Этот подход часто называют «жирной моделью».
Большинство PHP-фреймворков используют более поверхностный подход, где модель представляет собой просто интерфейс базы данных. Но, по крайней мере, эти модели должны проверять входящие данные и отношения.
В любом случае, вы не очень далеки от этого, если разделите запросы SQL или вызовы базы данных на другой уровень. Таким образом, вам нужно заботиться только о реальных данных / поведении, а не о реальном API хранилища. (Однако неоправданно переусердствовать. Например, вы никогда не сможете заменить серверную часть базы данных файловым хранилищем, если она не была разработана заранее.)
источник
Чаще всего большинство приложений будет иметь данные, отображение и обработку, и мы просто помещаем все это в буквы
M
,V
иC
.Model (
M
) -> Имеет атрибуты, которые содержат состояние приложения, и он ничего не знает оV
иC
.View (
V
) -> Имеет формат отображения для приложения и знает только о том, как обработать модель, и не беспокоится об этомC
.Контроллер (
C
) ----> Имеет обработки части приложения и действует как проводка между М и V , и это зависит от того, какM
, вV
отличиеM
иV
.В целом есть разделение проблем между каждым. В будущем любые изменения или улучшения могут быть добавлены очень легко.
источник
В моем случае у меня есть класс базы данных, который обрабатывает все прямые взаимодействия с базой данных, такие как запросы, выборки и тому подобное. Так что, если бы мне пришлось изменить мою базу данных с MySQL на PostgreSQL проблем не будет. Поэтому добавление этого дополнительного слоя может быть полезным.
Каждая таблица может иметь свой собственный класс и свои конкретные методы, но для фактического получения данных она позволяет классу базы данных обрабатывать его:
файл
Database.php
Таблица объекта classL
Я надеюсь, что этот пример поможет вам создать хорошую структуру.
источник
Database
в примере это не класс. Это просто оболочка для функций. Кроме того, как вы можете иметь «класс объекта таблицы» без объекта?