yii2基础(一)

运行应用




安装 Yii 后,就有了一个运行中的 Yii 应用,根据配置的不同,可以通过 `http://hostname/basic/web/index.php` 或 `http://hostname/index.php` 访问。本章节将介绍应用的内建功能,如何组织代码,以及一般情况下应用如何处理请求。


> 补充:为简单起见,在整个“入门”板块都假定你已经把 `basic/web` 设为 Web 服务器根目录并配置完毕,你访问应用的地址会是 `http://lostname/index.php` 或类似的。请按需调整 URL。

功能





一个安装完的基本应用包含四页:


*  主页,当你访问 `http://hostname/index.php` 时显示,
* “About” 页,
* “Contact” 页, 显示一个联系表单,允许终端用户通过 Email 联系你,
* “Login” 页, 显示一个登录表单,用来验证终端用户。试着用 “admin/admin” 登录,你可以看到当前是登录状态,已经可以“退出登录”了。

这些页面使用同一个头部和尾部。头部包含了一个可以在不同页面间切换的导航栏。
在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md),可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。

应用结构 ​






应用中最重要的目录和文件(假设应用根目录是 `basic`):

basic/                  应用根目录
    composer.json       Composer 配置文件, 描述包信息
    config/             包含应用配置及其它配置
        console.php     控制台应用配置信息
        web.php         Web 应用配置信息
    commands/           包含控制台命令类
    controllers/        包含控制器类
    models/             包含模型类
    runtime/            包含 Yii 在运行时生成的文件,例如日志和缓存文件
    vendor/             包含已经安装的 Composer 包,包括 Yii 框架自身
    views/              包含视图文件
    web/                Web 应用根目录,包含 Web 入口文件
        assets/         包含 Yii 发布的资源文件(javascript 和 css)
        index.php       应用入口文件
    yii                 Yii 控制台命令执行脚本

一般来说,应用中的文件可被分为两类:在 `basic/web` 下的和在其它目录下的。前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。

Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller)设计模式,这点在上述目录结构中也得以体现。 `models` 目录包含了所有[模型类],`views` 目录包含了所有[视图脚本],`controllers` 目录包含了所有[控制器类]。

以下图表展示了一个应用的静态结构:
[应用静态结构]

每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用]实例去处理它。 [应用]在它的[组建]辅助下解析请求,并分派请求至 MVC 元素。[视图]使用[小部件]去创建复杂和动态的用户界面。

请求生命周期 






以下图表展示了一个应用如何处理请求:


[请求生命周期]

1. 用户向[入口脚本]`web/index.php` 发起请求。
2. 入口脚本加载应用[配置]并创建一个[应用]实例去处理请求。
3. 应用通过[请求]组件解析请求的[路由]。
4. 应用创建一个[控制器]实例去处理请求。
5. 控制器创建一个[操作]实例并针对操作执行过滤器。
6. 如果任何一个过滤器返回失败,则操作退出。
7. 如果所有过滤器都通过,操作将被执行。
8. 操作会加载一个数据模型,或许是来自数据库。
9. 操作会渲染一个视图,把数据模型提供给它。
10. 渲染结果返回给[响应]组件。

11. 响应组件发送渲染结果给用户浏览器。


第一个程序HelloWorld:

说声 Hello




本章节描述了如何在你的应用中创建一个新的 “Hello” 页面。为了做到这点,将会创建一个[操作]和一个[视图]:

* 应用将会分派页面请求给操作
* 操作将会依次渲染视图呈现 “Hello” 给最终用户

贯穿整个章节,你将会掌握三件事:

1. 如何创建一个[操作]去响应请求,
2. 如何创建一个[视图]去构造响应内容,
3. 以及一个应用如何分派请求给[操作]。

创建操作 




为了说 “Hello”,需要创建一个 `say` [操作],从请求中接收 `message` 参数并显示给最终用户。如果请求没有提供 `message` 参数,操作将显示默认参数 “Hello”。


> 补充:[操作]是最终用户可以直接访问并执行的对象。操作被组织在[控制器]中。一个操作的执行结果就是最终用户收到的响应内容。

操作必须声明在[控制器]中。为了简单起见,你可以直接在 `SiteController` 控制器里声明 `say` 操作。这个控制器是由文件 `controllers/SiteController.php` 定义的。以下是一个操作的声明:
render('say', ['message' => $message]);
    }
}
在上述 `SiteController` 代码中,`say` 操作被定义为 `actionSay` 方法。Yii 使用 `action` 前缀区分普通方法和操作。`action` 前缀后面的名称被映射为操作的 ID。

涉及到给操作命名时,你应该理解 Yii 如何处理操作 ID。操作 ID 总是被以小写处理,如果一个操作 ID 由多个单词组成,单词之间将由连字符连接(如 `create-comment`)。操作 ID 映射为方法名时移除了连字符,将每个单词首字母大写,并加上 `action` 前缀。 例子:操作 ID `create-comment` 相当于方法名 `actionCreateComment`。

上述代码中的操作方法接受一个参数 `$message`,它的默认值是 `“Hello”`(就像你设置 PHP 中其它函数或方法的默认值一样)。当应用接收到请求并确定由 `say` 操作来响应请求时,应用将从请求的参数中寻找对应值传入进来。换句话说,如果请求包含一个 `message` 参数,它的值是 `“Goodybye”`, 操作方法中的 `$message` 变量也将被填充为 `“Goodbye”`。

在操作方法中,[[yii\web\Controller::render()|render()]] 被用来渲染一个名为 `say` 的[视图](structure-views.md)文件。 `message` 参数也被传入视图,这样就可以在里面使用。操作方法会返回渲染结果。结果会被应用接收并显示给最终用户的浏览器(作为整页 HTML 的一部分)。

创建视图 




[视图]是你用来生成响应内容的脚本。为了说 “Hello”,你需要创建一个 `say` 视图,以便显示从操作方法中传来的 `message` 参数。



`say` 视图应该存为 `views/site/say.php` 文件。当一个操作中调用了 [[yii\web\Controller::render()|render()]] 方法时,它将会按 `views/控制器 ID/视图名.php` 路径加载 PHP 文件。

注意以上代码,`message` 参数在输出之前被 [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。这很有必要,当参数来自于最终用户时,参数中可能隐含的恶意 JavaScript 代码会导致[跨站脚本(XSS)攻击](http://en.wikipedia.org/wiki/Cross-site_scripting)。

当然了,你大概会在 `say` 视图里放入更多内容。内容可以由 HTML 标签,纯文本,甚至 PHP 语句组成。实际上 `say` 视图就是一个由 [[yii\web\Controller::render()|render()]] 执行的 PHP 脚本。视图脚本输出的内容将会作为响应结果返回给应用。应用将依次输出结果给最终用户。

尝试下 ​




创建完操作和视图后,你就可以通过下面的 URL 访问新页面了:

http://hostname/index.php?r=site/say&message=Hello+World
[Hello World]

这个 URL 将会输出包含 “Hello World” 的页面,页面和应用里的其它页面使用同样的头部和尾部。

如果你省略 URL 中的 `message` 参数,将会看到页面只显示 “Hello”。这是因为 `message` 被作为一个参数传给 `actionSay()` 方法,当省略它时,参数将使用默认的 `“Hello”` 代替。

> 补充:新页面和其它页面使用同样的头部和尾部是因为 [[yii\web\Controller::render()|render()]] 方法会自动把 `say` 视图执行的结果嵌入称为[布局]的文件中,本例中是 `views/layouts/main.php`。

上面 URL 中的参数 `r` 需要更多解释。它代表[路由],是整个应用级的,指向特定操作的独立 ID。路由格式是 `控制器 ID/操作 ID`。应用接受请求的时候会检查参数,使用控制器 ID 去确定哪个控制器应该被用来处理请求。然后相应控制器将使用操作 ID 去确定哪个操作方法将被用来做具体工作。上述例子中,路由 `site/say` 将被解析至 `SiteController` 控制器和其中的 `say` 操作。因此 `SiteController::actionSay()` 方法将被调用处理请求。

> 补充:与操作一样,一个应用中控制器同样有唯一的 ID。控制器 ID 和操作 ID 使用同样的命名规则。控制器的类名源自于控制器 ID,移除了连字符,每个单词首字母大写,并加上 `Controller` 后缀。例子:控制器 ID `post-comment` 相当于控制器类名 `PostCommentController`。

总结 ​




通过本章节你接触了 MVC 设计模式中的控制器和视图部分。创建了一个操作作为控制器的一部分去处理特定请求。然后又创建了一个视图去构造响应内容。在这个小例子中,没有模型调用,唯一涉及到数据的地方是 `message` 参数。


你同样学习了 Yii 路由的相关内容,它是用户请求与控制器操作之间的桥梁。

下一章,你将学习如何创建一个模型,以及添加一个包含 HTML 表单的页面。


实用表单:

使用表单




本章节将介绍如何创建一个从用户那搜集数据的表单页。该页将显示一个包含 name 输入框和 email 输入框的表单。当搜集完这两部分信息后,页面将会显示用户输入的信息。

为了实现这个目标,除了创建一个[操作] 和两个[视图]外,还需要创建一个[模型]。

贯穿整个小节,你将会学到:

* 创建一个[模型](structure-models.md)代表用户通过表单输入的数据
* 声明规则去验证输入的数据
* 在[视图](structure-views.md)中生成一个 HTML 表单

创建模型 ​




模型类 `EntryForm` 代表从用户那请求的数据,该类如下所示并存储在 `models/EntryForm.php` 文件中。请参考[类自动加载] 章节获取更多关于类命名约定的介绍。
该类继承自 [[yii\base\Model]],Yii 提供的一个基类,通常用来表示数据。

> 补充:[[yii\base\Model]] 被用于普通模型类的父类并与数据表**无关**。[[yii\db\ActiveRecord]] 通常是普通模型类的父类但与数据表有关联(译者注:[[yii\db\ActiveRecord]] 类其实也是继承自 [[yii\base\Model]],增加了数据库处理)。

`EntryForm` 类包含 `name` 和 `email` 两个公共成员,用来储存用户输入的数据。它还包含一个名为 `rules()` 的方法,用来返回数据验证规则的集合。上面声明的验证规则表示:

* `name` 和 `email` 值都是必须的
* `mail` 的值必须满足 email 地址验证

如果你有一个从用户那搜集数据的 `EntryForm` 对象,你可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据验证。如果有数据验证失败,将把 [[yii\base\Model::hasErrors|hasErrors]] 属性设为 ture,想要知道具体发生什么错误就调用 [[yii\base\Model::getErrors|getErrors]]。
name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
    // 验证成功!
} else {
    // 失败!
    // 使用 $model->getErrors() 获取错误详情
}

创建操作 ​




下面你得在 `site` 控制器中创建一个 `entry` 操作用于新建的模型。操作的创建和使用已经在[说一声你好](start-hello.md)小节中解释了。
load(Yii::$app->request->post()) && $model->validate()) {
            // 验证 $model 收到的数据

            // 做些有意义的事 ...

            return $this->render('entry-confirm', ['model' => $model]);
        } else {
            // 无论是初始化显示还是数据验证错误
            return $this->render('entry', ['model' => $model]);
        }
    }
}
该操作首先创建了一个 `EntryForm` 对象。然后尝试从 `$_POST` 搜集用户提交的数据,由 Yii 的 [[yii\web\Request::post()]] 方法负责搜集。如果模型被成功填充数据(也就是说用户已经提交了 HTML 表单),操作将调用 [[yii\base\Model::validate()|validate()]] 去确保用户提交的是有效数据。

> 补充:表达式 `Yii::$app` 代表[应用] 实例,它是一个全局可访问的单例。同时它也是一个[服务定位器],能提供 `request`,`response`,`db` 等等特定功能的组件。在上面的代码里就是使用 `request` 组件来访问应用实例收到的 `$_POST` 数据。

用户提交表单后,操作将会渲染一个名为 `entry-confirm` 的视图去确认用户输入的数据。如果没填表单就提交,或数据包含错误(译者:如 email 格式不对),`entry` 视图将会渲染输出,连同表单一起输出的还有验证错误的详细信息。

> 注意:在这个简单例子里我们只是呈现了有效数据的确认页面。实践中你应该考虑使用 [[yii\web\Controller::refresh()|refresh()]] 或 [[yii\web\Controller::redirect()|redirect()]] 去避免[表单重复提交问题](http://en.wikipedia.org/wiki/Post/Redirect/Get)。

创建视图 ​




最后创建两个视图文件 `entry-confirm` 和 `entry`。他们会被刚才创建的 `entry` 操作渲染。

`entry-confirm` 视图简单地显示提交的 name 和 email 数据。视图文件保存在 `views/site/entry-confirm.php`。

You have entered the following information:

  • : name) ?>
  • : email) ?>
`entry` 视图显示一个 HTML 表单。视图文件保存在 `views/site/entry.php`。


    field($model, 'name') ?>
    field($model, 'email') ?>
    
'btn btn-primary']) ?>
视图使用了一个功能强大的[小部件](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]] 去生成 HTML 表单。其中的 `begin()` 和 `end()` 分别用来渲染表单的开始和关闭标签。在这两个方法之间使用了 [[yii\widgets\ActiveForm::field()|field()]] 方法去创建输入框。第一个输入框用于 “name”,第二个输入框用于 “email”。之后使用 [[yii\helpers\Html::submitButton()]] 方法生成提交按钮。

尝试下 ​




用浏览器访问下面的 URL 看它能否工作:
http://hostname/index.php?r=site/entry
你会看到一个包含两个输入框的表单的页面。每个输入框的前面都有一个标签指明应该输入的数据类型。如果什么都不填就点击提交按钮,或填入格式不正确的 email 地址,将会看到在对应的输入框下显示错误信息。
[验证错误的表单]
输入有效的 name 和 email 信息并提交后,将会看到一个显示你所提交数据的确认页面。
[输入数据的确认页]

### 效果说明 ​




你可能会好奇 HTML 表单暗地里是如何工作的呢,看起来它可以为每个输入框显示文字标签,而当你没输入正确的信息时又不需要刷新页面就能给出错误提示,似乎有些神奇。

是的,其实数据首先由客户端 JavaScript 脚本验证,然后才会提交给服务器通过 PHP 验证。[[yii\widgets\ActiveForm]] 足够智能到把你在 `EntryForm` 模型中声明的验证规则转化成客户端 JavaScript 脚本去执行验证。如果用户浏览器禁用了 JavaScript, 服务器端仍然会像 `actionEntry()` 方法里这样验证一遍数据。这保证了任何情况下用户提交的数据都是有效的。

> 警告:客户端验证是提高用户体验的手段。无论它是否正常启用,服务端验证则都是必须的,请不要忽略它。

输入框的文字标签是 `field()` 方法生成的,内容就是模型中该数据的属性名。例如模型中的 `name` 属性生成的标签就是 `Name`。

你可以在视图中自定义标签:
field($model, 'name')->label('自定义 Name') ?>
field($model, 'email')->label('自定义 Email') ?>
> 补充:Yii 提供了相当多类似的小部件去帮你生成复杂且动态的视图。在后面你还会了解到自己写小部件是多么简单。你可能会把自己的很多视图代码转化成小部件以提高重用,加快开发效率。

总结 




本章节指南中你接触了 MVC 设计模式的每个部分。学到了如何创建一个模型代表用户数据并验证它的有效性。

你还学到了如何从用户那获取数据并在浏览器上回显给用户。这本来是开发应用的过程中比较耗时的任务,好在 Yii 提供了强大的小部件让它变得如此简单。

下一章你将学习如何使用数据库,几乎每个应用都需要数据库。

你可能感兴趣的:(yii/yii2)