php MVC 中的模型应该如何构建?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5863870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 22:44:04  来源:igfitidea点击:

How should a model be structured in MVC?

phpoopmodel-view-controllerarchitecturemodel

提问by Dietpixel

I am just getting a grasp on the MVC framework and I often wonder how much code should go in the model. I tend to have a data access class that has methods like this:

我刚刚掌握了 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;
    }
}

My models tend to be an entity class that is mapped to the database table.

我的模型往往是映射到数据库表的实体类。

Should the model object have all the database mapped properties as well as the code above or is it OK to separate that code out that actually does the database work?

模型对象是否应该具有所有数据库映射属性以及上面的代码,还是可以将该代码与数据库实际工作的代码分开?

Will I end up having four layers?

我最终会有四层吗?

回答by tere?ko

Disclaimer:the following is a description of how I understand MVC-like patterns in the context of PHP-based web applications. All the external links that are used in the content are there to explain terms and concepts, and notto imply my own credibility on the subject.

免责声明:以下是我如何理解基于 PHP 的 Web 应用程序上下文中的类 MVC 模式的描述。内容中使用的所有外部链接都是为了解释术语和概念,而不是暗示我自己对该主题的可信度。

The first thing that I must clear up is: the model is a layer.

我必须澄清的第一件事是:模型是一个 layer

Second: there is a difference between classical MVCand what we use in web development. Here'sa bit of an older answer I wrote, which briefly describes how they are different.

第二:经典 MVC与我们在 Web 开发中使用的不同。这是我写的一个较旧的答案,它简要描述了它们的不同之处。

What a model is NOT:

模型不是什么:

The model is not a class or any single object. It is a very common mistake to make (I did too, though the original answer was written when I began to learn otherwise), because most frameworks perpetuate this misconception.

模型不是一个类或任何单个对象。这是一个非常常见的错误(我也犯过,虽然最初的答案是在我开始学习时写的),因为大多数框架都延续了这种误解。

Neither is it an Object-Relational Mapping technique (ORM) nor an abstraction of database tables. Anyone who tells you otherwise is most likely trying to 'sell'another brand-new ORM or a whole framework.

它既不是对象关系映射技术 (ORM),也不是数据库表的抽象。任何告诉你其他情况的人很可能试图“出售”另一个全新的 ORM 或整个框架。

What a model is:

什么是模型:

In proper MVC adaptation, the M contains all the domain business logic and the Model Layeris mostlymade from three types of structures:

在适当的MVC改编,M含有所有域业务逻辑和模型层主要由三种类型的结构制成:

  • Domain Objects

    A domain object is a logical container of purely domain information; it usually represents a logical entity in the problem domain space. Commonly referred to as business logic.

    This would be where you define how to validate data before sending an invoice, or to compute the total cost of an order. At the same time, Domain Objectsare completely unaware of storage - neither from where(SQL database, REST API, text file, etc.) nor even ifthey get saved or retrieved.

  • Data Mappers

    These objects are only responsible for the storage. If you store information in a database, this would be where the SQL lives. Or maybe you use an XML file to store data, and your Data Mappersare parsing from and to XML files.

  • Services

    You can think of them as "higher level Domain Objects", but instead of business logic, Servicesare responsible for interaction between Domain Objectsand Mappers. These structures end up creating a "public" interface for interacting with the domain business logic. You can avoid them, but at the penalty of leaking some domain logic into Controllers.

    There is a related answer to this subject in the ACL implementationquestion - it might be useful.

  • 领域对象

    域对象是纯域信息的逻辑容器;它通常代表问题域空间中的一个逻辑实体。通常称为业务逻辑

    这将是您定义如何在发送发票之前验证数据或计算订单总成本的地方。与此同时,域对象完全不知道存储-无论从哪里(SQL数据库,REST API,文本文件等),甚至也不是,如果他们得到保存或检索。

  • 数据映射器

    这些对象只负责存储。如果您将信息存储在数据库中,这将是 SQL 所在的位置。或者,您可能使用 XML 文件来存储数据,而您的数据映射器正在解析 XML 文件和解析 XML 文件。

  • 服务

    您可以将它们视为“更高级别的域对象”,但服务负责域对象映射器之间的交互,而不是业务逻辑。这些结构最终创建了一个用于与域业务逻辑交互的“公共”接口。您可以避免它们,但代价是将某些域逻辑泄漏到Controllers 中

    ACL implementationquestion 中有一个与此主题相关的答案- 它可能有用。

The communication between the model layer and other parts of the MVC triad should happen only through Services. The clear separation has a few additional benefits:

模型层和 MVC 三元组的其他部分之间的通信应该只通过服务发生。清晰的分离还有一些额外的好处:

  • it helps to enforce the single responsibility principle(SRP)
  • provides additional 'wiggle room' in case the logic changes
  • keeps the controller as simple as possible
  • gives a clear blueprint, if you ever need an external API
  • 它有助于执行单一责任原则(SRP)
  • 提供额外的“摆动空间”以防逻辑发生变化
  • 使控制器尽可能简单
  • 提供清晰的蓝图,如果您需要外部 API

 

 

How to interact with a model?

如何与模型交互?

Prerequisites:watch lectures "Global State and Singletons"and "Don't Look For Things!"from the Clean Code Talks.

先决条件:观看讲座“全局状态和单身人士”“不要寻找事物!” 来自清洁代码会谈。

Gaining access to service instances

访问服务实例

For both the Viewand Controllerinstances (what you could call: "UI layer") to have access these services, there are two general approaches:

对于ViewController实例(您可以称之为:“UI 层”)访问这些服务,有两种通用方法:

  1. You can inject the required services in the constructors of your views and controllers directly, preferably using a DI container.
  2. Using a factory for services as a mandatory dependency for all of your views and controllers.
  1. 您可以直接在视图和控制器的构造函数中注入所需的服务,最好使用 DI 容器。
  2. 使用服务工厂作为所有视图和控制器的强制依赖项。

As you might suspect, the DI container is a lot more elegant solution (while not being the easiest for a beginner). The two libraries, that I recommend considering for this functionality would be Syfmony's standalone DependencyInjection componentor Auryn.

您可能会怀疑,DI 容器是一个更优雅的解决方案(虽然对于初学者来说不是最简单的)。我建议为此功能考虑的两个库是 Syfmony 的独立DependencyInjection 组件Auryn

Both the solutions using a factory and a DI container would let you also share the instances of various servers to be shared between the selected controller and view for a given request-response cycle.

使用工厂和 DI 容器的解决方案都可以让您共享各种服务器的实例,以便在给定的请求-响应周期内在选定的控制器和视图之间共享。

Alteration of model's state

模型状态的改变

Now that you can access to the model layer in the controllers, you need to start actually using them:

现在您可以访问控制器中的模型层,您需要开始实际使用它们:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $identity = $this->identification->findIdentityByEmailAddress($email);
    $this->identification->loginWithPassword(
        $identity,
        $request->get('password')
    );
}

Your controllers have a very clear task: take the user input and, based on this input, change the current state of business logic. In this example the states that are changed between are "anonymous user" and "logged in user".

您的控制器有一个非常明确的任务:接收用户输入,并根据此输入更改业务逻辑的当前状态。在这个例子中,状态在“匿名用户”和“登录用户”之间改变。

Controller is not responsible for validating user's input, because that is part of business rules and controller is definitely not calling SQL queries, like what you would see hereor here(please don't hate on them, they are misguided, not evil).

控制器不负责验证用户的输入,因为这是业务规则的一部分,控制器绝对不会调用 SQL 查询,就像您在此处此处看到的那样(请不要讨厌它们,它们是被误导的,而不是邪恶的)。

Showing user the state-change.

向用户显示状态变化。

Ok, user has logged in (or failed). Now what?Said user is still unaware of it. So you need to actually produce a response and that is the responsibility of a view.

好的,用户已登录(或失败)。怎么办?所述用户仍然不知道它。所以你需要实际产生一个响应,这是视图的责任。

public function postLogin()
{
    $path = '/login';
    if ($this->identification->isUserLoggedIn()) {
        $path = '/dashboard';
    }
    return new RedirectResponse($path); 
}

In this case, the view produced one of two possible responses, based on the current state of model layer. For a different use-case you would have the view picking different templates to render, based on something like "current selected of article" .

在这种情况下,视图会根据模型层的当前状态生成两种可能的响应之一。对于不同的用例,您可以让视图根据“当前选择的文章”之类的内容选择不同的模板进行渲染。

The presentation layer can actually get quite elaborate, as described here: Understanding MVC Views in PHP.

表示层实际上可以变得非常复杂,如下所述:Understanding MVC Views in PHP

But I am just making a REST API!

但我只是在制作一个 REST API!

Of course, there are situations, when this is a overkill.

当然,在某些情况下,这是一种矫枉过正的情况。

MVC is just a concrete solution for Separation of Concernsprinciple. MVC separates user interface from the business logic, and it in the UI it separated handling of user input and the presentation.This is crucial. While often people describe it as a "triad", it's not actually made up from three independent parts. The structure is more like this:

MVC 只是关注点分离原则的具体解决方案。MVC 将用户界面与业务逻辑分开,并在 UI 中将用户输入的处理和呈现分开。这是至关重要的。虽然人们经常将其描述为“三合会”,但它实际上并不是由三个独立的部分组成。结构更像这样:

MVC separation

MVC分离

It means, that, when your presentation layer's logic is close to none-existent, the pragmatic approach is to keep them as single layer. It also can substantially simplify some aspects of model layer.

这意味着,当您的表示层的逻辑几乎不存在时,实用的方法是将它们保持为单层。它还可以大大简化模型层的某些方面。

Using this approach the login example (for an API) can be written as:

使用这种方法,登录示例(对于 API)可以写为:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $data = [
        'status' => 'ok',
    ];
    try {
        $identity = $this->identification->findIdentityByEmailAddress($email);
        $token = $this->identification->loginWithPassword(
            $identity,
            $request->get('password')
        );
    } catch (FailedIdentification $exception) {
        $data = [
            'status' => 'error',
            'message' => 'Login failed!',
        ]
    }

    return new JsonResponse($data);
}

While this is not sustainable, when you have complicate logic for rendering a response body, this simplification is very useful for more trivial scenarios. But be warned, this approach will become a nightmare, when attempting to use in large codebases with complex presentation logic.

虽然这是不可持续的,但当您有复杂的逻辑来呈现响应主体时,这种简化对于更琐碎的场景非常有用。但请注意,当尝试在具有复杂表示逻辑的大型代码库中使用时,这种方法将成为一场噩梦。

 

 

How to build the model?

如何建立模型?

Since there is not a single "Model" class (as explained above), you really do not "build the model". Instead you start from making Services, which are able to perform certain methods. And then implement Domain Objectsand Mappers.

由于没有单个“模型”类(如上所述),因此您实际上并没有“构建模型”。相反,您从制作能够执行某些方法的Services开始。然后实现域对象映射器

An example of a service method:

服务方法的一个例子:

In the both approaches above there was this login method for the identification service. What would it actually look like. I am using a slightly modified version of the same functionality from a library, that I wrote .. because I am lazy:

在上述两种方法中,身份识别服务都有这种登录方法。它实际上会是什么样子。我正在使用库中相同功能的略微修改版本,我编写了 .. 因为我很懒:

public function loginWithPassword(Identity $identity, string $password): string
{
    if ($identity->matchPassword($password) === false) {
        $this->logWrongPasswordNotice($identity, [
            'email' => $identity->getEmailAddress(),
            'key' => $password, // this is the wrong password
        ]);

        throw new PasswordMismatch;
    }

    $identity->setPassword($password);
    $this->updateIdentityOnUse($identity);
    $cookie = $this->createCookieIdentity($identity);

    $this->logger->info('login successful', [
        'input' => [
            'email' => $identity->getEmailAddress(),
        ],
        'user' => [
            'account' => $identity->getAccountId(),
            'identity' => $identity->getId(),
        ],
    ]);

    return $cookie->getToken();
}

As you can see, at this level of abstraction, there is no indication of where the data was fetched from. It might be a database, but it also might be just a mock object for testing purposes. Even the data mappers, that are actually used for it, are hidden away in the privatemethods of this service.

正如您所看到的,在这个抽象级别上,没有指示数据是从哪里获取的。它可能是一个数据库,但也可能只是一个用于测试目的的模拟对象。甚至实际用于它的数据映射器也隐藏在private此服务的方法中。

private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(Mapper\Identity::class);
    $mapper->store($identity);
}

Ways of creating mappers

创建映射器的方法

To implement an abstraction of persistence, on the most flexible approaches is to create custom data mappers.

要实现持久性的抽象,最灵活的方法是创建自定义数据映射器

Mapper diagram

映射器图

From: PoEAAbook

来自:PoEAA

In practice they are implemented for interaction with specific classes or superclasses. Lets say you have Customerand Adminin your code (both inheriting from a Usersuperclass). Both would probably end up having a separate matching mapper, since they contain different fields. But you will also end up with shared and commonly used operations. For example: updating the "last seen online"time. And instead of making the existing mappers more convoluted, the more pragmatic approach is to have a general "User Mapper", which only update that timestamp.

在实践中,它们是为与特定类或超类交互而实现的。假设您有CustomerAdmin在您的代码中(都继承自User超类)。两者最终可能都有一个单独的匹配映射器,因为它们包含不同的字段。但是您最终也会得到共享和常用的操作。例如:更新“最后一次在线查看”时间。而不是让现有的映射器更复杂,更实用的方法是拥有一个通用的“用户映射器”,它只更新那个时间戳。

Some additional comments:

一些补充意见:

  1. Database tables and model

    While sometimes there is a direct 1:1:1 relationship between a database table, Domain Object, and Mapper, in larger projects it might be less common than you expect:

    • Information used by a single Domain Objectmight be mapped from different tables, while the object itself has no persistence in the database.

      Example:if you are generating a monthly report. This would collect information from different of tables, but there is no magical MonthlyReporttable in the database.

    • A single Mappercan affect multiple tables.

      Example:when you are storing data from the Userobject, this Domain Objectcould contain collection of other domain objects - Groupinstances. If you alter them and store the User, the Data Mapperwill have to update and/or insert entries in multiple tables.

    • Data from a single Domain Objectis stored in more than one table.

      Example:in large systems (think: a medium-sized social network), it might be pragmatic to store user authentication data and often-accessed data separately from larger chunks of content, which is rarely required. In that case you might still have a single Userclass, but the information it contains would depend of whether full details were fetched.

    • For every Domain Objectthere can be more than one mapper

      Example:you have a news site with a shared codebased for both public-facing and the management software. But, while both interfaces use the same Articleclass, the management needs a lot more info populated in it. In this case you would have two separate mappers: "internal" and "external". Each performing different queries, or even use different databases (as in master or slave).

  2. A view is not a template

    Viewinstances in MVC (if you are not using the MVP variation of the pattern) are responsible for the presentational logic. This means that each Viewwill usually juggle at least a few templates. It acquires data from the Model Layerand then, based on the received information, chooses a template and sets values.

    One of the benefits you gain from this is re-usability. If you create a ListViewclass, then, with well-written code, you can have the same class handing the presentation of user-list and comments below an article. Because they both have the same presentation logic. You just switch templates.

    You can use either native PHP templatesor use some third-party templating engine. There also might be some third-party libraries, which are able to fully replace Viewinstances.

  3. What about the old version of the answer?

    The only major change is that, what is called Modelin the old version, is actually a Service. The rest of the "library analogy" keeps up pretty well.

    The only flaw that I see is that this would be a really strange library, because it would return you information from the book, but not let you touch the book itself, because otherwise the abstraction would start to "leak". I might have to think of a more fitting analogy.

  4. What is the relationship between Viewand Controllerinstances?

    The MVC structure is composed of two layers: ui and model. The main structures in the UI layerare views and controller.

    When you are dealing with websites that use MVC design pattern, the best way is to have 1:1 relation between views and controllers. Each view represents a whole page in your website and it has a dedicated controller to handle all the incoming requests for that particular view.

    For example, to represent an opened article, you would have \Application\Controller\Documentand \Application\View\Document. This would contain all the main functionality for UI layer, when it comes to dealing with articles (of course you might have some XHRcomponents that are not directly related to articles).

  1. 数据库表和模型

    虽然有时数据库表、Domain ObjectMapper之间存在直接的 1:1:1 关系,但在较大的项目中,它可能没有您预期的那么常见:

    • 单个域对象使用的信息可能来自不同的表,而对象本身在数据库中没有持久性。

      示例:如果您正在生成月度报告。这会从不同的表中收集信息,但MonthlyReport数据库中没有神奇的表。

    • 单个Mapper可以影响多个表。

      示例:当您从User对象存储数据时,此域对象可能包含其他域对象的集合 -Group实例。如果您更改它们并存储User,则数据映射器将不得不在多个表中更新和/或插入条目。

    • 来自单个域对象的数据存储在多个表中。

      示例:在大型系统中(想想:中型社交网络),将用户身份验证数据和经常访问的数据与大块内容分开存储可能是务实的,这很少需要。在这种情况下,您可能仍然只有一个User类,但它包含的信息将取决于是否获取了完整的详细信息。

    • 对于每个域对象,可以有多个映射器

      示例:您有一个新闻网站,其中包含面向公众和管理软件的共享代码。但是,虽然两个接口都使用相同的Article类,但管理需要在其中填充更多信息。在这种情况下,您将有两个单独的映射器:“内部”和“外部”。每个执行不同的查询,甚至使用不同的数据库(如在 master 或 slave 中)。

  2. 视图不是模板

    MVC 中的视图实例(如果您不使用模式的 MVP 变体)负责表示逻辑。这意味着每个视图通常会处理至少几个模板。它从模型层获取数据,然后根据接收到的信息选择模板并设置值。

    您从中获得的好处之一是可重用性。如果您创建一个ListView类,那么,使用编写良好的代码,您可以让同一个类处理文章下方的用户列表和评论的呈现。因为它们都具有相同的呈现逻辑。您只需切换模板。

    您可以使用本机 PHP 模板或使用某些第三方模板引擎。也可能有一些第三方库,它们能够完全替代View实例。

  3. 旧版本的答案呢?

    唯一的主要变化是,旧版本中所谓的Model,实际上是一个Service。“图书馆类比”的其余部分保持得很好。

    我看到的唯一缺陷是这将是一个非常奇怪的图书馆,因为它会从书中返回信息,但不会让您接触书本身,否则抽象将开始“泄漏”。我可能得想一个更合适的比喻。

  4. ViewController实例之间是什么关系?

    MVC结构由两层组成:ui和model。UI 层的主要结构是视图和控制器。

    当您处理使用 MVC 设计模式的网站时,最好的方法是在视图和控制器之间建立 1:1 的关系。每个视图代表您网站中的整个页面,它有一个专用控制器来处理该特定视图的所有传入请求。

    例如,要表示已打开的文章,您可以使用\Application\Controller\Document\Application\View\Document。这将包含 UI 层的所有主要功能,当涉及到处理文章时(当然,您可能有一些与文章没有直接关系的XHR组件)

回答by netcoder

Everything that is business logicbelongs in a model, whether it is a database query, calculations, a REST call, etc.

所有业务逻辑都属于模型,无论是数据库查询、计算、REST 调用等。

You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.

您可以在模型本身中访问数据,MVC 模式不限制您这样做。你可以用服务、映射器等等来修饰它,但模型的实际定义是一个处理业务逻辑的层,仅此而已。如果你想要的话,它可以是一个类、一个函数或一个包含无数对象的完整模块。

It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):

拥有一个单独的对象来实际执行数据库查询总是更容易,而不是直接在模型中执行它们:这在单元测试时特别有用(因为在模型中注入模拟数据库依赖项很容易):

class Database {
   protected $_conn;

   public function __construct($connection) {
       $this->_conn = $connection;
   }

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.

此外,在 PHP 中,您很少需要捕获/重新抛出异常,因为保留了回溯,尤其是在您的示例中。只需抛出异常并在控制器中捕获它即可。

回答by mario

In Web-"MVC" you can do whatever you please.

在 Web-“MVC”中,您可以随心所欲。

The original concept (1)described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".

最初的概念(1)将模型描述为业务逻辑。它应该代表应用程序状态并强制执行一些数据一致性。这种方法通常被描述为“胖模型”。

Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.

大多数 PHP 框架遵循更浅的方法,其中模型只是一个数据库接口。但至少这些模型仍应验证传入的数据和关系。

Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)

无论哪种方式,如果您将 SQL 内容或数据库调用分离到另一层中,您就不会太远。这样你只需要关心真实的数据/行为,而不是实际的存储 API。(然而,过度使用它是不合理的。如果没有提前设计,您将永远无法用文件存储替换数据库后端。)

回答by feel good and programming

More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,Vand C.

更常见的是,大多数应用程序都有数据、显示和处理部分,我们只是将所有这些都放在字母M,V和 中C

Model(M)-->Has the attributes that holds state of application and it dont know any thing about Vand C.

Model( M)--> 具有保存应用程序状态的属性,它对Vand一无所知C

View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.

View( V)--> 具有应用程序的显示格式,并且只知道如何在其上消化模型而不关心C.

Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,Vunlike Mand V.

Controller( C)---->具有应用程序的处理部分,充当 M 和 V 之间的接线,它依赖于两者MVM和不同V

Altogether there is separation of concern between each. In future any change or enhancements can be added very easily.

总而言之,每个人之间都有关注点的分离。将来可以非常轻松地添加任何更改或增强功能。

回答by Ibu

In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQLto PostgreSQLthere won't be any problem. So adding that extra layer can be useful.

就我而言,我有一个数据库类来处理所有直接的数据库交互,例如查询、获取等。因此,如果我不得不将我的数据库从MySQL更改为PostgreSQL,则不会有任何问题。所以添加额外的层会很有用。

Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:

每个表都可以有自己的类和特定的方法,但要真正获取数据,它让数据库类来处理它:

File Database.php

文件 Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

Table object classL

表对象类L

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

I hope this example helps you create a good structure.

我希望这个例子可以帮助你创建一个好的结构。