mis*_*tin 5 php oop model-view-controller
我意识到这个话题已被反复询问和解决,虽然我已经阅读了无数类似的问题,并阅读了无数篇文章,但我仍未能理解一些关键问题...我正在尝试构建自己的MVC用于学习目的的框架,以及更好地熟悉OOP.这是供个人私人使用,并不是暗示作为懒惰的借口,而是我不太关心拥有更强大框架的所有花俏.
我的目录结构如下:
public
- index.php
private
- framework
- controllers
- models
- views
- FrontController.php
- ModelFactory.php
- Router.php
- View.php
- bootstrap.php
Run Code Online (Sandbox Code Playgroud)
我有一个.htaccess文件,用于将所有请求定向到index.php,此文件包含基本配置设置,如时区和全局常量,然后加载bootstrap.php文件.引导程序包含我的类的自动加载器,启动会话,定义在整个项目中使用的全局函数,然后调用路由器.路由器从URL中挑选请求,使用ReflectionClass验证它,并以example.com/controller/method/params的形式执行请求.
我的所有控制器都扩展了FrontController.php:
<?php
namespace framework;
class FrontController
{
public $model;
public $view;
public $data = [];
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View();
}
// validate user input
public function validate() {}
// determines whether or not a form is being submitted
public function formSubmit() {}
// check $_SESSION for preserved input errors
public function formError() {}
}
Run Code Online (Sandbox Code Playgroud)
这个前端控制器加载ModelFactory:
<?php
namespace framework;
class ModelFactory
{
private $db = null;
private $host = 'localhost';
private $username = 'dev';
private $password = '********';
private $database = 'test';
// connect to database
public function connect() {}
// instantiate a model with an optional database connection
public function build($model, $database = false) {}
}
Run Code Online (Sandbox Code Playgroud)
和基本视图:
<?php
namespace framework;
class View
{
public function load($view, array $data = [])
{
// calls sanitize method for output
// loads header, view, and footer
}
// sanitize output
public function sanitize($output) {}
// outputs a success message or list of errors
// returns an array of failed input fields
public function formStatus() {}
}
Run Code Online (Sandbox Code Playgroud)
最后,这是一个示例控制器,用于演示当前如何处理请求:
<?php
namespace framework\controllers;
use framework\FrontController,
framework\Router;
class IndexController extends FrontController implements InterfaceController
{
public function contact()
{
// process form if submitted
if ($this->formSubmit()) {
// validate input
$name = isset($_POST['name']) && $this->validate($_POST['name'], 'raw') ? $_POST['name'] : null;
$email = isset($_POST['email']) && $this->validate($_POST['email'], 'email') ? $_POST['email'] : null;
$comments = isset($_POST['comments']) && $this->validate($_POST['comments'], 'raw') ? $_POST['comments'] : null;
// proceed if required fields were validated
if (isset($name, $email, $comments)) {
// send message
$mail = $this->model->build('mail');
$to = WEBMASTER;
$from = $email;
$subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';
$body = $comments . '<br /><br />' . "\r\n\r\n";
$body .= '-' . $name;
if ($mail->send($to, $from, $subject, $body)) {
// status update
$_SESSION['success'] = 'Your message was sent successfully.';
}
} else {
// preserve input
$_SESSION['preserve'] = $_POST;
// highlight errors
if (!isset($name)) {
$_SESSION['failed']['name'] = 'Please enter your name.';
}
if (!isset($email)) {
$_SESSION['failed']['email'] = 'Please enter a valid e-mail address.';
}
if (!isset($comments)) {
$_SESSION['failed']['comments'] = 'Please enter your comments.';
}
}
Router::redirect('contact');
}
// check for preserved input
$this->data = $this->formError();
$this->view->load('contact', $this->data);
}
}
Run Code Online (Sandbox Code Playgroud)
从我能够理解的,我的逻辑是关闭的,原因如下:
$data属性移出FrontController并进入ModelFactory,然后从Controller调用View而不传递数据解决这个问题?从技术上讲,它会遵循MVC流程图,但建议的解决方案看起来像是一个微不足道甚至是微不足道的细节,假设它很简单,它可能不是......isAllowed()可以从中调用的方法控制器和视图.将此方法放入模型中是否有意义,因为Controller和View都应该可以访问模型?总的来说,我是在正确的轨道上,还是我需要解决哪些明显的问题才能走上正轨?我真的希望得到针对我的例子的个人回复,而不是"去读这个"..我感谢任何诚实的反馈和帮助.
验证应该在模型中完成,而不是在控制器中完成。然而,模型不应该访问 $_POST 变量,所以我不完全确定我是否正确地完成了这部分?我觉得这就是他们所说的“胖控制器”,这很糟糕,但我不确定需要改变什么......
没错,模型应该对请求一无所知,因此,您需要将 $_POST 传递给模型,但它不会知道这些是请求参数。
一件事:与业务逻辑无关的验证应该保留在控制器中。假设您出于安全原因为表单创建了一个 CSRF 令牌,该验证应该位于控制器内部,因为它处理请求。
控制器不应该向视图发送数据;相反,视图应该有权访问模型来请求自己的数据。那么,将 $data 属性从 FrontController 移出并移入 ModelFactory,然后从控制器调用视图而不传递数据可以解决此问题吗?从技术上讲,它将遵循 MVC 流程图,但假设它是如此简单,那么所提出的解决方案似乎是一个微不足道甚至微不足道的细节,但事实可能并非如此。
这不一定是真的。这种方法称为活动模型,通常您使用该Observer模式,其中模型由视图观察。如果某些模型发生变化,它会通知视图进行自我更新。这种方法更适合桌面应用程序,而不是基于 Web 的应用程序。在 Web 应用程序中,最常见的是让控制器作为模型和视图之间的中介(被动模型)。没有正确的方法,您应该选择您最喜欢的方法。
让我质疑我的整个实现的部分是我有一个 User 对象,它是用用户相应的角色和权限实例化的,并且我一直在尝试弄清楚如何或更具体地在哪里创建一个 isAllowed() 方法,该方法可以可以从控制器和视图中调用。既然控制器和视图都应该有权访问模型,那么将此方法放入模型中是否有意义?
好吧,这个没办法,我只好叫你去读一下ACL了。