模型
模型(Model)是在应用程序中构成业务层的类。它们应当负责管理几乎所有涉及数据的事情,譬如数据的合法性,数据间的交互,以及整个业务领域中数据在工作流程中的演化。
通常模型类用来表示数据,并且在 CakePHP 应用程序中用来访问数据。它们通常代表数据库中的表,但也可用于访问任何操控数据的东西,比如文件,外部网络服务,iCal 日程。
一个模型可以与其他模型关联。例如,一份菜谱可以和菜谱的作者关联,也可以和菜谱的原料相关联。
本章中我们将解释模型的哪些特性可以自动化,如何改变这些特性,以及模型有哪些方法和属性。我们会解释关联数据的各种方式。我们还将描述如何查找,保存和删除数据。最后,我们来看一下数据源(Datasource)。
理解模型
模型代表数据模型。在面向对象编程中数据模型是表示"事物"的对象,比如,汽车,人,或者房子。例如,一个博客(blog)可以有多篇文章(post),每篇文章又可以有多条评论(comment)。博客(Blog),文章(Post)和评论(Comment)就是彼此关联的模型的例子。
这里有一个 CakePHP 模型定义的简单例子:
- App::uses('AppModel', 'Model');
- class Ingredient extends AppModel {
- public $name = 'Ingredient';
- }
仅需这样简单的声明,Ingredient 模型就具备了所有用来生成查询以及保存和删除数据的功能。这些魔术般的方法来自 CakePHP 的 Model 类,得益于继承的魔法。Ingredient 模型扩展了应用程序的模型 AppModel,而 AppModel 又扩展了 CakePHP 内部的 Model 类。就是这个核心的 Model 类赋予你的 Ingredient 模型这些功能的。App::uses('AppModel', 'Model')
保证模型在每次使用时都加载了。
这个中间的类 AppModel 是空的。如果你没有自己创建,则会从 CakePHP 内核文件夹中取得。重载 AppModel,让你可以定义应用程序中所有的模型都具备的功能。为此,你需要在 Model文件夹中创建自己的 AppModel.php
,就象应用程序中所有其他的模型一样。使用Bake 创建项目,就会为你自动生成这个文件。
欲知如何在多个模型中使用相似的逻辑的更多信息,也可参看Behaviors。
回到我们的 Ingredient 模型。为此,在 /app/Model/
目录中创建一个 PHP 文件。按照约定,文件名应该和类名一样,在本例中就是 Ingredient.php
。
注解
如果 CakePHP 在 /app/Model 目录中无法找到对应的文件,它就会为你动态创建一个模型对象。这也意味着,如果你的模型文件命名不正确(比如,把它命名为ingredient.php 或者 Ingredients.php,而不是 Ingredient.php),CakePHP 就会使用AppModel 的实例,而不是你的模型文件(CakePHP 认为是缺失的)。如果你试图使用在你的模型中定义的方法,或者你的模型上附加的行为,然而你得到的却是关于你调用的方法的名称的 SQL 错误 —— 这明显是因为 CakePHP 无法找到你的模型,那么你要检查文件名、应用程序缓存,或者两者都要检查。
注解
某些类名是无法作为模型名称的。例如,"File" 无法使用,因为 "File" 是 CakePHP内核中已经存在的一个类了。
模型定义了之后,就可以在 控制器 (Controller)中使用了。如果模型名称与控制器名称匹配,CakePHP 就会自动使该模型可以访问。例如,一个名为IngredientsController 的控制器会自动初始化 Ingredient 模型,并把它附加在控制器上,作为 $this->Ingredient
:
- class IngredientsController extends AppController {
- public function index() {
- //获得所有原料并把它传给视图:
- $ingredients = $this->Ingredient->find('all');
- $this->set('ingredients', $ingredients);
- }
- }
关联的模型可以从主模型访问。在下例中,Recipe 模型与 Ingredient 模型有关联:
- class Recipe extends AppModel {
- public function steakRecipes() {
- $ingredient = $this->Ingredient->findByName('Steak');
- return $this->findAllByMainIngredient($ingredient['Ingredient']['id']);
- }
- }
这里展示了如何使用已经关联在一起的模型。要明白关联是如何定义的,请看模型的关联一节。