Yii 1.1 Application Development Cookbook中文翻译(第二章)

Eddy 发布于2013-2-6 12:18:5 分类: 技术心得 已浏览loading 网友评论0条 我要评论

翻译了比较久,年前总算是把这个小任务完成了。文章是用markdown语法来写的,在github上阅读效果更佳:

去GitHub上阅读Yii 1.1 Application Development Cookbook中文翻译(第二章) 

 

简介

本章将帮助你学习Yii框架中关于URL路由、控制器和视图的一些有用的知识。学习完本章内容你可以更加灵活的运用控制器和视图。

配置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)。

  • 1.在protected/config/main.php配置文件中添加如下规则: 'home' => 'website/index', 'alias:about' => 'website/page', 'page/' => 'website/page',
  • 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

http://www.yiiframework.com/doc/guide/en/topics.url

http://www.yiiframework.com/doc/api/1.1/CUrlManager

通过路径生成URLs

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

在URL规则中应用正则表达式

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

    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

     

如何做......

我们想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/)

为静态页面创建URL规则

一个网站一般都包含一些静态页面,比如/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

 

在程序运行时提供你自己的URL规则

当你运用插件模块化架构来开发应用程序时,你肯定希望能以某种方式将指定的模块规则插入到当前的应用程序中。

开始吧

  • 1、运用yiic webapp生成一个新的应用程序。
  • 2、添加.htaccess文件(官方教程的URL管理一节有说明)到你的web根目录。
  • 3、添加 'showScriptName' => false 至urlManager配置中。
  • 4、运用Gii生成Page模块。
  • 5、不要忘记添加你的新模块到应用程序配置文件的模块列表中。

Yii代码生成工具如下图所示:

图省略 

如何做......

  • 1、在protected/components目录下创建ModuleUrlManager.php文件,写入如下代码: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”控制器。

  • 5、你也可以覆盖你的主应用程序中的URL规则。因此,你在模块中指定的URL规则仅当主应用程序中的规则均不匹配才会被应用。

如何工作的......

让我们看看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应用程序。

我们想添加一些控制器,而且我们想这些控制器仅当用户登陆后才能被访问。我们可以再每个控制器中单独的设置约束规则以实现此功能,但有一种更好的办法来实现它。

如何做......

  • 1、首先我们需要基类控制器,我们的用户控制器将会用到。让我们在protected/components目录下创建SecureController.php文件,写入如下代码:
    <?php        class SecureController extends Controller        {            public function filters()            {                return array(                    'accessControl',                );            }            public function accessRules()            {                return array(                    array('allow',                    'users'=>array('@'),                ),                array('deny',                    'users'=>array('*'),                ),                );            }        }
  • 2、现在,在Gii代码生成工具中,在基类中填入 SecureController,你将得到类似如下内容:
    class TestController extends SecureController    {        public function actionIndex()        {            $this->render('index');        }            }
  • 3、现在,你的TestController index动作将仅能被登陆用户访问,即使我们没有在TestController类中显示的声明。

如何工作的......

简单说就是用到了类的继承。如果filters或accessRules在TestController中未找到,那么将会从父类SecureController中调用。

运用外部动作

在Yii中,你可以在单独的类中定义控制器动作,然后把它放到你的控制器中。这种方式你可以复用一些公共的功能。

例如,你可以对一个动作中的自动完成域改变后台,从而节省时间,不需要一遍又一遍的去写。我们要看的一个简单例子是删除一个模型。

开始吧

  • 1、用yiic webapp命令创建一个新的Yii应用程序。
  • 2、用下面的脚本创建数DB据库:
        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`)        );
  • 3、运用Gii生成Post和User模型。

如何做......

  • 1、让我们在posts中写一个常规的delete动作,如下所示:
    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);        }    }

我们定义了两个动作。一个列出所有的帖子,另外一个删除指定的存在的帖子然后重定向到主页。

  • 2、现在,我们在一个单独的动作类中做同样的事情。在protected/components目录下创建DeleteAction.php文件,代码如下所示:
    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',            );        }            }
  • 4、OK。现在post控制器中我们用的是外部的删除动作,但是user控制器如何运用它呢?为了在UserController中运用我们的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);        }    }
  • 5、现在,我们可以为post控制器和user控制器应用此动作了。对post控制,代码如下所示:
    class PostController extends CController    {        function actions()        {        return array(            'delete' => array(                'class' => 'DeleteAction',                'modelClass' => 'Post',            );        );        }        }
  • 6、对于user控制器,我们这样实现:
    class PostController extends CController    {        function actions()        {        return array(            'delete' => array(                'class' => 'DeleteAction',                'modelClass' => 'User',            );        );        }        }
  • 7、这样,通过对相似的任务重用外部动作,你可以节省很多时间。

如何工作的......

每个控制器都可以用外部的动作来构建,就像拼图一样。不同之处在于你可以灵活的运用外部动作,而且可以在其他地方对其复用。在DeleteAction的最终版本中,我们定义了一些公共的属性。因为DeleteAction是一个组件,因此我们可以配置它的属性。在此例中,我们将配置信息传递给动作,以此来为一个模块添加动作。

更多......

参考下面的地址可获取更多信息:

http://www.yiiframework.com/doc/api/CAction/

http://www.yiiframework.com/doc/api/CController#actions-detail

用CViewAction显示静态页面

如果你有一些静态页面,而且你不是经常修改它,那么就没有必要去查询数据库执行页面渲染与管理。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何做......

  • 1、我们只需要将CViewAction连接到我们的控制器即可。
    class SiteController extends CController    {        function actions()        {            return array(                'page'=>array(                    'class'=>'CViewAction',                ),            );        }    }

当然你也可以用如下的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. 

延伸阅读

参考下面的地址可获取更多信息:

http://www.yiiframework.com/doc/api/CViewAction

运用flash消息

当你运用表单来编辑模型、删除模型或是做其他操作,告诉用户结果是成功还是出错,这对用户来说是很友好的。典型的例子就是,在某个操作后,比如编辑表单,然后会有一个网页重定向,我们需要在重定向的网页上显示消息。然而,如何从当前页面传递消息到重定向页面,传递完成后清除消息呢?Flas消息将会帮助我们。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何做......

  • 1、让我们创建一个protected/controllers/WebsiteController.php控制器,代码如下:
    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');        }    }
  • 2、另外,创建protected/views/website/index.php视图,代码如下:
    <?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消息:

http://www.yiiframework.com/doc/api/CWebUser

在视图中运用控制器实例

Yii视图非常优雅且功能强大。其中很有用的一个就是你可以在视图中使用控制器实例。我们试试吧。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何做......

  • 1、创建一个控制器,代码如下:
class WebsiteController extends CController{    function actionIndex()    {        $this->pageTitle = 'Controller context test';        $this->render('index');    }    function hello()    {        if(!empty($_GET['name']))        echo 'Hello, '.$_GET['name'].'!';    }}
  • 2、现在,我们创建一个视图来看看我们能做什么:
<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文档,里面列出了有你可以在视图中应用的一些方法:

http://www.yiiframework.com/doc/api/CController

运用局部视图来重用视图

Yii支持局部视图,如果你有一个单独的不包含很多业务逻辑的块,你想重用它或是把它当做Email的模板。那么局部视图就是最好的选择。

开始吧

  • 1、用yiic webapp命令创建一个新的Yii应用程序。

  • 2、新建WebsiteController,代码如下:

class WebsiteController extends CController{    function actionIndex()    {        $this->render('index');    }}

如何实现......

我们以需要重用某一代码块为例开始讲解。例如,我们需要在很多页面中嵌入一个YouTube视频。让我们为其创建一个可重用的模板。

  • 1、新建视图文件protected/views/common/youtube.php,从YouTue拷贝嵌入视频的代码。如下所示:
<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>
  • 2、现在,我们需要使它能被重用。我们想能够设置video ID,width和height。我们让width和height可选,如下所示:
<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>
  • 3、现在你可以在protected/views/website/index.php中这样来使用它:
<?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/控制其名/目录下寻找视图文件**】。

  • 4、现在,让我们发送一些Emails。因为我们不能给上千用户发送同样的邮件,所以我们将使用一个可定制的模板 。让我们在protected/controllers/WebsiteController.php中添加一个新的方法,如下所示:
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));    }}
  • 5、下面是我们的模板protected/views/email/welcome.php:
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

运用代码片段(clips)

在Yii中有一个功能可以让你在视图中运用clips。它的基本思想就是你可以记录一些输出内容,然后在其它地方对其重用。一个好的例子就是你可以在布局中定义额外的可在其他地方进行填充的内容区域。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何实现......

  • 1、对于我们的这个例子,我们需要在布局中定义两个区域:beforeContent和footer。打开protected/views/layouts/main.php文件,在内容输出(<?php echo $content; ?>)前插入以下内容:
<?php if(!empty($this->clips['beforeContent'])) echo$this->clips['beforeContent']?>

然后,插入以下内容至

<?php if(!empty($this->clips['footer'])) echo$this->clips['footer']?>
  • 2、现在我们需要在某处来填充这些区域。我们将用一个控制器动作来填充beforeContent区域。打开protected/controllers/ SiteController.php文件,添加如下代码到actionIndex方法中:
$this->beginClip('beforeContent');echo 'Your IP is '.Yii::app()->request->userHostAddress;$this->endClip();
  • 3、对于footer,我们将在视图中设置它的内容。打开protected/views/site/index.php文件,添加如下代码:
<?php $this->beginClip('footer')?>This application was built with Yii.<?php $this->endClip()?>
  • 4、现在,打开网站的首页你将会看到在页面内容前会显示你的IP地址,页面内容后会显示“built with”标签。

如何工作的......

我们用代码来标记特殊的区域,然后在输出前进行检验。如果存在则输出其内容。然后,我们用控制器方法 beginClip 和 endClip 来为clips填充内容。

运用装饰件(decorators)

在Yii中,我们可以把要输出内容包装到decorator中。decorators最普通的应用就是布局。当你在控制器方法中调用render方法来渲染视图时,Yii自动的用main布局视图来包装它。让我们创建一个简单的decorator来格式化显示引用内容。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何实现......

  • 1、首先,我们创建一个装饰文件protected/views/decorators/quote.php:
<div class="quote">&ldquo;<?php echo $content?>&rdquo;, <?php echo $author?></div>
  • 2、现在我们将在protected/views/site/index.php中运用我们的装饰件:
<?php $this->beginContent('//decorators/quote', array('author' =>'Edward A. Murphy'))?>If anything bad can happen, it probably will<?php $this->endContent()?>
  • 3、现在你的主页应该包含下面的标记:
<div class="quote">&ldquo;If anything bad can happen, it probably will&rdquo;,Edward A. Murphy</div>

如何工作的......

decorators非常简单。在beginContent和endContent之间的任意内容都被当做$content变量传送到decorator模板中。然后, decorator模板将会渲染它并将它插入到endContent调用处。我们可以利用beginContent的第二个参数传送额外的变量到decorator中,我们的示例中对于作者参数就是这么做的。

[注意:我们用到//decorators/quote作为视图路径,这样做的意思就是视图文件将从主题视图根目录下开始寻找,而不是从应用程序视图根目录下开始寻找]

更多......

访问下面的URL获取更多关于decorators的信息:

http://www.yiiframework.com/doc/api/CContentDecorator/

定义多重布局

大多数应用程序对于所有的视图使用单一的布局。然而,有些时候需要多个布局。例如,一个应用程序可以在不同的页面使用不同的布局:博客的页面有两个附加列,文章页面要一个额外的列,归档页面不需要额外的列。

开始吧

用yiic webapp命令创建一个新的Yii应用程序。

如何实现......

  • 1、在protected/views/layouts下创建两个布局:blog和articles。Blog包含下列代码:
<?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()?>
  • 2、Articles将包含以下代码:
<?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()?>
  • 3、创建三个控制器BlogController、ArticleController、PortfolioController,如下所示:
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记录进行分页并对其数据进行归类整理。

开始吧......

  • 1、用yiic webapp命令创建一个新的Yii应用程序。
  • 2、创建一个数据库,新建表post,字段包含id和title,添加10-20条记录。
  • 3、用Gii生成Post模型。

如何实现......

  • 1、首先,你需要创建控制器 protected/controllers/PostController.php :
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,        ));    }}
  • 2、修改视图文件 protected/views/post/index.php ,如下所示:
<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,))?>
  • 3、试着访问 http://example.com/post ,你将看到分页显示的数据,并且有按ID或标题排序的链接。

它是如何工作的......

首先,我们获取模型记录总数,并用它初始化分页组件实例。然后,我们用 applyLimit 方法来施加限制。随后,我们为模型创建 sorter 实例对象,通过调用 applyOrder 方法指定我们想要按哪些字段进行排序。最后,我们将修改过的规则传递给 findAll 。在这一步,我们已经有了模型数据列表、分页数据链接和用来生成数据整理链接的 sorter 实例对象。

在视图中,我们用到了我们在模型中生成的数据。首先,我们用 CSort::link 方法生成链接。然后,我们列出模型数据。最后,用CLinkPager 挂件生成分页导航。

更多......

访问下面链接获取更多关于分页和数据整理的信息:

http://www.yiiframework.com/doc/api/CPagination/

http://www.yiiframework.com/doc/api/CSort/

已经有(0)位网友发表了评论,你也评一评吧!
原创文章如转载,请注明:转载自Eddy Blog
原文地址:http://www.rrgod.com/technique/869.html     欢迎订阅Eddy Blog

记住我的信息,下次不用再输入 欢迎给Eddy Blog留言