??Yii中关系型活动记录一个比较神奇的特性是,直接从问题(Issue)$model的实例中访问问题(Issue)所属项目的有效成员的能力。当我们使用Gii工具初始创建我们的问题(Issue)模型类时,它足够聪明地查看下面的数据库并且创建相关的关系。可以从relations()方法中看到,在/protected/models/Issue.php文件中可以查看。因为我们在创建了恰当的数据库关系后,才创建的这个类,所以,方法应该看起来是这样的:
有了这些关系,我们可以相当简单地访问相关AR实例
通常我们需要写复杂的SQL join语句来访问这样的关系型数据。而使用了Yii中的关系型AR,将我们从这种复杂漫长痛苦的过程中解放出来。我们现在可以使用优雅精简的面向对象语法来访问这些关系了。
把逻辑放到模型类中
需要添加一个简单的getter方法来将这个私有属性给暴露出来。
criteria 条件
CDetailView,我们以前并没有见过这个。这个和CListView是相似的东西,用于显示一个列表,但是它用于显示一个单一数据模型的详细内容,而不是显示一个多项的列表。
设计和创建带有显式关系的数据库表
使用带有关系的活动记录
添加下拉菜单型的表单元素
控制器过滤器
把这个过滤器添加到过滤器配置数组。为了让我们的新过滤器应用到创建动作,添加如下高亮处代码到IssueController::filters()方法中:
在前面很短的时间内,我们完成了大量开发工作。Trackstar应用程序基本功能的基础已经奠定。
用于认证的基础脚手架代码,确实为我们提供了一个好的开端,但是我们需要进行一定的修改,使之支持更多的用户。同时我们需要向应用程序添加用户CRUD功能,用来对多用户进行管理。这次迭代聚焦在使用User表扩展认证模型,和适当添加基本用户数据管理所需功能。
需要确定所有在本次迭代将要实现的细节
修改认证流程,使用数据库来认证用户登录信息
每一个tbl_user表中定义的列,都有一个输入框与之对应,我们并不希望把它们全部暴露给用户。
着手新建一个用来存放更新相关公共字段逻辑代码的类。这个新类将成为一个可被我们应用中所有AR类继承的基类。新建这样一个基类而不是直接将相关逻辑代码添加到Project模型类的原因是:这部分逻辑代码被Issue和User模型类所共同需要。比起复制相同代码到每一个类中,上面的做法将允许我们在一个地方为每一个AR模型类同时设置那些字段(属性)。我们也将定义这个类为抽象类,这样使得他们不可以被直接实例化。
重载了CActiveRecord::beforeValidate()方法。这是CActiveRecord提供的众多可以定制其工作流的事件之一
如果在AR类save()被调用时不提供一个false参数,验证将被触发。这一过程将执行所有在AR类中rules()里定义的验证细节。一共有2个方法允许我们将适当的逻辑置放在验证开始之前和验证结束之后,这个2方法为:beforeValidate()和afterValidate()。在这个部分,我们决定在验证执行前对我们审查表后的公共字段进行直接设置。
一个属性的值可以设置为CDbExpression类型,在所属记录被保存前。在保存过程中所需的值将由运行数据库表达式获得。
$model->attributes=$_POST['User'];
在这里,所有$_POST[‘User’]数组里的项会和$model类安全属性列表中的做匹配,成功匹配的完成赋值。
新建的$password_repeat不存在对应的tbl_user表中的列,需要将其直接添加到安全属性列表。
我们还需要将密码确认框添加到表单,让我们行动起来。
这显然不是一个长期解决方案,但是是一个很好的基础。
Yii认证框架的核心是一个叫user的应用组件,一般来说,是IWebUser接口的对象实现。这个具体的类是默认通过框架类CWebUser实现的。这个用户组件封装了所有当前用户在整个应用中的认证信息。这个组件的配置在我们使用yiic工具自动生成整个项目代码的时候被创建。
任何地方通过Yii::app()->user进行访问
设置为true时,可以将用户的信息持久的储存在浏览器的cookies里。储存的信息将在后面的访问中自动用于认证。
Yii认证框架定义了一个独立的实体来储存当前认证逻辑。这是一个认证类,而且一般形式上,这个类实现了IUserIdentity接口。这个类扮演的主要角色是封装了认证逻辑,使得容易进行不同的应用。基于项目需求,我们需要将用户数据的用户名和密码和数据库中储存的值进行匹配,或者允许用户使用他们的 OpenID credentials进行登录,或者整合入一个现有的LDAP方式。逻辑分离是指将认证方式从登录流程中分离出来,从而允许我们轻松的在不同应用中转换。认证类提供这样程度的分离。
当最初建立我们的应用程序时,处于protected/components/UserIdentity.php的认证类被同时创建。它继承自Yii框架类CUserIdentity,这个框架类是基于用户名密码认证的基础类。
Yii::app()->user->login($identity, $duration);
id为CUserIdentity类的明确定义属性。所以与姓名和ID不同,所有其他需要被持久化保持在会话中的用户属性可以采用相同的方法定义。
我们使用了updateByPk()方法作为一种高效,处理用户记录更新的方式,并且简单到只需要指出主键和需要更新的name=>value键值对。
认证和授权
一旦用户提供了足够的认证信息后,应用程序需要找到一种合适的方法去判断用户是否有足够的权限去执行要求的操作。
利用Yii的用户访问控制中的一些特性来扩展我们的基本授权模型。Yii即提供了一个简单的访问控制过滤器,也提供了一个更先进的RBAC(基于角色的访问控制)体系,来帮助我们完成授权需求。
制定一个策略来强制用户在获得访问任何Project或Issue相关功能前,必须登录
建立用户角色并且使之与一个特殊的功能权限对应
制定一个为用户分配角色的机制(包含角色相关的权限)
确保我们的角色权限结构针对每一个Project独立存在(也就是说,允许用户在不同的项目拥有不同的权限)
制定一个让用户和项目,同时也和项目中的角色相关联的机制
实施适当的认证访问检测,使得应用程序可以针对基于不同用户权限进行允许或拒绝访问操作
Yii内部有大量内部功能可以帮助我们完成这一需求
Yii框架提供的过滤器被叫做 accessControl(访问控制)。这个过滤器可以被直接使用在控制器类中,提供一种授权方案来验证用户是否可以使用一个特定的控制器下的行为。
最佳实践
‘@’特殊字符泛指所有已认证用户。
我们将在protected/components里添加一个新的挂件,作为这个文件夹的内容已被指定在主配置文件自动加载。'
Yii的灵活之处是让我们可以使用其他的框架组件。我们将使用Zend Framework中的一个组件,它是Zend_Feed。使用它可以让我们不用写任何底层的代码就能生成一个RSS格式的Web feed。
为了在Yii应用程序中使用这个框架,我们需要将一些文件移到我们的应用程序的目录结构中。让我们在 /protected目录下创建一个新的目录叫vendors 。然后移动Zend框架目录下的/library/Zend目录到新创建的目录下。移动完成了,确保在TrackStar应用程序中存在 protected/vendors/Zend/Feed.php文件。
通过Zend_Feed组件来返回转换成所需格式的数据。Zend_Feed期望的是简单的数组,其本身的每个元素是一个包含评论实体的数组。
配置路由规则Yii的URL管理器允许我们指定规则来定义URL的解析和创建。定义一个路由规则和模式,该模式用于匹配URL,以确定哪些规则用于解析或创建URL。
从URL中移除入口文件现在我们需要从URL中移除index.php。需要两步完成:
修改Web服务器配置,重定向所有请求的路由到index.php,但不包括已经存在的文件或目录。
设置UrlManager的showScriptName属性为false。
??通过创建新的布局,CSS和其他配置文件来建立一个新的主题,并为应用程序提供一个新前端设计
布局设置
定制一个布局主要分为2步操作。其一是CWebApplication的$layout属性。默认值指向protected/views/layouts/main.php。这一项为默认设置,可以在位于protected/config/main.php的主配置文件里进行修改。
另外一个需要指定布局的地方是设置Controller(控制器)类$layout属性。这样就允许针对不同Contorller(控制器)以更细的粒度进行设置
当你调用render()方法来渲染一个view文件时,Yii将会将view文件的内容嵌入controller类或应用程序级设置的layout文件中。你可以通过调用CController::renderParial()方法实例来避免应用layout装饰。
重载layout属性设置
Yii的另一个大优势就是其适当利用了其他拥有优良血统的框架,Blueprint CSS 框架就是其中一个例子。
$pageTitle属性被定义在Yii的CController基类中,其默认值为controller(控制器)后的action(动作)的名字。这个值很容易在controller类中重置,或者在view文件中重置。
也就是说并非view文件可以使用布局文件实现布局,布局文件也可以使用其他布局文件实现布局。
基类方法中的beginContent()和endContent()被用来显示被附加上的特殊视图内容。这里特殊显示的是我们的主布局文件‘layouts/main’。beginContent()方法实际使用了Yii内置部件CContentDecorator,该部件主要用于布局文件嵌套。因此介于beginContent()和endContent()之间的内容将作为输出内容显示在beginContent()中指定的view文件中。如果没有指定,将会使用controller级的默认布局文件,如果controller级没有指定将使用应用程序级。
主题提供了一个体系化的解决方案,来设计网页应用程序的布局。MVC结构的最大好处就是就是将展示层从后台分离出来。主题极大的利用了该分离,允许你随时随地轻松且动态更换网站的整体外观。Yii允许使用一种非常简单的应用程序主题,来为web设计提供极大的自由度。
在Yii中每一个主题都是由一系列包含view文件,布局文件,相关资源文件,如:图片,CSS,JavaScipt文件等的文件夹集合。主题的名字就是该文件包 (最外层文件包) 的名字。默认的,所有主题都被放置在WebRoot/themes路径下。当然,该路径可以在应用程序中进行设置。你只需要修改themeManager应用程序组件的basePath和baseUrl属性值就可以完成该修改。
国际化就是一个使软件程序自动适应不同语言而不需要修改底层引擎的过程。本地化就是使国际软件适应某一区域或者某一语言的过程。Yii通过如下方面实现对他们的支持:
Yii为每一种语言和区域提供本地化数据支持
Yii提供相关服务帮助翻译文字信息和文件
Yii提供语言相关的日期和时间格式化
Yii提供语言相关的数字格式化
Yii几乎包含了所有语言和区域的本地化数据。数据都是从通用语言环境数据信息库(CLDR) (http://cldr.unicode.org/)并且按照其相关语言ID进行命名后储存在Yii 框架的framework/i18n/data/目录。
模块是一个大型应用程序中的小型应用程序。模块拥有与应用程序相似的结构,包含模型,试图,控制器,和其他支持组件。但是,模块不可以单独作为一个应用程序出现,必须嵌入某一应用程序。
模块可以帮助你模块化实现你的应用程序。大型应用程序常划分为离散的应用程序来实现功能,这里离散的应用程序可以通过模块实现。站点功能类似添加用户论坛,用户博客,或者站点管理功能都是一些例子,可以从主功能上剥离,使得可以分离开发,并且可以很容易的在以后的项目中重用。我们将在项目的不同目录建立存放管理功能的模块。
每一个模块的结构都和我们的主应用程序很相似。
模块类扮演了存储来自模块代码共享信息的中转地带。例如,我们可以使用CWebModule的params属性来存储模块的特定参数,使用components属性在模块级分享应用程序组件。该类在模块中的作用类似应用程序中的类对整个应用程序的作用。因此,CWebModule是对模块来说的,CWebApplication是对整个应用程序来说的。
路由应该是如下形式/moduleID/controllerID/actionID。
上:/themes/[themeName]/views/[moduleID]/layouts/为layout文件,/themes/[themeName]/views/[moduleID]/[controllerID]/为对应controller的视图文件。
与以前唯一的不同就是这里需要指明所属模块为admin。
Yii包含了强大的JavaScript框架jQuery.jQuery是一个开源JavaScript库,它使的DOM元素和JavaScript之间的交互变得简单.
Yii::app()->clientScript->registerScript(
'fadeAndHideEffect',
'$(".sys-message").animate({opacity: 1.0}, 5000). fadeOut("slow");'
);
日志是在应用程序开发的最后一步应该被提起的一个主题。信息,警告,严重错误信息在引起应用程序崩溃时时非常有价值的,在生产环境中它们大多被实际用户使用。
系统级调试信息等级事通过Yii::trace来创建的,只有当应用程序处于该特殊调试模式下才会记录信息。
我们可以通过以下2个静态方法中的一个来记录信息:
Yii::log($message, $level, $category)
Yii::trace($message, $category)
好像之前提到的,俩者的唯一区别就是Yii::trace方法只在调试模式下记录信息。
默认的,Yii::log和Yii::trace将信息存储在内存中。一般的,将这些消息显示在浏览器窗口中会使得它们非常有价值,或者存储到一些持久化介质中,或者是发送email,甚至是数据库中。Yii的消息路由功能允许将日志信息路由至不同目的地。
在Yii中消息路由是由CLogRouter应用程序组件管理的。它允许你定义一系列消息目的地。
Yii提供一个完整的基于PHP5 异常体系的错误控制框架,一个内置的机制通过关键点来控制程序错误。当主Yii应用程序组件被建立用来接收进入的用户请求,它注册了CApplication::handleError()方法来控制PHP的warnings和notices。它注册了CApplication::handleException()方法来控制未捕获的PHP异常。也就是说,在应用程序执行时一个PHP warning/notice或者一个未捕获的PHP异常发生了,上面一种错误控制将进行控制,并且执行所需的错误控制流程。
没有任何敏感信息会在生产模式暴露给用户。
缓存数据可以很好的帮助在生产状态下的web应用程序提高性能。如果这是一个不需要每次请求都发生改变的特殊内容,使用缓存来存储和提供这一内容,可以节约重新生成的时间。
这是一个被序列化的关于我们最新从数据库中取回的SysMessage AR类实例的缓存值,正是我们希望在那的。这样说来,缓存正常工作。
当将一段数据放入缓存时,必须设置一个唯一的key,用来存储数据。key就是上面提到的唯一的字符串值,value就是希望存入缓存的数据值。可以是任何格式的,唯一的要求是可以被序列化。
在Yii中还有其他可行的方法来存储有view脚本生成的页面的一部分,或者整个页面。
片段缓存用来缓存一个页面的一部分。我们可以在view脚本中使用片段缓存。我们通过使用CController::beginCache()和CController::endCache()方法来实现。这2个方法用来在渲染页面中标识内容中需要被缓存的部分。
该filter配置为利用COutputCache过滤器来缓存整个被应用程序调用ProjectController::actionView()方法生成的内容。+ view 添加在 COutputCache后,如你所能记得的,是对特殊方法添加过滤器的标准的方式。持续时间被设置为页面生成后的2分钟。
使用yiilite.php当使用PHP APC扩展,一件可以做的事是使用Yii bootstrap(引导)文件yiilite.php代替yii.php。这可以很好的增加Yii应用程序的性能。yiilite.php文件包含在每一个yii发行版本中。它是一些常用Yii类文件合并的产物。因此使用yiilite.php可以减少文件的included量和trace语句。
?
同时大量提到过的例子的身影会出现在其他你未来的应用程序中。祝你未来的项目开发愉快!