PHP - структурирование веб-приложения Slim3 с использованием MVC и понимание роли модели - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь создать систему аутентификации в php с помощью среды Slim3 вместе с системой шаблонов Twig, а для базы данных я использую MySQL с PDO. Я также пытаюсь реализовать это, используя шаблон проектирования контроллера представления модели. Однако мне трудно понять, как использовать структуру MVC для веб-приложения. Я посмотрел на множество объяснений в Интернете, и, похоже, нет однозначного ответа. Многие люди говорят об использовании php-фреймворка, такого как Laravel, Symfony или CodeIgniter, поскольку они, очевидно, используют MVC-подобную структуру. Однако я бы предпочел не усложнять ситуацию и писать код вручную, а не использовать фреймворк.

В настоящее время я вижу две интерпретации MVC. Первый изображен на этой диаграмме:

enter image description here

Другая интерпретация, которую я видел, такова: (взято из этого видео на YouTube )

enter image description here

Я провел свое исследование. Были полезны такие вопросы и ответы, как this и this . Но я все еще не уверен, как я мог бы структурировать свои собственные приложения, особенно идентифицируя и понимая аспект модели MVC. Теперь я объясню процесс регистрации моего приложения для аутентификации. Итак, у вас есть идея, как работает мой код.

Во-первых, у меня есть класс SQLQueries, который просто помещает ряд операторов SQL в функции. Затем у меня есть класс SQLWrapper, в котором есть функции, которые могут, например, хранить информацию о новых пользователях в базе данных. Этот класс также вызывает функции из класса SQLQueries. У меня также есть класс ValidateSanitize, который имеет функции, которые очищают пользовательский ввод, а также проверяют, является ли пользовательский ввод действительным в форме. Эти три класса, я думаю, являются частью модельного аспекта MVC, но я не уверен. Я вижу много других учебных пособий, использующих «класс модели пользователя», но я не могу найти его в своем приложении.

Мои представления - это просто шаблоны Twig, отображающие html, такие как домашняя страница, регистрация, вход в систему и т. Д. У меня есть контроллеры. Я намерен иметь несколько контроллеров, которые делают разные вещи. Пока я только внедрил AuthController, который отвечает за регистрацию и вход пользователя в систему.

Итак, первое, что делает AuthController, это отображает форму регистра в функции getRegisterForm. После того как пользователь отправил форму, функция postRegisterForm принимает этот пользовательский ввод и назначает его испорченным переменным.

public function postRegisterForm($request, $response)  
{
   $arr_tainted_params = $request->getParsedBody(); 

   $tainted_email = $arr_tainted_params['email'];  it a variable
   $tainted_username = $arr_tainted_params['username'];
   $tainted_password = $arr_tainted_params['password'];
   $tainted_password_confirm = $arr_tainted_params['password_confirm'];

Затем создаются все три предыдущих класса, а также детали базы данных, поэтому их функции могут использоваться в AuthController:

$sanitizer_validator = $this->container->ValidateSanitize;
$sql_wrapper = $this->container->SQLWrapper;
$sql_queries = $this->container->SQLQueries;
$db_handle = $this->container->get('dbase');

Затем испорченные пользовательские данные очищаются с помощью функции sanitize_input. Затем очищенные данные пользователя передаются в функции проверки, чтобы убедиться, что они не вызывают нарушений проверки. Здесь также хешируется пароль:

$cleaned_email = $sanitizer_validator->sanitize_input($tainted_email, FILTER_SANITIZE_EMAIL); 
$cleaned_username = $sanitizer_validator->sanitize_input($tainted_username, FILTER_SANITIZE_STRING);
$cleaned_password = $sanitizer_validator->sanitize_input($tainted_password, FILTER_SANITIZE_STRING);
$cleaned_password_confirm = $sanitizer_validator->sanitize_input($tainted_password_confirm, FILTER_SANITIZE_STRING);

$hashed_cleaned_password = password_hash($cleaned_password, PASSWORD_DEFAULT); 

$sanitizer_validator->check_email_exists($cleaned_email);
$sanitizer_validator->validate_email($cleaned_email);
$sanitizer_validator->validate_username($cleaned_username);
$sanitizer_validator->validate_password($cleaned_password);
$sanitizer_validator→validate_password_confirm($cleaned_password_confirm);

Наконец, есть оператор if, который проверяет, все ли сообщения об ошибках валидации пусты. Если это так, мы предоставляем классу SQLWrapper данные базы данных, а также объект класса SQLQueries. Затем мы вставляем сведения о пользователях в базу данных, вызывая функцию store-details для классов SQLWrapper. Наконец, мы направляем пользователя на страницу входа, чтобы пользователь мог войти в свою недавно зарегистрированную учетную запись.

if ($sanitizer_validator->get_validate_messages('email_error') == ' ' && $sanitizer_validator->get_validate_messages('username_error') == ' '
    && $sanitizer_validator->get_validate_messages('password_error') == ' ' && $sanitizer_validator->check_passwords_match($cleaned_password, $cleaned_password_confirm ) == true
    && $sanitizer_validator->check_email_exists($cleaned_email) == false)
{   

    $sql_wrapper->set_db_handle($db_handle); 
    $sql_wrapper->set_sql_queries($sql_queries); 

     $sql_wrapper->store_details($cleaned_email, $cleaned_username, $hashed_cleaned_password);
     return $response→withRedirect($this→container→router→pathFor('login'));

}

Однако, если какое-либо из сообщений об ошибке проверки не является пустым, мы вызываем SanitiseValidate display_validate_messages, который просто устанавливает сообщения в сеанс, который будет отображаться в шаблоне ветки регистра. Затем мы перенаправляем обратно на страницу регистрации, чтобы пользователь мог видеть сообщения об ошибках проверки.

else
  {
      $sanitizer_validator->display_validate_messages();
      return $response->withRedirect($this->container->router->pathFor('register'));
  }
}

Итак, основываясь на этомПользователь регистрирует учетную запись. Придерживается ли это чистой простой структуры MVC или необходимо внести некоторые изменения? Кто-нибудь из моих классов играет роль модели? Будем благодарны за любые предложения и советы относительно моей структуры.

Полное приложение можно увидеть на моем GitHub , если это будет полезно. Обратите внимание, что эта версия немного старше, чем образец кода, который я использовал в этом вопросе.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Существует курс, в котором вы пройдете через создание MVC с Slim 3. Я связываю его здесь: https://codecourse.com/courses/slim-3-authentication. Надеюсь, что это помогло, пройти курс очень легко, и вы многому научитесь.

0 голосов
/ 15 января 2019

Действительно, существует множество подходов относительно того, как шаблон MVC должен применяться в веб-приложениях. Это множество вариантов является результатом того простого факта, что оригинальный шаблон MVC - разработанный для настольных приложений (Трюгве Реенскауг, в 1979 году) - не может быть применен как веб-приложения. Здесь - небольшое описание. Но из этого набора подходов вы можете выбрать тот, который наилучшим образом соответствует вашим требованиям. Может быть, вы попробуете их больше, прежде чем решитесь. Хотя в какой-то момент вы узнаете, какой из них подходит вашему зрению.

В следующих схемах я пытался представить выбранный мной подход в веб-процессе MVC - главным образом, вдохновленный презентацией Роберта Мартина Ключ: Архитектура потерянных лет (по лицензии Creative Commons Attribution ShareAlike 3.0 ).

<Ч />

enter image description here

<Ч />

enter image description here

<Ч />

enter image description here

<Ч />

В целом, вы можете представить веб-приложение MVC как состоящее из следующих частей:

  1. Доменная модель (например, модель, например, слой модели);
  2. Сервисный уровень (необязательно);
  3. Механизм доставки ;
  4. Другие компоненты (например, собственные библиотеки и т. Д.).

1) Модель домена должна состоять из следующих компонентов:

  • Объекты (например, объекты домена) и объекты значений . Они моделируют бизнес-правила с точки зрения свойств и поведения и, будучи независимыми от приложений, могут использоваться несколькими (типами) приложений.
  • (Data) картографы и, необязательно, хранилища . Эти компоненты отвечают за логику персистентности.
  • Внешние услуги . Они используются для выполнения различных задач, связанных с использованием внешних / собственных библиотек (таких как отправка электронных писем, анализ документов и т. Д.).

Кроме того, модель предметной области можно разделить на две части:

a) Абстракция модели домена . Это будет единственное пространство на уровне модели, доступное компонентам механизма доставки или службам уровня обслуживания, если он реализован:

  • Сущности и объекты стоимости;
  • (Данные) абстракции картографа и, необязательно, абстракции репозитория;
  • Абстракции внешних сервисов.

    Примечание. Под абстракциями я подразумеваю интерфейсы и абстрактные классы.

b) Реализация доменной модели . Это пространство будет тем, в котором будут находиться реализации различных абстракций модели предметной области (см. a ). Контейнер внедрения зависимостей (как часть механизма доставки) будет отвечать за передачу экземпляров этих конкретных классов в качестве зависимостей - например, в качестве аргументов конструктора - другим компонентам приложения (таким как контроллеры, представления, службы и т. Д.).

2) Сервисный уровень (необязательно): Технически, компоненты механизма доставки могут напрямую взаимодействовать с элементами модели предметной области. Хотя такие взаимодействия включают в себя (много) операций, характерных только для модели, а не для механизма доставки. Поэтому хорошим выбором является отложить выполнение этих операций до классов обслуживания (например, services ), как часть так называемого уровня обслуживания . Компоненты механизма доставки будут затем использовать только эти службы для доступа к компонентам модели домена.

Примечание. Сервисный уровень фактически можно рассматривать как часть уровня модели. В приведенных ниже схемах я предпочел отобразить его как слой, находящийся вне модели. Но в примере с файловой системой я поместил соответствующую папку в доменное пространство.

3) Механизм доставки суммирует конструкции, используемые для обеспечения взаимодействия между пользователем и компонентами уровня модели. Под пользователем я имею в виду не человека, а интерфейс, с которым он может взаимодействовать - например, браузер, консоль (например, CLI), графический интерфейс пользователя на рабочем столе и т. Д.

  • Веб-сервер : анализирует пользовательский запрос через одну точку входа (index.php).

  • Контейнер для инъекций зависимостей : обеспечивает надлежащие зависимости для различных компонентов приложения.

  • HTTP-сообщение (например, HTTP-запрос и HTTP-ответ) абстракция (см. PSR-7: интерфейсы HTTP-сообщения ).

  • Маршрутизатор : сопоставляет компоненты запроса (метод HTTP и путь URI) с компонентами каждого маршрута (метод и шаблон HTTP) в предварительно определенном списке маршрутов и возвращает соответствующий маршрут, если найдено.

  • Фронт-контроллер : сопоставляет запрос пользователя с маршрутом и отправляет его определенному контроллеру и / или отображает действие.

  • Контроллеры . Они записывают (например, выполняют операции создания, обновления и удаления) в слой модели и (не должны) ожидать результатов. Это может произойти путем непосредственного взаимодействия с компонентами, определенными в модели предметной области, или, предпочтительно, путем взаимодействия только с классами обслуживания.

  • Просмотры . Это должны быть классы, а не файлы шаблонов. Они могут получить шаблонизатор в качестве зависимости. Они только выбирают данные (например, выполняют операции чтения) со слоя модели. Либо путем прямого взаимодействия с компонентами, определенными в модели предметной области, либо, предпочтительно, путем взаимодействия только с классами обслуживания. Кроме того, они решают, какой результат (например, строка) или содержимое файла шаблона будет отображаться пользователю. Действие вида всегда должно возвращать объект ответа HTTP (может быть, как определено в спецификации PSR-7), тело которого будет предварительно обновлено с указанным результатом или содержимым файла шаблона.

  • Файлы шаблонов . Должно быть максимально простым. Вся логика представления должна происходить только в экземплярах представления. Таким образом, файлы шаблонов должны содержать только переменные (будь то чисто PHP или представленные с использованием синтаксиса используемого механизма шаблонов) и, возможно, некоторые простые условные операторы или циклы.

  • Отправитель ответа : читает тело экземпляра ответа HTTP, возвращенного представлением, и печатает его.

4) Прочие компоненты . Как пожелал. Например, некоторые библиотеки, разработанные вами. Как реализация абстракции PSR-7 .

<Ч />

Как я решил отправить запрос пользователя:

Как вы видите на диаграммах выше, фронт-контроллер отправляет запрос пользователя не только на действие контроллера (для обновления модели домена), но и на действие просмотра (для чтения и отображения обновленного состояния). / данные из слоя модели). Вид расщепленной отправки. Это может быть относительно легко достигнуто путем назначения действия контроллера и действия просмотра для каждого маршрута (как показано ниже) и указания переднему контроллеру вызывать их последовательно:

<?php

use MyApp\UI\Web\Application\View;
use MyApp\UI\Web\Application\Controller;

// Note: $this specifies a RouteCollection to which the route is added. 
$this->post('/upload', [
    'controller' => [Controller\Upload::class, 'uploadFiles'],
    'view' => [View\Upload::class, 'uploadFiles'],
]);

Этот подход обеспечивает гибкость в отношении отправки пользовательских запросов. Например, имя действия представления может отличаться от имени действия контроллера. Или для того, чтобы получать только данные слоя модели, вам не нужно отправлять пользовательский запрос в контроллер, а только в представление. Поэтому вам вообще не нужно назначать действие контроллера в маршруте:

<?php

use MyApp\UI\Web\Application\View;

$this->get('/upload', [View\Upload::class, 'listFiles']);
<Ч />

Пример структуры файловой системы :

enter image description here

myapp / domain : папка, содержащая классы модели домена и сервисы. Этот каталог может быть перенесен в папку «myapp / web / src», но не должен, потому что уровень модели и уровень сервиса не являются частью механизма доставки.

domain folder

myapp / web : папка, содержащая классы механизма доставки. Его название отображает тип приложения - это может быть веб-приложение, клиентское приложение и т. Д.

web folder

MyApp / веб / ЦСИ

web-src folder

<Ч />

Ресурсы

Те, что перечислены в старом ответе моего.

Учебники, представленные Алехандро Жервасио:

Пример на странице Slim 3: Action-Domain-Responder с Slim .

...