翻译了比较久,年前总算是把这个小任务完成了。文章是用markdown语法来写的,在github上阅读效果更佳:
去GitHub上阅读Yii 1.1 Application Development Cookbook中文翻译(第二章)
本章将帮助你学习Yii框架中关于URL路由、控制器和视图的一些有用的知识。学习完本章内容你可以更加灵活的运用控制器和视图。
Yii URL路由是非常强大的,它主要完成两个功能:一是解析URL到内部路由,而是根据这些内部路由创建URL。路由规则的描述分散在Yii官方文档和API文档中。让我们通过一个例子来学习如何配置应用程序的路由规则。
1.在Yii官方教程中描述了如何用 yiic webapp( http://www.yiiframework.com/doc/guide/ ) 命令创建一个新的Yii应用程序。找到文件 your protected/config/main.php ,应包含如下代码:
// application components'components'=>array( …// uncomment the following to enable URLs in path-format'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\ d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ),),
2.删除rules中的内容,我们从头开始配置。
3.在 protected/controllers 目录下,创建 WebsiteController.php 文件,写入如下代码:
class WebsiteController extends CController{public function actionIndex(){ echo "index";}public function actionPage($alias){ echo "Page is $alias.";}}
此为应用程序的控制器,我们将个性化其URL。
4.配置应用程序服务器一使用简洁的URLs。如果你的服务器是Apache,开启了mod_rewrite模块且AllowOverride设置为on,那么你需要在webroot根目录下的.htaccess文件中添加以下代码:
Options +FollowSymLinksIndexIgnore */*RewriteEngine on# if a directory or a file exists, use it directlyRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d# otherwise forward it to index.phpRewriteRule . index.php
我们的网站应该在/home显示主页(index页面),/page/ 显示其他页面。另外,/bout应该指向page页面(alias为about)。
2.保存配置,你应该可以浏览以下URLs: /home /about /page/about /page/test
浏览 http://server.local/about ,应该显示如下:
Page is about.
译者注: /home实际上是/website/index /about实际上是/website/page/alias/about /page/about实际上是/website/page/alias/about /page/test实际上是/website/page/alias/test
让我们看看做了什么,为什么会这样。我们先看看第一条规则:
'home' => 'website/index',
website/index
代表什么呢?
在Yii应用程序中,每一个控制器和对应的动作都有相关联的内部路由。一个格式化的内部路由就是moduleID/controllerID/actionID。例如,WebsiteController的actionPage方法的路由为website/page。因此,为了得到控制器ID,你应该将控制器类名称去掉Controller后缀并且使第一个字母小写。为了获取动作ID,你应该将动作方法名去掉action前缀并使第一个字母小写。
那么,home是什么呢?
为了更好的理解它,我们需要知道应用不同的URLs访问应用程序时都发生了些什么。 当我们用/home访问时,URL路由器自顶至下检查我们的路由规则,并尝试去匹配我们输入的URL。 如果匹配成功,路由器会获取到此条规则对应的控制器和动作并执行它。因此,/home是一个URL模式,它定义了哪些URLs将被此条规则处理。
备注:规则越少,那么匹配次数就越少,意味着性能也会更好。
你可以用一个特别的语法规则来创建参数化的规则。让我们看看第三条规则:
'page/<alias>' => 'website/page',
我们定义了一个alias参数,此参数应该是在/page/后被指定。它可以是任何值,此值会被当做$alias参数传递给WebsiteController::actionPage($alias)。
你也可以为此参数定义一个模式。在第二条规则中就是这么做的:
'<alias:about>' => 'website/page',
这里的alias应该匹配about或其他值,否则规则不会被应用。
参考更多信息,请查阅以下地址:
http://www.yiiframework.com/doc/guide/en/basics.controller
Yii不仅允许你通过URLs路由到不同的控制器和动作,也允许通过指定内部的路由和参数来生成URL。这是很有用的一个功能,因为这可以让你在开发应用程序时只需要把精力集中在内部路由上,而无需关心真实的URLs。
备注:不要直接指定URLs,而要用Yii URL工具生成URLs。这会让你在修改URLs时省去重写更多代码
1.用yiic webapp命令创建一个新的Yii应用程序,找到protected/config/main.php文件,替换规则数组如下:
// application components'components'=>array( … // uncomment the following to enable URLs in path-format 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<alias:about>' => 'website/page', 'page/about/<alias:authors>' => 'website/page', 'page/<alias>' => 'website/page', ),
2.在protected/controllers目录下,创建WebsiteController.php文件,写入如下代码:
class WebsiteController extends CController{public function actionIndex(){ echo "index";}public function actionPage($alias){ echo "Page is $alias.";}}
此为应用程序的控制器,我们为其创建个性化的URL。
3.配置应用程序服务器一使用简洁的URLs。如果你的服务器是Apache,开启了mod_rewrite模块且AllowOverride设置为on,那么你需要在webroot根目录下的.htaccess文件中添加以下代码:
Options +FollowSymLinksIndexIgnore */*RewriteEngine on# if a directory or a file exists, use it directlyRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d# otherwise forward it to index.phpRewriteRule . index.php
我们需要生成URLs指向WebsiteController的index和page动作。有几种不同的方式去实现,这取决于我们在哪需要它,但基本原理都是一样的。让我们列出一些生成URLs的方法。
CHtml::link()和其他CHtml方法,例如form、refresh和ajaxLink等都可以用来生成URL,它们经常在视图中被使用。Yii内部用CHtml::normalizeUrl来解析内部路由。因此,你应该按以下格式传参给这些方法: URL字符串:在这种情况下,URL直接被使用。 array(internal route, param => value, param => value, …)。此种情况下,URL将被生成。
什么是内部路由?每一个控制器和它的动作方法都有相关的路由。一个格式化的路由是这样的:moduleID/controllerID/actionID。例如WebsiteController的actionPage方法对应的路由为website/page。因此,为了得到控制器ID,你应该将控制器类名称去掉Controller后缀并且使第一个字母小写。为了获取动作ID,你应该将动作方法名去掉action前缀并使第一个字母小写。
$_GET
变量传递的参数会被传递给指定的内部路由动作。例如,如果我们想创建一个URL指向 WebsiteController::actionIndex
,并传递参数 $_GET['name']
给它,我们可以这样来做:
echo CHtml::link('Click me!', array('website/index', 'name' => 'Qiang'));
URLs在控制器中也很有用处。在控制器内部,你可以用createUrl和createAbsoluteUrl来得到相对URl和绝对URL:
class WebsiteController extends CController { public function actionTest() { //echo $this->createUrl('website/page', 'alias' => 'about'); //echo $this->createAbsoluteUrl('website/page', //'alias' => 'test'); //译者注:原书是上面的代码,实际测试时第二个参数应为数组,否则出错,下面是我写的代码 //public string createUrl(string $route, array $params=array ( ), string $ampersand='&') echo $this->createUrl('website/page',array('alias'=>'about')); echo $this->createAbsoluteUrl('website/page',array('alias'=>'about')); } // the rest of the methods }
我们将得到如下的URL:
/about http://example.com/about
译者注:实际测试因为index.php隐藏是在.htaccess文件中实现的,故生成URL结果应该是:/index.php/about、http://example.com/index.php/about
相对URLs可以用在应用程序内部,绝对URLs应该用在指向外部资源的地址或者指向从外部访问应用程序的资源(例如RSS feeds、e-mails等等)。
当你不能获取控制器实例时,例如,你在执行一个控制台应用程序,你可以用应用程序的方法:
echo Yii::app()->createUrl('website/page', 'alias' => 'about'); echo Yii::app()->createAbsoluteUrl('website/page', 'alias' => 'test');
译者注:此处同上,第二个参数应该为数组。public string createUrl(string $route, array $params=array ( ), string $ampersand='&')
两种方法的不同之处在于当你用指定的控制器方法时,你可以省略控制器和模块名称。在下面例子中,当前的模块名和当前的控制器名被应用:
class MyController extends CController { public function actionIndex() { // As we're inside of controller, createUrl will assume that URL // is for current controller echo $this->createUrl('index'); } }
我们提到的所有URL生成工具都是运用CWebApplication::createUrl
方法(CUrlManager::createUrl)来实现的。它试着自顶向下一个个去应用路由规则。如果没有规则被匹配,那么将会生成缺省的URL格式。
参考下面的地址可获取更多信息:
http://www.yiiframework.com/doc/guide/en/basics.controller
http://www.yiiframework.com/doc/guide/en/topics.url
http://www.yiiframework.com/doc/api/CUrlManager
http://www.yiiframework.com/doc/api/CHtml/#normalizeUrl-detail
http://www.yiiframework.com/doc/api/CHtml/#link-detail
http://www.yiiframework.com/doc/api/CController/#createUrldetail
http://www.yiiframework.com/doc/api/CWebApplication/#createUrldetail
Yii URL路由有一个“隐蔽”的功能,那就是你可以在URL规则中应用正则表达式,这在处理字符串时非常有用。
1.用yiic webapp命令创建一个新的Yii应用程序,找到protected/config/main.php,应包含如下代码:
// application components'components'=>array(…// uncomment the following to enable URLs in path-format'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\ d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ),),
2.删除rules中的内容,我们从头开始配置。
3.在你的protected/controllers文件夹下,创建PostController.php文件,写入如下代码:
class PostController extends CController{ public function actionView($alias) { echo "Showing post with alias $alias."; } public function actionIndex($order = 'DESC') { echo "Showing posts ordered $order."; } public function actionHello($name) { echo "Hello, $name!"; }}
此为应用程序的控制器,我们为其创建个性化的URL。
4.配置应用程序服务器使用简洁的URLs。如果你的服务器是Apache,开启了mod_rewrite模块且AllowOverride设置为on,那么你需要在webroot根目录下的.htaccess文件中添加以下代码: `` Options +FollowSymLinks IndexIgnore / RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
我们想PostController的动作根据一些规则来接收参数,如果参数不匹配规则,那么就返回"404 not found"。另外, 让我们用正则表达式来实现:
'post/<alias:[-a-z]+>' => 'post/view', '(posts|archive)' => 'post/index', '(posts|archive)/<order:(DESC|ASC)>' => 'post/index', 'sayhello/<name>' => 'post/hello',
现在,你可以尝试访问如下URLs:
// success http://example.com/post/test-post // success http://example.com/post/another_post // success http://example.com/posts // success http://example.com/archive // fail http://example.com/archive/test // success http://example.com/posts/ASC
访问 http://example.com/post/test-post ,应该显示如下:
Showing post with alias test-post.
访问 http://example.com/archive/test ,应该会显示错误,显示如下:
Error 404 Unable to resolve the request "archive/test".
在参数定义和其余规则中都可以应用正则表达式。我们来一条条看看我们定义的规则:
'post/<alias:[-a-z]+>' => 'post/view',
Alias参数应该包含一个或更多英文字符或'-'字符。其余字符是不允许的。
'(posts|archive)' => 'post/index',
posts和archive均指向post/index。
'(posts|archive)/<order:(DESC|ASC)>' => 'post/index',
posts和archive均指向post/index。参数Order仅接受连个值:DESC和ASC。
'sayhello/<name>' => 'post/hello',
你应该指定name值,但是没有任何限制。
要注意的是尽管应用了规则,开发人员也不能假定用户输入的数据是安全的。
访问以下资源,可以学习更多关于正则表达式的知识:
http://www.php.net/manual/en/reference.pcre.pattern.syntax.php Mastering Regular Expressions, by Jeffrey Friedl (http://regex.info/)
一个网站一般都包含一些静态页面,比如/about、/contact、/tos等等页面。我们一般在一个独立的控制器中去处理这些页面。让我们来找一种方式为这些页面创建URL规则。
1.用yiic webapp命令创建一个新的Yii应用程序,找到protected/config/main.php,应包含如下代码:
// application components'components'=>array(…// uncomment the following to enable URLs in path-format'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\ d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ),),
2.删除rules中的内容,我们从头开始配置。
3.在你的protected/controllers文件夹下,创建WebsiteController.php文件,写入如下代码:
class WebsiteController extends CController{ public function actionPage($alias) { echo "Page is $alias."; }}
4.配置应用程序服务器一使用简洁的URLs。如果你的服务器是Apache,开启了mod_rewrite模块且AllowOverride设置为on,那么你需要在webroot根目录下的.htaccess文件中添加以下代码:
Options +FollowSymLinks IndexIgnore */* RewriteEngine on # if a directory or a file exists, use it directly RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # otherwise forward it to index.php RewriteRule . index.php
最直接的方式就是为每个页面定义一条规则:
'<alias:about>' => 'website/page', '<alias:contact>' => 'website/page', '<alias:tos>' => 'website/page',
运用正则表达式,我们可以把它压缩成一条规则:
'<alias:(about|contact|tos)>' => 'website/page',
如我我们希望URL是/tos,并且alias参数为terms_of_service
,那该怎么办呢?
没问题,我们可以用缺省参数来实现:
'tos' => array('website/page', 'defaultParams' => array('alias' => 'terms_of_service')),
OK。如果我们有很多页面,而且能够动态地创建页面而不需要添加更多规则或是去修改已经存在的规则,那么应该怎么办呢?
我们可以这样来实现:
'<alias>' => 'website/page'
这条规则会匹配所有情况,我们需要把它放到最后面,以免影响其他规则。另外,缺省规则有个slug,比如控制器名会失效。为了解决这个问题,我们需要添加我们之前删除了的缺省规则。
让我们看看我们刚写的规则。
'<alias:about>' => 'website/page',
如果URL是/about,那么给将会把about作为alias参数传递给website/page。
'<alias:(about|contact|tos)>' => 'website/page',
如果URL是/about、/contact或/tos,那么给将会把对应值作为alias参数传递给website/page。
'tos' => array('website/page', 'defaultParams' => array('alias' => 'terms_of_service')),
当URL为/tos时,把terms_of_service
作为alias值。这条规则有点特别,因为它用到了缺省参数值。缺省参数允许你设置一个值,当指定的参数名未给定的时候就用这个缺省值。当你需要指定这个选项时,你应该用数组来表示:
'pattern' => array('internal/route', 'option' => 'value', 'option' => 'value', …),
备注:你可以设置的options列表,参考http://www.yiiframework.com/doc/api/1.1/CUrlRule
当你运用插件模块化架构来开发应用程序时,你肯定希望能以某种方式将指定的模块规则插入到当前的应用程序中。
'showScriptName' => false
至urlManager配置中。Yii代码生成工具如下图所示:
图省略
php <?php class ModuleUrlManager { static function collectRules() { if(!empty(Yii::app()->modules)) { foreach(Yii::app()->modules as $moduleName => $config) { $module = Yii::app()->getModule($moduleName); if(!empty($module->urlRules)) { Yii::app()->getUrlManager()->addRules($module->urlRules); } } } return true; } }
2、在应用程序配置中,添加如下一行:
'onBeginRequest' => array('ModuleUrlManager', 'collectRules'),
3、现在在你的page模块中,你可以添加自定义的规则。打开PageModule.php文件添加如下内容:
public $urlRules = array( 'test' => 'page/default/index',);
4、打开浏览器访问 http://example.com/test ,测试是否正常工作。页面应该显示如下:
page/default/index
这是“index”动作的视图内容,此动作属于”page“模块中的“DefaultController”控制器。
让我们看看ModuleUrlManager::collectRules
方法:
如果我们的应用程序定义了模块,那么我们就会检测urlRules公共属性是否存在。如果存在,运用CUrlManager::addRules方法将定义的URL规则添加到主应用程序配置中。CUrlManager::addRules
方法描述到:“为了使新的规则有效,此方法应该在CWebApplication::processRequest
之前被调用”。
现在让我们看看我们的应用程序是如何工作的。在index.php中,有如下一行:
Yii::createWebApplication($config)->run();
在应用配置文件初始化之后,我们调用了CWebApplication::run():
public function run() { if($this->hasEventHandler('onBeginRequest')) $this->onBeginRequest(new CEvent($this)); $this->processRequest(); if($this->hasEventHandler('onEndRequest')) $this->onEndRequest(new CEvent($this)); }
我们看到,在调用之前processRequest,onBeginRequest事件被触发。
在每个请求前都实例化应用程序模块,这对性能是不利的。一个好的方法就是缓存模块规则。缓存的规则依赖于你的应用程序。让我们看个简单的例子:
<?php class ModuleUrlManager { static function collectRules() { if(!empty(Yii::app()->modules)) { $cache = Yii::app()->getCache(); foreach(Yii::app()->modules as $moduleName => $config) { $urlRules = false; if($cache) $urlRules = $cache->get('module.urls.'.$moduleName); if($urlRules===false){ $urlRules = array(); $module = Yii::app()->getModule($moduleName); if(isset($module->urlRules)) $urlRules = $module->urlRules; if($cache) $cache->set('module.urls.'.$moduleName, $urlRules); } if(!empty($urlRules)) Yii::app()->getUrlManager()->addRules($urlRules); } } return true; } }
上面的代码缓存了每个模块的URL规则。因此,添加一个新的模块是没有问题的,但是修改现存的模块需要手动更新缓存:
Yii::app()->cache->flush().
在大多数框架中,基类控制器都是被继承,而且在官方文档中均有说明。在Yii中,你可以通过其他方式来灵活的运用控制器。当然,应用控制器是可行的也是很有用的。
用yiic webapp命令创建一个新的Yii应用程序。
我们想添加一些控制器,而且我们想这些控制器仅当用户登陆后才能被访问。我们可以再每个控制器中单独的设置约束规则以实现此功能,但有一种更好的办法来实现它。
<?php class SecureController extends Controller { public function filters() { return array( 'accessControl', ); } public function accessRules() { return array( array('allow', 'users'=>array('@'), ), array('deny', 'users'=>array('*'), ), ); } }
class TestController extends SecureController { public function actionIndex() { $this->render('index'); } … }
简单说就是用到了类的继承。如果filters或accessRules在TestController中未找到,那么将会从父类SecureController中调用。
在Yii中,你可以在单独的类中定义控制器动作,然后把它放到你的控制器中。这种方式你可以复用一些公共的功能。
例如,你可以对一个动作中的自动完成域改变后台,从而节省时间,不需要一遍又一遍的去写。我们要看的一个简单例子是删除一个模型。
CREATE TABLE `post` ( `id` int(10) unsigned NOT NULL auto_increment, `created_on` int(11) unsigned NOT NULL, `title` varchar(255) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL auto_increment, `username` varchar(200) NOT NULL, `password` char(40) NOT NULL, PRIMARY KEY (`id`) );
class PostController extends CController { function actionIndex() { $posts = Post::model()->findAll(); $this->render('index', array( 'posts' => $posts, )); } function actionDelete($id) { $post = Post::model()->findByPk($id); if(!$post) throw new CHttpException(404); if($post->delete()) $this->redirect('post/index'); throw new CHttpException(500); } }
我们定义了两个动作。一个列出所有的帖子,另外一个删除指定的存在的帖子然后重定向到主页。
class DeleteAction extends CAction { function run() { if(empty($_GET['id'])) throw new CHttpException(404); $post = Post::model()->findByPk($_GET['id']); if(!$post) throw new CHttpException(404); if($post->delete()) $this->redirect('post/index'); throw new CHttpException(500); } }
3、让我们在我们的控制器内应用它。删除actionDelete,我们不再需要它了。然后,添加actions方法:
class PostController extends CController { function actions() { return array( 'delete' => 'DeleteAction', ); } … }
class DeleteAction extends CAction { public $pk = 'id'; public $redirectTo = 'index'; public $modelClass; function run() { if(empty($_GET[$this->pk])) throw new CHttpException(404); $model = CActiveRecord::model($this->modelClass) ->findByPk($_GET[$this->pk]); if(!$model) throw new CHttpException(404); if($model->delete()) $this->redirect($this->redirectTo); throw new CHttpException(500); } }
class PostController extends CController { function actions() { return array( 'delete' => array( 'class' => 'DeleteAction', 'modelClass' => 'Post', ); ); } … }
class PostController extends CController { function actions() { return array( 'delete' => array( 'class' => 'DeleteAction', 'modelClass' => 'User', ); ); } … }
每个控制器都可以用外部的动作来构建,就像拼图一样。不同之处在于你可以灵活的运用外部动作,而且可以在其他地方对其复用。在DeleteAction的最终版本中,我们定义了一些公共的属性。因为DeleteAction是一个组件,因此我们可以配置它的属性。在此例中,我们将配置信息传递给动作,以此来为一个模块添加动作。
参考下面的地址可获取更多信息:
http://www.yiiframework.com/doc/api/CAction/
http://www.yiiframework.com/doc/api/CController#actions-detail
如果你有一些静态页面,而且你不是经常修改它,那么就没有必要去查询数据库执行页面渲染与管理。
用yiic webapp命令创建一个新的Yii应用程序。
class SiteController extends CController { function actions() { return array( 'page'=>array( 'class'=>'CViewAction', ), ); } }
2、现在,把你当页面放到protected/views/site/pages目录下,命名为about.php 和 contact.php。现在你可以用下面的URL进行访问:
当然你也可以用如下的URL,如果你配置了path模式的干净URLs。
http://example.com/site/page/view/about
我们运用了外部的名为CViewAction的动作,CViewAction只是简单的去查找是否存在和$_GET参数同名的视图文件。如果存在,那么显示它,否则显示404 Not found页面。
Parameter name Description basePath It is a base path alias that is prepended to a view name. Default is pages. That means a page named faq.company will be translated to protected/views/pages/faq/company.php. defaultView It is a name of a page to render when there is no $_GET parameter supplied. Default is index. layout Layout used to render a page. By default, controller layout is used. If it is set to null, then no layout is applied. renderAsText If set to true, then the page will be rendered as is. Else, PHP inside will be executed. viewParam The name of the $_GET parameter used to pass page name to CViewAction. Default is view.
参考下面的地址可获取更多信息:
当你运用表单来编辑模型、删除模型或是做其他操作,告诉用户结果是成功还是出错,这对用户来说是很友好的。典型的例子就是,在某个操作后,比如编辑表单,然后会有一个网页重定向,我们需要在重定向的网页上显示消息。然而,如何从当前页面传递消息到重定向页面,传递完成后清除消息呢?Flas消息将会帮助我们。
用yiic webapp命令创建一个新的Yii应用程序。
class WebsiteController extends CController { function actionOk(){ Yii::app()->user->setFlash('success','Everything went fine!'); $this->redirect('index'); } function actionBad(){ Yii::app()->user->setFlash('error','Everything went wrong!'); $this->redirect('index'); } }
<?php if(Yii::app()->user->hasFlash('success')):?> <div class="flash-notice"> <?php echo Yii::app()->user->getFlash('success')?> </div> <?php endif?> <?php if(Yii::app()->user->hasFlash('error')):?> <div class="flash-error"> <?php echo Yii::app()->user->getFlash('error')?> </div> <?php endif?>
我们用Yii::app()->user->setFlash('success','Everything went fine!')
设置了一个flash消息,例如,调用CWebUser::setFlash
方法。在内部,它把消息存储到用户状态中,在底层就是我们的消息被保存在$_SESSION
变量中,当Yii::app()->user->getFlash('success')
被调用时,$_SESSION
中相应的键值被删除。
下面的URL包含了CWebUser的API参考,它将会有助于你更好的理解flash消息:
Yii视图非常优雅且功能强大。其中很有用的一个就是你可以在视图中使用控制器实例。我们试试吧。
用yiic webapp命令创建一个新的Yii应用程序。
class WebsiteController extends CController{ function actionIndex() { $this->pageTitle = 'Controller context test'; $this->render('index'); } function hello() { if(!empty($_GET['name'])) echo 'Hello, '.$_GET['name'].'!'; }}
<h1><?php echo $this->pageTitle?></h1><p>Hello call. <?php $this->hello()?></p><?php $this->widget('zii.widgets.CMenu',array('items'=>array( array('label'=>'Home', 'url'=>array('index')), array('label'=>'Yiiframework home', 'url'=>'http://yiiframework.ru/',),))?>
我们用$this
来代表当前正在运行的控制器实例。我们可以用$this
来调用控制器方法及访问它的属性。最有用的属性是PageTitle,它指向当前页面的标题。另外还有很多非常有用的内置方法,比如renderPartials和widget。
下面的URL地址包含CController的API文档,里面列出了有你可以在视图中应用的一些方法:
Yii支持局部视图,如果你有一个单独的不包含很多业务逻辑的块,你想重用它或是把它当做Email的模板。那么局部视图就是最好的选择。
1、用yiic webapp命令创建一个新的Yii应用程序。
2、新建WebsiteController,代码如下:
class WebsiteController extends CController{ function actionIndex() { $this->render('index'); }}
我们以需要重用某一代码块为例开始讲解。例如,我们需要在很多页面中嵌入一个YouTube视频。让我们为其创建一个可重用的模板。
<object width="480" height="385"><param name="movie"value="http://www.youtube.com/v/S6u7ylr0zIg?fs=1 "></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/S6u7ylr0zIg?fs=1"type="application/x-shockwave-flash" allowscriptaccess="always"allowfullscreen="true" width="480" height="385"></embed></object>
<object width="<?php echo!empty($width) ? $width : 480?>"height="<?php echo!empty($height) ? $height: 385?>"><paramname="movie" value="http://www.youtube.com/v/<?php echo$id?>?fs=1 "></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/<?php echo $id?>?fs=1"type="application/x-shockwave-flash" allowscriptaccess="always"allowfullscreen="true" width="<?php echo !empty($width) ? $width: 480?>" height="<?php echo !empty($height) ? $height: 385?>"></embed></object>
<?php $this->renderPartial('////common/youtube', array( 'id' => '8Rp-CaIKvQs', // you can get this id by simply looking at video URL 'width' => 320, 'height' => 256,))?>
看上去是不是很好^_注意我们使用了//
去引用视图。意思就是Yii会从protected/views下寻找视图,不带控制器名称【**译者注:默认情况是从protected/views/控制其名/目录下寻找视图文件**】。
class WebsiteController extends CController{ function actionSendmails() { $users = User::model->findAll(); foreach($users as $user) { $this->sendEmail('welcome', $user->email, 'Welcome to the website!', array('user' => $user)); } echo 'Emails were sent.'; } function sendEmail($template, $to, $subject, $data) { mail($to, $subject, $this->renderPartial ('//email/'.$template, $data, true)); }}
Hello <?php echo $user->name?>,Welcome to the website!You can go check our new videos section. There are funny raccoons.Yours,Website team.
CController::renderPartial
用的是同样的模板来处理,因为CController::render
不希望应用布局。因为我们可以用$this
引用当前的控制器实例,所以我们可以用它的renderPartial方法来在其他视图中渲染另一个视图。renderPartial在处理AJAX中也非常有用,因为此种情况下你不需要渲染布局。
访问下面URL获取更多信息
http://www.yiiframework.com/doc/api/CController/#renderPartial-detail
在Yii中有一个功能可以让你在视图中运用clips。它的基本思想就是你可以记录一些输出内容,然后在其它地方对其重用。一个好的例子就是你可以在布局中定义额外的可在其他地方进行填充的内容区域。
用yiic webapp命令创建一个新的Yii应用程序。
<?php echo $content; ?>
)前插入以下内容:<?php if(!empty($this->clips['beforeContent'])) echo$this->clips['beforeContent']?>
然后,插入以下内容至
<?php if(!empty($this->clips['footer'])) echo$this->clips['footer']?>
$this->beginClip('beforeContent');echo 'Your IP is '.Yii::app()->request->userHostAddress;$this->endClip();
<?php $this->beginClip('footer')?>This application was built with Yii.<?php $this->endClip()?>
我们用代码来标记特殊的区域,然后在输出前进行检验。如果存在则输出其内容。然后,我们用控制器方法 beginClip 和 endClip 来为clips填充内容。
在Yii中,我们可以把要输出内容包装到decorator中。decorators最普通的应用就是布局。当你在控制器方法中调用render方法来渲染视图时,Yii自动的用main布局视图来包装它。让我们创建一个简单的decorator来格式化显示引用内容。
用yiic webapp命令创建一个新的Yii应用程序。
<div class="quote">“<?php echo $content?>”, <?php echo $author?></div>
<?php $this->beginContent('//decorators/quote', array('author' =>'Edward A. Murphy'))?>If anything bad can happen, it probably will<?php $this->endContent()?>
<div class="quote">“If anything bad can happen, it probably will”,Edward A. Murphy</div>
decorators非常简单。在beginContent和endContent之间的任意内容都被当做$content变量传送到decorator模板中。然后, decorator模板将会渲染它并将它插入到endContent调用处。我们可以利用beginContent的第二个参数传送额外的变量到decorator中,我们的示例中对于作者参数就是这么做的。
[注意:我们用到//decorators/quote作为视图路径,这样做的意思就是视图文件将从主题视图根目录下开始寻找,而不是从应用程序视图根目录下开始寻找]
访问下面的URL获取更多关于decorators的信息:
大多数应用程序对于所有的视图使用单一的布局。然而,有些时候需要多个布局。例如,一个应用程序可以在不同的页面使用不同的布局:博客的页面有两个附加列,文章页面要一个额外的列,归档页面不需要额外的列。
用yiic webapp命令创建一个新的Yii应用程序。
<?php $this->beginContent('//layouts/main')?><div><?php echo $content?></div><div class="sidebar tags"> <ul> <li><a href="#php">PHP</a></li> <li><a href="#yii">Yii</a></li> </ul></div><div class="sidebar links"> <ul> <li><a href="http://yiiframework.com/">Yiiframework</a></li> <li><a href="http://php.net/">PHP</a></li> </ul></div><?php $this->endContent()?>
<?php $this->beginContent('//layouts/main')?><div><?php echo $content?></div><div class="sidebar toc"> <ul> <li><a href="#intro">1. Introduction</a></li> <li><a href="#quick-start">2. Quick start</a></li> </ul></div><?php $this->endContent()?>
class BlogController extends Controller{ function actionIndex() { $this->layout = 'blog'; $this->render('//site/index'); }}class ArticleController extends Controller{ function actionIndex() { $this->layout = 'articles'; $this->render('//site/index'); }}class PortfolioController extends Controller{ function actionIndex() { $this->render('//site/index'); }}
我们为blog和articles定义了额外的连个布局文件。因为我们不想从main布局中复制粘贴同样的部分,我们利用了`$this-
beginContent
和
$this->endContent`来实现,如下图所示:
这样,我们就能够把articles布局内渲染的视图内容作为main布局的$content。
在最近的Yii发布版本中,重心已由原来的AR转移到了表格、列表和数据提供者。然而某些时候直接使用AR更有效。让我们看看如何对AR记录进行分页并对其数据进行归类整理。
class PostController extends Controller{ function actionIndex() { $criteria = new CDbCriteria(); $count=Post::model()->count($criteria); $pages=new CPagination($count); // elements per page $pages->pageSize=5; $pages->applyLimit($criteria); // sorting $sort = new CSort('Post'); $sort->attributes = array( 'id', 'title', ); $sort->applyOrder($criteria); $models = Post::model()->findAll($criteria); $this->render('index', array( 'models' => $models, 'pages' => $pages, 'sort' => $sort, )); }}
<p><?php echo $sort->link('id')?></p><p><?php echo $sort->link('title')?></p><ol><?php foreach($models as $model):?><li><h2><?php echo $model->id?> - <?php echo $model->title?></h2></li><?php endforeach?></ol><?php $this->widget('CLinkPager', array('pages' => $pages,))?>
首先,我们获取模型记录总数,并用它初始化分页组件实例。然后,我们用 applyLimit
方法来施加限制。随后,我们为模型创建 sorter 实例对象,通过调用 applyOrder
方法指定我们想要按哪些字段进行排序。最后,我们将修改过的规则传递给 findAll
。在这一步,我们已经有了模型数据列表、分页数据链接和用来生成数据整理链接的 sorter 实例对象。
在视图中,我们用到了我们在模型中生成的数据。首先,我们用 CSort::link
方法生成链接。然后,我们列出模型数据。最后,用CLinkPager
挂件生成分页导航。
访问下面链接获取更多关于分页和数据整理的信息:
已经有(0)位网友发表了评论,你也评一评吧!
原创文章如转载,请注明:转载自Eddy Blog
原文地址:http://www.rrgod.com/technique/869.html 欢迎订阅Eddy Blog。