2:Yii基础知识(Yii权威指南)

Yii典型的工作流
下图展示了一个 Yii 应用在处理用户请求时典型的工作流。
2:Yii基础知识(Yii权威指南)_第1张图片
 

应用或前端控制器
应用是指请求处理中的执行上下文。它的主要任务是分析用户请求并将其分派到合适的控制器中以作进一步处理。 它同时作为服务中心,维护应用级别的配置。鉴于此,应用也叫做前端控制器。
应用由 入口脚本 创建为一个单例对象。这个应用单例对象可以在任何地方通过 Yii::app() 访问。

应用配置
我们通常将应用配置放在protected/config/main.php中,里面我们可以自定义一些配置如:
array(
   'name'=>'Yii Framework',
   'defaultController'=>'site',
   ...
)
然后我们继续查看入口文件,可以看到加载Application的方法是读取此配置文件:
$config=dirname(__FILE__).'/protected/config/main.php'; 
Yii::createWebApplication($config)->run();

应用组件
通过配置应用的 components 属性, 我们可以自定义应用中用到的任何组件类及其属性值。例如,我们可以配置应用的 CMemCache 组件, 这样它就可以使用多个 memcache 服务器实现缓存:
array(
    ......
    'components'=>array(
        ......
        'cache'=>array(
            'class'=>'CMemCache',
            'servers'=>array(
                array('host'=>'server1', 'port'=>11211, 'weight'=>60),
                array('host'=>'server2', 'port'=>11211, 'weight'=>40),
            ),
        ),
    ),
)
如上所示,我们在 components 数组中添加了 cache 元素。cache 元素表明此组件的类是 CMemCache, 他的 servers 属性应依此初始化。

要访问一个应用组件,使用 Yii::app()->ComponentID ,其中的 ComponentID 是指组件的ID(例如 Yii::app()->cache)。
应用的组件可以通过在其配置中设置 enabled 为 false 禁用。当我们访问被禁用的组件时将返回 Null。
注:默认情况下,应用组件会按需创建。这意味着一个应用的组件如果没有在一个用户请求中被访问,它可能根本不被创建。 因此,如果一个应用配置了很多组件,其总体性能可能并不会下降。有的应用组件 (例如 CLogRouter) 可能需要在无论它们是否被访问的情况下都要被创建。 要实现这个,需将其ID列在应用的 preload 属性里。


核心应用组件
我们可以在protected/config/main.php里面看到默认的一些核心应用组件。
  • assetManager: CAssetManager - 管理私有资源文件的发布。

  • authManager: CAuthManager - 管理基于角色的访问控制 (RBAC).

  • cache: CCache - 提供数据缓存功能。注意,你必须指定实际的类(例如CMemCache, CDbCache)。 否则,当你访问此组件时将返回 NULL。

  • clientScript: CClientScript - 管理客户端脚本 (javascripts 和 CSS).

  • coreMessages: CPhpMessageSource - 提供 Yii 框架用到的核心信息的翻译。

  • db: CDbConnection - 提供数据库连接。注意,使用此组件你必须配置其 connectionString 属性。

  • errorHandler: CErrorHandler - 处理未捕获的 PHP 错误和异常。

  • format: CFormatter - 格式化数值显示。此功能从版本 1.1.0 起开始提供。

  • messages: CPhpMessageSource - 提供Yii应用中使用的信息翻译。

  • request: CHttpRequest - 提供关于用户请求的信息。

  • securityManager: CSecurityManager - 提供安全相关的服务,例如散列,加密。

  • session: CHttpSession - 提供session相关的功能。

  • statePersister: CStatePersister - 提供全局状态持久方法。

  • urlManager: CUrlManager - 提供 URL 解析和创建相关功能

  • user: CWebUser - 提供当前用户的识别信息。

  • themeManager: CThemeManager - 管理主题。

 
控制器
控制器 是 CController 或其子类的实例。它在当用户请求时由应用创建。 当一个控制器运行时,它执行所请求的动作,动作通常会引入所必要的模型并渲染相应的视图。 动作 的最简形式,就是一个名字以 action 开头的控制器类方法。
我们可以在一个控制器里面设置一个默认的action方法,例如设置一个test为默认action.
class SiteController extends Controller
{
     ...
     public $defaultAction = 'test';
     ...
}

路由器大小写敏感
注意: 默认情况下,路由是大小写敏感的,从版本 1.0.1 开始,可以通过设置应用配置中的CUrlManager::caseSensitive 为 false 使路由对大小写不敏感。当在大小写不敏感模式中时, 要确保你遵循了相应的规则约定,即:包含控制器类文件的目录名小写,且 控制器映射 和 动作映射 中使用的键为小写。

控制器接收所有的请求
如果指定了 CWebApplication::catchAllRequest , 控制器将基于此属性创建, 而用户指定的控制器 ID 将被忽略。这通常用于将应用设置为维护状态并显示一个静态提示页面。

动作Action
如前文所述,动作可以被定义为一个以 action 单词作为前缀命名的方法。而更高级的方式是定义一个动作类并让控制器在收到请求时将其实例化。 这使得动作可以被复用,提高了可复用度。

要定义一个新动作类,可用如下代码:

class UpdateAction extends CAction
{
    public function run()
    {
        // place the action logic here
    }
}
为了让控制器注意到这个动作,我们要用如下方式覆盖控制器类的actions() 方法:

class PostController extends CController
{
    public function actions()
    {
        return array(
            'edit'=>'application.controllers.post.UpdateAction',
        );
    }
}
如上所示,我们使用了路径别名 application.controllers.post.UpdateAction 指定动作类文件为 protected/controllers/post/UpdateAction.php.

通过编写基于类的动作,我们可以将应用组织为模块的风格。例如, 如下目录结构可用于组织控制器相关代码:
protected/
    controllers/
        PostController.php
        UserController.php
        post/
            CreateAction.php
            ReadAction.php
            UpdateAction.php
        user/
            CreateAction.php
            ListAction.php
            ProfileAction.php
            UpdateAction.php


动作Action参数绑定
从版本 1.1.4 开始,Yii 提供了对自动动作参数绑定的支持。 就是说,控制器动作可以定义命名的参数,参数的值将由 Yii 自动从 $_GET 填充。假设有2个参数,一个category和一个language。
public function actionCreate($category, $language='en')
    {
        // ... fun code starts here ...
    }
注意我们在动作方法 actionCreate 中添加了两个参数。 这些参数的名字必须和我们想要从 $_GET 中提取的名字一致。 当用户没有在请求中指定 $language 参数时,这个参数会使用默认值 en 。


过滤器
过滤器是一段代码,可被配置在控制器动作执行之前或之后执行。例如, 访问控制过滤器将被执行以确保在执行请求的动作之前用户已通过身份验证;性能过滤器可用于测量控制器执行所用的时间。
一个动作可以有多个过滤器。过滤器执行顺序为它们出现在过滤器列表中的顺序。过滤器可以阻止动作及后面其他过滤器的执行。
1.过滤器可以定义为一个控制器类的方法。方法名必须以 filter 开头。例如,现有的 filterAccessControl 方法定义了一个名为 accessControl 的过滤器。 过滤器方法必须为如下结构:
public function filterAccessControl($filterChain)
{
    // 调用 $filterChain->run() 以继续后续过滤器与动作的执行。
}

2.控制器可以说一个CFilter或其子类的实例,例如我们可以这样定义:
class PerformanceFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // 动作被执行之前应用的逻辑
        return true; // 如果动作不应被执行,此处返回 false
    }
 
    protected function postFilter($filterChain)
    {
        // 动作执行之后应用的逻辑
    }
}
要对动作应用过滤器,我们需要覆盖 CController::filters() 方法。此方法应返回一个过滤器配置数组。例如:
class PostController extends CController
{
    ......
    public function filters()
    {
        return array(
            'postOnly + edit, create',
            array(
                'application.filters.PerformanceFilter - edit, create',
                'unit'=>'second',
            ),
        );
    }
}
上述代码指定了两个过滤器: postOnly 和 PerformanceFilter。 postOnly 过滤器是基于方法的(相应的过滤器方法已在 CController 中定义); 而 performanceFilter 过滤器是基于对象的。路径别名 application.filters.PerformanceFilter 指定过滤器类文件是 protected/filters/PerformanceFilter。我们使用一个数组配置 PerformanceFilter ,这样它就可被用于初始化过滤器对象的属性值。此处 PerformanceFilter 的 unit 属性值将被初始为 second。
使用加减号,我们可指定哪些动作应该或不应该应用过滤器。上述代码中, postOnly 应只被应用于 edit 和 create 动作,而 PerformanceFilter 应被应用于 除了 edit 和 create 之外的动作。 如果过滤器配置中没有使用加减号,则此过滤器将被应用于所有动作。


模型Model
Yii 实现了两种类型的模型:表单模型和 Active Record。二者均继承于相同的基类 CModel。
表单模型是 CFormModel 的实例。表单模型用于保持从用户的输入获取的数据。 这些数据经常被获取,使用,然后丢弃。例如,在一个登录页面中, 我们可以使用表单模型用于表示由最终用户提供的用户名和密码信息。
Active Record (AR) 是一种用于通过面向对象的风格抽象化数据库访问的设计模式。 每个 AR 对象是一个 CActiveRecord 或其子类的实例。代表数据表中的一行。 行中的字段对应 AR 对象中的属性。


视图View
要渲染时,需通过传递视图的名称调用 CController::render()。下面将会渲染一个edit.php试图并传入了2个值:
$this->render('edit', array(
    'var1'=>$value1,
    'var2'=>$value2,
));
在以上的方式中, render() 方法将提取数组的第二个参数到变量里.其产生的结果是,在视图脚本里,我们可以直接访问变量 $var1 和 $var2.

布局
布局是一种用来修饰视图的特殊的视图文件.它通常包含了用户界面中通用的一部分视图.例如:布局可以包含header和footer的部分,然后把内容嵌入其间.

......header here......
<?php echo $content; ?>
......footer here......

其中的 $content 则储存了内容视图的渲染结果.

当使用 render() 时,布局被隐式应用.视图脚本 protected/views/layouts/main.php 是默认的布局文件.这可以通过改变 CWebApplication::layout 或者 CWebApplication::layout 进行自定义。要渲染一个不带布局的视图,则需调用 renderPartial() 。

小物件
小物件是 CWidget 或其子类的实例.它是一个主要用于表现数据的组件.小物件通常内嵌于一个视图来产生一些复杂而独立的用户界面.例如,一个日历小物件可用于渲染一个复杂的日历界面.小物件使用户界面更加可复用.
我们可以按如下视图脚本来使用一个小物件:

<?php $this->beginWidget('path.to.WidgetClass'); ?>
...可能会由小物件获取的内容主体...
<?php $this->endWidget(); ?>
或者
<?php $this->widget('path.to.WidgetClass'); ?>
后者用于不需要任何 body 内容的组件.

小物件可通过配置来定制它的表现.这是通过调用 CBaseController::beginWidget 或 CBaseController::widget 设置其初始化属性值来完成的.例如,当使用 CMaskedTextField 小物件时,我们想指定被使用的 mask (可理解为一种输出格式,译者注).我们通过传递一个携带这些属性初始化值的数组来实现.这里的数组的键是属性的名称,而数组的值则是小物件属性所对应的值.正如以下所示 :
<?php
$this->widget('CMaskedTextField',array(
    'mask'=>'99/99/9999'
));
?>

继承 CWidget 并覆盖其init() 和 run() 方法,可以定义一个新的小物件:
class MyWidget extends CWidget
{
    public function init()
    {
        // 此方法会被 CController::beginWidget() 调用
    }
 
    public function run()
    {
        // 此方法会被 CController::endWidget() 调用
    }
}

小物件可以像一个控制器一样拥有它自己的视图.默认情况下,小物件的视图文件位于包含了小物件类文件目录的 views 子目录之下.这些视图可以通过调用 CWidget::render() 渲染,这一点和控制器很相似.唯一不同的是,小物件的视图没有布局文件支持。另外,小物件视图中的$this指向小物件实例而不是控制器实例。


组件
Yii 应用建立于组件之上。组件是 CComponent 或其子类的实例。使用组件主要涉及访问它的属性以及触发或处理它的时间。 基类 CComponent 指定了如何定义属性和事件。

组件的属性就像对象的公共成员变量。它是可读写的。例如:
$width=$component->textWidth;     // 获取 textWidth 属性
$component->enableCaching=true;   // 设置 enableCaching 属性
要定义一个组件属性,我们只需在组件类中定义一个公共成员变量即可。更灵活的方式是定义其 getter 和 setter 方法,例如:
public function getTextWidth()
{
    return $this->_textWidth;
}
 
public function setTextWidth($value)
{
    $this->_textWidth=$value;
}
上述代码定义了一个可写的属性名为 textWidth (名字是大小写不敏感的)。 当读取属性时,getTextWidth() 就会被调用,其返回值则成为属性值;相似的, 当写入属性时,setTextWidth() 被调用。如果 setter 方法没有定义,则属性将是只读的, 如果对其写入则会抛出一个异常。使用 getter 和 setter 方法定义一个属性有一个好处:即当读取或写入属性时, 可以执行额外的逻辑(例如,执行验证,触发事件)。

组件事件
组件事件是一些特殊的属性,它们使用一些称作 事件句柄 (event handlers)的方法作为其值。 附加(分配)一个方法到一个事件将会引起方法在事件被唤起处自动被调用。因此, 一个组件的行为可能会被一种在部件开发过程中不可预见的方式修改。

组件事件以 on 开头的命名方式定义。和属性通过 getter/setter 方法来定义的命名方式一样, 事件的名称是大小写不敏感的。以下代码定义了一个 onClicked 事件:
public function onClicked($event)
{
    $this->raiseEvent('onClicked', $event);
}
这里作为事件参数的  $event  是  CEvent  或其子类的实例。

我们可以附加一个方法到此 event,如下所示:
$component->onClicked=$callback;
这里的 $callback 指向了一个有效的 PHP 回调。它可以是一个全局函数也可以是类中的一个方法。 如果是后者,它必须以一个数组的方式提供: array($object,'methodName').

组件行为
行为类必须实现  IBehavior  接口。 大多数行为可以继承自  CBehavior  。如果一个行为需要绑定到一个  模型 , 它也可以从专为模型实现绑定特性的  CModelBehavior  或  CActiveRecordBehavior  继承。
要使用一个行为,它必须首先通过调用此行为的 attach() 方法绑定到一个组件。然后我们就可以通过组件调用此行为方法:
// $name 在组件中实现了对行为的唯一识别
$component->attachBehavior($name,$behavior);
// test() 是行为中的方法。
$component->test();

已绑定的行为可以像一个组件中的普通属性一样访问。 例如,如果一个名为 tree 的行为绑定到了一个组件,我们就可以通过如下代码获得指向此行为的引用。
$behavior=$component->tree;
// 等于下行代码:
// $behavior=$component->asa('tree');
行为是可以被临时禁止的,此时它的方法开就会在组件中失效.例如:

$component->disableBehavior($name);
// 下面的代码将抛出一个异常
$component->test();
$component->enableBehavior($name);
// 现在就可以使用了
$component->test();


模块
块是一个独立的软件单元,它包含  模型 视图 控制器  和其他支持的组件。 在许多方面上,模块看起来像一个  应用 。主要的区别就是模块不能单独部署,它必须存在于一个应用里。 用户可以像他们访问普通应用的控制器那样访问模块中的控制器。
模块在一些场景里很有用。对大型应用来说,我们可能需要把它划分为几个模块,每个模块可以单独维护和部署。一些通用的功能,例如用户管理, 评论管理,可以以模块的形式开发,这样他们就可以容易地在以后的项目中被复用。

创建模块
模块组织在一个目录中,目录的名字即模块的唯一  ID  。 模块目录的结构跟  应用基础目录  很相似。下面列出了一个  fourm  的模块的典型的目录结构:
forum/
   ForumModule.php            模块类文件
   components/                包含可复用的用户组件
      views/                  包含小物件的视图文件
   controllers/               包含控制器类文件
      DefaultController.php   默认的控制器类文件
   extensions/                包含第三方扩展
   models/                    包含模块类文件
   views/                     包含控制器视图和布局文件
      layouts/                包含布局文件
      default/                包含 DefaultController 的视图文件
         index.php            首页视图文件
模块必须由一个继承自 CWebModule 的模块类。类的名字通过表达式 ucfirst($id).'Module' 确定, 其中的 $id 代表模块的 ID (或者说模块的目录名字)。 模块类是存储模块代码间可共享信息的中心位置。例如,我们可以使用 CWebModule::params 存储模块参数,使用 CWebModule::components 分享模块级的 应用组件 .

使用模块
要使用模块,首先将模块目录放在  应用基础目录  的  modules  中。 然后在应用的  modules  属性中声明模块 ID 。例如,为了使用上面的  forum  模块, 我们可以使用如下  应用配置 :(main.php)
return array(
    ......
    'modules'=>array('forum',...),
    ......
);

模块也可以在配置时带有初始属性值。做法和配置 应用组件 很类似。 例如, forum 模块可以在其模块类中有一个名为 postPerPage 的属性,它可以在 应用配置(main.php)中配置如下:
return array(
    ......
    'modules'=>array(
        'forum'=>array(
            'postPerPage'=>20,
        ),
    ),
    ......
);
模块的实例可通过当前活动控制器的 module 属性访问。在模块实例中,我们可以访问在模块级中共享的信息。 例如,为访问上面的 postPerPage 信息,我们可使用如下表达式:
$postPerPage=Yii::app()->controller->module->postPerPage;
模块中的控制器动作可以通过  路由   moduleID/controllerID/actionID  访问。 例如,假设上面的  forum  模块有一个名为 PostController  的控制器,我们就可以通过  路由   forum/post/create  访问此控制器中的  create  动作。 此路由对应的 URL 即  http://www.example.com/index.php?r=forum/post/create .


路径别名与名字空间
Yii 中广泛的使用了路径别名。路径别名关联于一个目录或文件的路径。它以点号语法指定,类似于广泛使用的名字空间(namespace)格式:
通过使用  YiiBase::getPathOfAlias() , 别名可以被翻译为其相应的路径。 例如,  system.web.CController  会被翻译为 yii/framework/web/CController
通过调用  YiiBase::setPathOfAlias() ,我们可以定义新的根路径别名。

Root Alias

为方便起见,Yii 预定义了以下几个根别名:

  • system: 表示 Yii 框架目录;
  • zii: 表示 Zii 库 目录;
  • application: 表示应用的 基础目录;
  • webroot: 表示 入口脚本 文件所在的目录。此别名从版本 1.0.3 开始有效。
  • ext: 表示包含了所有第三方 扩展 的目录。此别名从版本 1.0.8 开始有效。

额外的,如果应用使用了 模块, (Yii) 也为每个模块ID定义了根别名,指向相应模块的跟目录。 此功能从版本 1.0.3 起有效。

通过使用 YiiBase::getPathOfAlias(), 别名可以被翻译为其相应的路径。 例如, system.web.CController 会被翻译为yii/framework/web/CController


使用别名导入Importing Classes
例如,如果我们想包含 CController 类的定义,我们可以调用如下代码
Yii::import('system.web.CController');


使用Class Map
Yii允许用户定义的类通过使Class Map机制来预先导入,这也是Yii内置类使用的方法。 预先引入机制可以在Yii应用的任何地方使用,无需显式地导入或者包含文件。这个特性对于一个建立在Yii基础上的框架或者类库来说很有用。

若要使用预导入功能,要在CWebApplication::run()执行前执行下面的代码:
Yii::$classMap=array(
    'ClassName1' => 'path/to/ClassName1.php',
    'ClassName2' => 'path/to/ClassName2.php',
    ......
);


导入目录
我们还可以使用如下语法导入整个目录,这样此目录下的类文件就会在需要时被自动包含。
Yii::import('system.web.*');


YII代码书写规则
变量名和函数名应该使它们的第一个单词全部小写,以使其区别于类名(例如:$basePath, runController(), LinkPager)。对私有类成员变量来说,我们推荐以下划线作为其名字前缀(例如: $_actionList)。


YII数据库书写规范
1.数据库表名和列名都使用小写命名。
2. 名字中的单词应使用下划线分割 (例如  product_order )。
3. 对于表名,你既可以使用单数也可以使用复数。但 不要 同时使用两者。为简单起见,我们推荐使用单数名字。
4. 表名可以使用一个通用前缀,例如  tbl_  。这样当应用所使用的表和另一个应用说使用的表共存于同一个数据库中时就特别有用。 这两个应用的表可以通过使用不同的表前缀很容易地区别开。


你可能感兴趣的:(2:Yii基础知识(Yii权威指南))