Sne*_*ike 1 php model-view-controller design-patterns model slim-3
我正在尝试使用Slim3框架以及Twig模板系统在php中创建一个身份验证系统,对于数据库,我正在使用MySQL和PDO。我也在尝试使用模型视图控制器设计模式来实现它。但是我很难理解如何为Web应用程序使用MVC结构。我在网上查看了过多的解释,似乎没有明确的答案。很多人说要使用PHP框架,例如Laravel,Symfony或CodeIgniter,因为他们显然采用了类似MVC的结构。但是,我宁愿保持简单,并手动编写代码,而不是使用框架。
我目前对MVC有两种解释。此图中描绘了第一个:
我看到的另一种解释是:(摘自该YouTube视频)
我已经做了研究。问题和答案,如这和这个是有帮助的。但是我仍然不确定如何构造自己的应用程序,特别是识别和理解MVC的模型方面。现在,我将说明身份验证应用程序的注册过程。这样您就知道我的代码是如何工作的。
首先,我有一个SQLQueries类,该类将一系列SQL语句简单地放入函数中。然后,我有一个SQLWrapper类,该类具有的功能可以例如在数据库中存储新用户的详细信息。此类还从SQLQueries类调用函数。我也有一个ValidateSanitize类,该类具有清理用户输入以及检查用户输入在表单中是否有效的功能。我认为这三个类是MVC模型方面的一部分,但我不确定。我看到了许多其他的使用“用户模型类”的教程,但我的应用程序中找不到它们。
我的视图只是显示HTML的Twig模板,例如主页,注册,登录等。然后我有了控制器。我打算让多个控制器执行不同的操作。目前,我只实现了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'];
Run Code Online (Sandbox Code Playgroud)
接下来,实例化所有前面的三个类以及数据库详细信息,以便可以在AuthController中使用它们的功能:
$sanitizer_validator = $this->container->ValidateSanitize;
$sql_wrapper = $this->container->SQLWrapper;
$sql_queries = $this->container->SQLQueries;
$db_handle = $this->container->get('dbase');
Run Code Online (Sandbox Code Playgroud)
然后,使用sanitize_input函数清除受污染的用户详细信息。然后,将清理后的用户详细信息输入到validate函数中,以确保它们不会触发任何验证冲突。密码也在此处散列:
$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);
Run Code Online (Sandbox Code Playgroud)
最后,有一个if语句,检查所有验证错误消息是否为空。如果是的话,我们将为SQLWrapper类提供数据库详细信息以及SQLQueries类对象。然后,通过调用SQLWrapper类store-details函数将用户详细信息插入数据库。最后,我们将用户定向到登录页面,以便用户可以登录其新注册的帐户。
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'));
}
Run Code Online (Sandbox Code Playgroud)
但是,如果任何验证错误消息都不为空,那么我们将调用SanitiseValidate display_validate_messages,该消息将消息简单地设置为要在寄存器树枝模板上显示的会话。然后,我们重定向回注册页面,以便用户可以看到验证错误消息。
else
{
$sanitizer_validator->display_validate_messages();
return $response->withRedirect($this->container->router->pathFor('register'));
}
}
Run Code Online (Sandbox Code Playgroud)
因此,基于用户注册帐户的这种结构。这是否遵循干净的简单MVC结构,还是需要进行一些更改?我的任何课程都扮演过模型的角色吗?关于我的结构的任何建议和技巧将不胜感激。
将完整的应用程序可以在我的GitHub上可以看到,如果这将是有益的。请注意,此版本比我在此问题中使用的示例代码稍旧。
确实,关于如何在Web应用程序中应用MVC模式有多种方法。众多变体是一个简单事实的结果,即原始的MVC模式(为桌面应用程序开发(由Trygve Reenskaug,在1979年开发))无法原样应用于Web应用程序。这里有一些描述。但是,从这套方法中,您可以选择最符合您的要求的一种。也许您会先决定尝试其中的更多方法。虽然,在某个时候,您会知道哪一个适合您的视野。
在下图中,我试图在Web MVC工作流上展示我选择的方法-主要是受罗伯特·马丁(Robert Martin)的演讲主题演讲:迷失的年代的体系结构(按知识共享署名ShareAlike 3.0许可)。
通常,您可以将Web MVC应用程序视为由以下部分组成:
1)的域模型应该包括以下组件组成:
此外,领域模型可以分为两部分:
a) 领域模型抽象。这将是交付层的组件或服务层的服务访问的模型层的唯一空间-如果已实现:
外部服务的抽象。
注意:抽象是指接口和抽象类。
b) 领域模型的实现。该空间将是其中不同的域模型的抽象(见的实现方式中,一个一个)将驻留。依赖项注入容器(作为传递机制的一部分)将负责将这些具体类的实例作为依赖关系传递给应用程序的其他组件(例如,控制器,视图,服务等),例如作为构造函数参数。
2) 服务层(可选):从技术上讲,交付机制的组件可以直接与域模型的元素进行交互。尽管此类交互涉及(很多)操作,但这些操作仅特定于模型,而不特定于交付机制。因此,一个不错的选择是将这些操作的执行推迟到服务类(例如services)中,作为所谓服务层的一部分。然后,传递机制组件将仅使用这些服务来访问域模型组件。
注意:实际上,服务层可以视为模型层的一部分。在下面的图表中,我倾向于将其显示为位于模型外部的图层。但是,在文件系统示例中,我将相应的文件夹放在域空间中。
3)的输送机构总结了构建体用于确保用户和模型层的部件之间的交互。用户不是人,而是人可以与之交互的界面,例如浏览器,控制台(例如CLI),桌面GUI等。
Web服务器:通过单个入口点(index.php)解析用户请求。
依赖项注入容器:为应用程序的不同组件提供适当的依赖项。
HTTP消息(例如HTTP请求和HTTP响应)的抽象(请参阅PSR-7:HTTP消息接口)。
Router:将请求组件(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'],
]);
Run Code Online (Sandbox Code Playgroud)
这种方法为用户请求分配提供了灵活性。例如,视图动作的名称可以与控制器动作的名称不同。或者,为了仅获取模型层数据,您无需将用户请求分派给控制器,而仅分派给视图。因此,您根本不需要在路由中分配控制器操作:
<?php
use MyApp\UI\Web\Application\View;
$this->get('/upload', [View\Upload::class, 'listFiles']);
Run Code Online (Sandbox Code Playgroud)
文件系统结构示例:
myapp / domain:包含域模型类和服务的文件夹。该目录可以被带到“ myapp / web / src”文件夹中,但是不能,因为模型层和服务层不是传递机制的一部分。
myapp / web:包含传递机制类的文件夹。它的名称描述了应用程序的类型-可以是Web应用程序,CLI应用程序等。
myapp / web / src:
资源:
我的旧答案中列出的那些。
Alejandro Gervasio展示的教程:
Slim 3页面上的示例:带Slim的Action-Domain-Responder。
| 归档时间: |
|
| 查看次数: |
592 次 |
| 最近记录: |