PHP MVC 原理

发布于 2024-12-17 03:36:04 字数 1091 浏览 0 评论 0原文

我没有使用现成的框架,也不是特别想要(我也不想探究原因......)。不管怎样,关于我的问题,我希望它有意义......

我正在努力弄清楚模型中应该包含什么以及控制器中应该包含什么。最初我的印象是模型类应该代表一个实际的对象(例如 - 数据库的 cars 表中的一辆汽车),并且模型属性应该反映数据库字段。然而,我现在感觉我有错误的想法 - 模型类的实例应该代表一个实际的项目,还是应该包含许多执行操作的方法 - 有时针对一辆汽车,有时针对多辆汽车基于我之前的例子。

例如,我想从数据库中获取所有汽车并在视图中显示它们。我认为应该遵循这样的思路吗?

控制器文件

function list() {
    $cars = $this->model->get_all();
    $this->view->add($cars);
    $this->view->render('cars-list');
}

模型文件

function get_all() {
    // Use a database interaction class that I've written 
    $cars = Database::select();

    return $cars;
}

现在,如果汽车有一个“状态”字段,该字段以整数形式存储在数据库中,并且我想将其更改为字符串,那么应该在哪里那该怎么办呢?通过在模型中的 get_all() 方法中循环 SQL 结果数组?

另外,表单验证应该在哪里进行?我编写了一个验证类,其工作方式有点像这样:

$validator = new Validator();    
$validator->check('field_name', 'required');

如果检查失败,它会向验证器中的数组添加一条错误消息。然后,该错误消息数组将被传递到视图。我的验证器类应该在模型中使用还是在控制器中使用?

预先感谢任何人可以提供的任何帮助。如果您知道任何处理基本 CRUD 的简单 MVC 示例/开源应用程序的链接,我们将不胜感激。

I'm not using an off-the-shelf framework and don't particularly want to (nor d I want to go into the reasons why...). Anyway, onto my question(s), I hope it make sense....

I'm trying to get my head around what should go in the model and what should go in the controller. Originally I had the impression that a model class should represent an actual object (eg - a car from the cars table of a database) and model properties should mirror the database fields. However I'm now getting the feeling that I've got the wrong idea - should an instance of a model class represent an actual item, or should it contain a number of methods for doing stuff - sometimes to one car or sometimes to multiple cars based on my example earlier.

For example I want to get all the cars from a the database and show them in the view. Am I right in think it should be along the lines of this?

Controller File

function list() {
    $cars = $this->model->get_all();
    $this->view->add($cars);
    $this->view->render('cars-list');
}

Model File

function get_all() {
    // Use a database interaction class that I've written 
    $cars = Database::select();

    return $cars;
}

Now, if the car had a "status" field that was stored as an integer in the database and I wanted to change that to a string, where should that be done? By looping the SQL results array in the get_all() method in the model?

Also, where should form validation live? I have written a validation class that works a little like this:

$validator = new Validator();    
$validator->check('field_name', 'required');

If the check fails, it adds an error message to the array in the Validator. This array of error messages would then get passed to the view. Should the use of my validator class go in model or the controller?

Thanks in advance for for any help anyone can offer. If you know of any links to a simple MVC example / open source application that deals with basic CRUD, they would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

怀念你的温柔 2024-12-24 03:36:04

MVC 中的职责大致细分如下:

  • 模型:业务逻辑。很多人认为模型只是数据库的接口,但这是错误的。系统中的模型应该描述系统中的所有实体、它们的行为方式以及交互方式。数据访问只是其中的一小部分(甚至可以说应该分为自己的数据访问层,与模型、视图或控制器分开)。例如,在博客应用程序中,博客将具有帖子的集合,并且每个帖子可能具有(取决于博客应用程序实现的功能)评论的集合。这意味着实现一个博客类、一个帖子类和一个评论类。如果您选择删除帖子,则该帖子有责任确保它不会留下任何孤立评论。为此,您可以在帖子类中使用一个用于删除帖子的方法,并在评论类中使用类似的方法。当帖子发送删除消息时,作为删除过程的一部分,它将向与被删除帖子关联的所有评论发送删除消息。
  • 视图:表示逻辑。视图基本上是一个网页、一个 RSS 提要、一个 CSV 文件,实际上是您的应用程序可能输出给最终用户的任何类型的数据。它应该只显示已分配给它的变量。 (在视图中实现一些逻辑是可以的,只要它与输出数据有关。视图不必完全愚蠢)
  • 控制器:粘合逻辑。控制器基本上有两个工作要做:1)从模型中获取数据,将其注入视图并将其呈现给用户。 2)获取用户的输入,将其发送到适当的模型进行处理并将结果呈现给用户。这意味着控制器应该包含很少的代码,正是实现上面列出的两个目标所需的代码。

正如我已经提到的,许多人认为该模型只不过是一个数据访问层。您通常可以看出人们何时遵循这种设计理念,因为结果是模型没有做很多事情,而控制器做了太多事情(所谓的胖控制器反模式)。这种方法的问题在于,如果您想在其他项目中重用代码库的部分内容,那么您就无法在不带走大量控制器的情况下将模型转移到新项目中。控制器通常被认为是特定于应用程序的,因此不可重用。另一方面,模型体现了应用程序中的实体,并且您可能有多个需要使用相同类型实体的应用程序(博客软件、电子商务店面和留言板都是非常不同的应用程序,但它们都需要来实现用户)。

一般来说,您需要胖模型(可以轻松地重用,无需复制模型本身未实现的代码)和瘦控制器(当您需要模型执行其他操作时可以轻松替换)。

不过,验证有点阻碍了工作,因为这就是所谓的横切关注点。 MVC 的思想是关注点分离之一,因为它的目标是将代码描述为属于 3 个主要类别之一(业务逻辑、表示逻辑、粘合逻辑),但验证并不容易适合其中任何一个。可以提出很好的论据,因为它既是业务逻辑又是粘合逻辑,并且如果您想向用户显示验证错误,那么它也有表示逻辑的元素。

一般来说,我在模型中实现一定程度的验证,通常是相当基本的健全性检查(例如要求整数实际上是内部值等),并实现一组单独的类来对输入进行完整验证。我将在控制器中调用验证类,如果验证失败,我会将结果呈现给视图。如果成功,则数据将发送到相关模型进行处理。我想您可以将验证称为“实用程序逻辑”,这是您需要定期执行的操作,但不能真正与任何一个模型、视图或控制器绑定。

The general breakdown of responsibilities in MVC is generally as follows:

  • Model: Business logic. A lot of people think the model is simply an interface to the database, but this is incorrect. The models in your system should describe all the entities in your system, how they behave and how they interact. Data access is only a small part of this (and arguably should even be partitioned off into its own data-access layer separate from the model, view or controller). For example, in a blogging application, a blog will have a collection of posts, and each post may have (depending on the features the blogging app implements) a collection of comments. This would mean implementing a blog class, a post class and a comment class. Should you choose to delete a post, then it's the responsibility of the post to ensure it doesn't leave any orphan comments behind. You'd do this by having a method in the post class for deleting a post, and a similar method in the comment class. When the post gets sent the delete message, it will as part of the deletion process send a delete message to all the comments associated with the post being deleted.
  • View: Presentation logic. A view is basically a web page, an RSS feed, a CSV file, in fact any kind of data that your application might output to the end user. It should just display the variables that have been assigned to it. (It is okay to implement some logic in the view provided it's to do with outputting data. Views don't have to be completely dumb)
  • Controller: Glue logic. The controller has basically two jobs to do: 1) Take data from a model, inject it into a view and present it to the user. 2) Take input from the user, send it to the appropriate model for processing and present the results to the user. This means that the controller should contain very little code, just what's needed for achieving the two goals listed above.

As I already mentioned, many people think the model is little more than a data access layer. You can usually tell when people have followed this design philosophy because the result is models that don't do a lot, and controllers that do too much (the so called Fat Controller anti-pattern). The problem with this approach is that if you want to reuse portions of your codebase in some other project, then you can't take the model over to the new project without taking a big chunk of the controller along with it. Controllers are generally considered to be application-specific and therefore non-reusable. Models, on the other hand, embody entities in your application, and you might have several applications that require the use of the same type of entity (Blogging software, e-commerce storefronts and message boards are all very different applications, but they all need to implement users).

Generally, you want fat models (which can be easily reused without copying code not implemented in the model itself) and skinny controllers (that can easily be replaced when you need your model to do something else).

Validation kind of throws a spanner in the works though, as it's what's called a cross-cutting concern. The idea of MVC is one of separation of concerns as it aims to characterize code as falling into one of 3 major categories (business logic, presentation logic, glue logic), but validation doesn't easily fit into any of those. Good arguments can be made for it being both business and glue logic, and if you want to display validation errors to the user, then it's also got an element of presentation logic as well.

Generally, I implement a level of validation in my models, generally fairly basic sanity checks (such as requiring that integers are actually inter values and the like), and implementing a separate set of classes for doing full validation of input. I'll invoke the validation classes in my controller and if validation fails there I'll present the results to the view. If it succeeds then the data gets sent to the relevant model for processing. I suppose you could call validation "utility logic", something you need to do in a regular basis that you can't really tie to any one model, view, or controller.

半山落雨半山空 2024-12-24 03:36:04

我强烈建议您看一下 马丁·福勒。它很好地解释了每个 MVC 组件的每个职责分离(以及许多其他有用的模式)。

在紧要关头,维基百科对 MVC。

简而言之,您设置的结构是正确的。您的控制器通知模型发生了某些事件,模型对该事件做出反应,然后视图使用模型向最终用户表示系统的状态。验证应该在您的模型中执行,因为它负责维护系统的正确状态。您还可能有一些客户端验证,严格来说是为了减少网络流量并为用户提供更好的界面。

要记住的一件事是您希望将业务逻辑保留在模型中。您要尽量避免所谓的贫血域模型。当您的模型只是数据库上的薄层时,这是非常典型的。

我推荐的另一本书是 Eric Evans 所著的《领域驱动设计:解决软件复杂性》DDD 的重点是“主要重点应该放在域和域逻辑上”。

I would highly recommend you take a look at "Patterns of Enterprise Application Architecture" by Martin Fowler. It has a good explanation of what each of the separation of responsibilities are for each of the MVC components (plus a lot of other useful patterns).

In a pinch, wikipedia has an okay explanation of MVC.

In short, the structure you've setup is correct. You're controller is informing the model that some event has occurred, the model is reacting to that event, then the view is using the model to represent the state of the system to the end user. The validation should be performed within your Model, since it is responsible for maintaining the correct state of the system. You may also have some client-side validation which is strictly there to reduce network traffic and provide a nicer interface for the user.

One thing to keep in mind is that you want to keep your business logic within the Model. You want to try to avoid what's called an anemic domain model. This is pretty typical when your model is just a thin veneer over a database.

Another book I would recommend is by "Domain-Driven Design: Tackling Complexity in Software" by Eric Evans. The focus with DDD is that "the primary focus should be on the domain and domain logic".

你不是我要的菜∠ 2024-12-24 03:36:04

如果您希望状态字段在应用程序中被视为字符串,那么您不希望将其作为数据库中的整数的持久性详细信息从汽车类中泄露出来。在其接口中,它是一个字符串,因此应该对其进行处理。

因此,我将在 Car 类中使用 getStatus() 方法,只要需要,您就可以在 getAll() 之后调用该方法。您将在项目级别委派演员。最好不要让应用程序的其余部分知道您在最低级别有一个整数。从汽车中暴露一条字符串,并在应用程序的其余部分中继续使用它。

至于验证,我会在控制器中完成。您从视图中获取内容并确保它对于您的模型来说足够好。除非它是专门需要在模型中进行的检查(IE 业务相关约束)。

If you want the status field to be treated as a string within your application, you don't want the persistence detail of having it as an integer in your db to creep out from the car class. In its interface it's a string and as such it should be treated.

So, I'd use a getStatus() method in the Car class, which you'd invoke AFTER the getAll(), whenever you'd need it. You'd be delegating the cast at item level. It's better not to let the rest of your application to know that you have an integer at the lowest level. Expose a string from car and live on with it within the rest of your application.

As for the validation, I'd do it in the controller. You get stuff from the view and make sure it's good enough for your model. Unless it's a check which specifically needs to be made within the model (IE business relate constraint).

才能让你更想念 2024-12-24 03:36:04

首先,如果您不想使用任何 PHP 框架,您可以查看它们的源代码并获得有关某些功能实现的好主意。

验证怎么样,我认为它是一个业务逻辑功能,所以它必须放在控制器层。(编辑:这是个坏主意)

First of all, if you don't want use any PHP framework, you can look at their sources and get good ideas about some features implementation.

What about a validation, I think that it is a business-logic feature, so it must be placed at the controller layer. (edited: that is bad idea)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文