zoukankan      html  css  js  c++  java
  • 《应用Yii1.1和PHP5进行敏捷Web开发》学习笔记(转)

    1、建立应用程序:
     
      YiiRoot/framework/yiic webapp demo
     
    2、添加链接:
     
       <a href="/demo/index.php?r=message/goodbye">Goodbye!</a>
       <?php echo CHtml::link("Goodbye",array('message/goodbye')); ?>
     
    3、Unit 单元测试:
     
    单元测试是软件测试中最小的单位,在面向对象的应用程序中,(如Yii应用程序)的最小单位是类的接口,公共的方法。单元测试集中在一个单独的类中,而不要求与其它类或对象一起运行。他们的目的是为了验证一个最小单位的代码是否达到预期目的。
     
    4、功能测试
     
    功能测试重点测试应用程序端对端的功能特性。这个测试相对于单元测试要高一个层次,通常要多个类或对象一起运行。功能测试的目的是验证一个给定的应用程序功能是否可以正常工作。
     
    5、目录/protected/tests/是测试用目录。
     
    6、要建立一个支持DBMS的连接,可以简单的实例化CDbConnection类:
     
         $connection=new CDbConnection($dsn,$username,$password);
     
    7、一般用小写字母定义数据库名和表明。表名前可以加前缀,比如tbl_project,表名使用了一个tbl_前缀。在Yii中为了采用表前缀支持,必须设置CDbConnection::tablePrefix属性为期望的表前缀。然后在整个应用程序的SQL语句中,可以使用{{TableName}}做为参考表名,其中TableName就是表的名称,但不用前缀。
     
    例:    $sql='SELECT * FROM {{project}}';
               $projects=Yii::app()->db->createCommand($sql)->queryAll();
     
    8、在Project AR模型类的rules()方法返回的是一个规则数组,一般每一个规则格式如下所示:
     
          Array('Attribute List', 'Validator', 'on'=>'Scenario List', …additional options);
     
          Attribute List(属性列表)是一个字符串,需要验证的类的属性名用逗号分开。Validator(验证器)指的是使用什么样的规则执行验证。on这个参数指定了一个scenario(情景)列表来使用这条验证规则。
     
         scenario(情景)允许你限制验证规则应用在特定的上下文中。一种典型的例子是insert(插入)或update(更新)。例如:如果被指定为 'on'=>'insert',这将表明验证规则只适用于模型的插入情景。这同样适用于'update'或其它的任何你希望定义的情景。你可以设置一个模型的scenario(情景)属性或能过构造函数传给一个模型的实例。
     
    9、为了使用这一内置验证器,我们需要为我们的模型类添加一个新属性。
     
         在User模型AR类顶部添加如下代码:public $password_repeat;
     
         们在期望对比的属性名后附加_repeat,形成了与之对比的新属性名。对比验证器允许你设置2个属性名,或者属性名和确定值进行对比。在没有明确指出对比规则的情况下,默认对比属性名相同,后接_repeat的属性。这也是我们为何如此命名的用意。现在我们可以按照如下方式在User::rules()添加验证器:array('password', 'compare'),
     
         由于我们直接在User AR类中添加了$password_repeat属性,并且它与底层数据库表之间没有对应关系,我们需要告诉模型类允许这个属性在setAttributes()被调用时被设置。我们的做法是将其添加到User模型类的安全属性列表中。向User::rules()数组添加下列代码:array('password_repeat', 'safe'),
     
         简单介绍一下,当表单提交到UserController::actionCreate()方法时,会使用下列的代码将User 模型类的属性进行批量转换:
            $model->attributes=$_POST['User'];
     
        在这里,所有$_POST[‘User’]数组里的项会和$model类安全属性列表中的做匹配,成功匹配的完成赋值。默认的,除了主键外的所有底层数据库表里的字段都被视为安全的。我们新建的$password_repeat不存在对应的tbl_user表中的列,需要将其直接添加到安全属性列表。
     
    10、Yii认证框架的核心是一个叫user的应用组件,一般来说,是IWebUser接口的对象实现。这个具体的类是默认通过框架类CWebUser实现的。这个用户组件封装了所有当前用户在整个应用中的认证信息。这个组件的配置在我们使用yiic工具自动生成整个项目代码的时候被创建。具体配置信息可以在protected/config/main.php文件查看,基于components数组:
     
      'user'=>array(
         // enable cookie-based authentication '
         allowAutoLogin'=>true,
       ),
     
          因为它被配置成了一个使用关键词‘user’的应用组件,所以我们可以在我们项目中的任何地方通过Yii::app()->user进行访问。
     我们也发现了类属性allowAutoLogin也在这里被设置好了。这个属性默认值为false,但是当设置为true时,可以将用户的信息持久的储存在浏览器的cookies里。储存的信息将在后面的访问中自动用于认证。这样我们就可以在登录表单显示一个Remember Me复选框,当用户选中的情况下,再次访问网站都会自动登录进行。
     
    11、User::model()->updateByPk($this->_identity->id, array('last_login_time' => new CDbExpression('NOW()')));  
     
    12、访问控制过滤器
     
      public function filters() {
        return array( 
            'accessControl',
            // perform access control for CRUD operations 
        );
      public function accessRules()
      {
         return array(
             array('allow', // allow all users to perform 'index' and'view' actions
                 'actions'=>array('index','view'),
                 'users'=>array('*'),
             ),
             array('allow', // allow authenticated user to perform 'create' and 'update' actions
                 'actions'=>array('create','update'),
                 'users'=>array(),
             ),
             array('allow', // allow admin user to perform 'admin' and 'delete' actions
                 'actions'=>array('admin','delete'), 
                 'users'=>array('admin'),
             ), 
             array('deny', // deny all users
                 'users'=>array('*'),
             ),
         );
      }
     
    accessRules()方法中,有4条规则被申明。每一条都以数组形式存在。该数组的第一个元素是allow(通过)或deny(拒绝)。分别标识了获得或拒绝相关访问。剩下的部分由 name=>value键值对组成,申明了规则里剩余的参数。星号‘*’特殊字符泛指所有用户(包括匿名,已认证,和其他类型)。‘@’特殊字符泛指所有已认证用户。
     
    定义访问规则的时候可以使用一些 context parameters(内容参数)。前面提到的规则定义了行为和用户来组成规则的内容,下面是一个完整的参数列表:
    Controllers(控制器):这条规则指定了一个包含多个控制器ID的数组,来指明哪些规则需要被应用。 
    Roles(角色):这条规则指定了一个将被规则使用的授权列表(包括角色,操作,权限等)。这些是为RBAC的一些功能服务的。
     
    Ips(IP地址):这条规则指定了一组可以被施加到规则的客户端IP地址。 
    Verbs(提交类型):这条规则制定了可以被施加到规则的HTTP请求类型。 
    Expression(表达式):这个规则指定了一个PHP表达式,这个表达式的值被用来决定这个规则是否应该被使用。 
    Actions(行为):这个规则指定了需要被规则匹配的对应action ID(行为ID)的方法。 
    Users(用户):这个规则指定了应该被施加规则的用户。登录当前项目的用户名作为被匹配项。3个特殊字符可以被使用: 
    *:任何用户 
    ?:匿名用户 
    @:登录用户/认证用户 
    访问规则按照其被申明的顺序一条一条的被评估。第一条规则与当前模型进行匹配,来判断授权结果。如果当前规则是一个allow的,这个行为(action)可以被执行;如果是一个deny规则,这个action无法被执行;如果没有规则和内容匹配,这个action仍然可以被执行。这是第四条被定义的原因。如果我们不在我们的认证列表末端定义一条deny全部用户全部action的规则,我们就无法完成预期的访问控制。拿第二个规则来举例,所有通过认证的用户可以执行create和update actions。但是它并不会拒绝匿名用户的请求。它对匿名用户熟视无睹。这里第四条规则确保所有和上面3条不匹配的请求都被拒绝掉。
     
    13、格式化url
     
    (1)在main.php中增加以下代码,即可将url变为路径格式。
     
             'urlManager'=>array( 
                 'urlFormat'=>'path',
             ),
     
       例:http://localhost/trackstar/index.php?r=issue/view&id=1变为http://localhost/trackstar/index.php/issue/view/id/1
     
    (2) Yii的URL管理器允许我们指定规则来定义URL的解析和创建。定义一个路由规则和模式,该模式用于匹配URL,以确定哪些规则用于解析或创建URL。该模式可以包含命名参数,它使用的语法为ParamName:RegExp(参数名:正则表达式)。当解析一个URL,一个匹配的规则将提取路径信息中的命名的参数放到$_GET变量中。当通过应用程序创建一个URL时,一个匹配的规则将从$_GET变量中提取命名的参数并放到路径信息中。如果模式以‘/*’结尾,它的意思有更多的GET参数附加到URL路径信息的中。指定URL规则,设置CUrlManager的rules属性,rules是一个数组,其中的格式为pattern=>route(模式=>路由)。
     
    举个例子,让我们看看下面两条规则:
    'urlManager'=>array( 
        'urlFormat'=>'path',
        'rules'=>array(
            'issues'=>'issue/index', 
            'issue/<id:d+>/*'=>'issue/view', 
        )
     
    上面代码中指定了两条规则。第一条规则说明,如果用户请求的URL是http://localhost/trackstar/index.php/issues,它应被视为http://localhost/trackstar/index.php/issue/index,并且这条规则也同样适用于创建URL。
     
    第二条规则使用了语法包含了一个命名参数ID,它的意思,例如,如果用户请求的URL为http://localhost/trackstar/index.php/issue/1,它应被视为http://localhost/trackstar/index.php/issue/view?id=1。并且这条规则也同样适用于创建URL。
     
    路由部分本身也可以指定为一个数组,如指定URL后缀或是否区分大小写等其它属性。我们将利用这些优势,指定我们的评论feed规则。
    让我们将下列规则添加到我们的urlManager组件配置中:
     
    'urlManager'=>array( 
        'urlFormat'=>'path',
        'rules'=>array(
            'commentfeed'=>array('comment/feed', 'urlSuffix'=>'.xml', 'caseSensitive'=>false),
        ),
    ),
     
    在这里,我们使用urlSuffix属性指定了我们想要的.xml作为后缀。
    现在,我们可以通过下面的URL访问feed:http://localhost/trackstar/index.php/commentFeed.xml
     
    (3)从URL中移除入口文件现在我们需要从URL中移除index.php。需要两步完成:修改Web服务器配置,重定向所有请求的路由到index.php,但不包括已经存在的文件或目录。设置UrlManager的showScriptName属性为false。第一步操作是告诉应用程序怎样处理路由请求,第二步操作是告诉应用程序如何创建URL。
     
    由于我们使用的是Apache HTTP Server,第一步我们可以在应用程序根目录创建一个.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这种方式只适用于Apache HTTP Server。如果你使用的是不同的Web服务器,你将需要编写新的重写(rewrite)规则文件。另外请注意,这些信息可以放在Apache的配置文件中使用以替代.htaccess文件。
     
    htaccess文件创建后,我们现在可以通过以下URL访问feed,http://localhost/trackstar/commentfeed.xml (或http://localhost/ trackstar/commentFeed.xml因为我们设置了caseSensitive为false,不区分大小写)
    然而,即使这样,如果我们在应用程序中使用一个控制器方法或CHTML助手方法创建URL,在一个控制器类中执行下面的代码:
    $this->createAbsoluteUrl('comment/feed');它将生成的URL仍然包括index.php: http://localhost/trackstar/index.php/commentfeed.xml
    当生成URL时为了不使用入口文件,我们需要设置urlManager组件的属性。我们再才修改main.php配置文件,例如:
     
    'urlManager'=>array( 
        'urlFormat'=>'path', 
        'rules'=>array(
            'commentfeed'=>array('site/commentFeed', 'urlSuffix'=>'.xml', 'caseSensitive'=>false),
        ),
        'showScriptName'=>false,
    ),
     
    在URL中为了处理指定project ID的评论feed,我们需要添加另外一个规则:
     
    'urlManager'=>array( 
        'urlFormat'=>'path',
        'rules'=>array(
            '<pid:d+>/commentfeed'=>array('site/ commentFeed', 'urlSuffix'=>'.xml', 'caseSensitive'=>false),
            'commentfeed'=>array('site/commentFeed', 'urlSuffix'=>'.xml', 'caseSensitive'=>false),
        ), 
        'showScriptName'=>false,
    ),
     
    这条规则同样也使用了语法指定模式,URL的commentfeed.xml部分之前指定了一个project ID。通过这条规则,我们可以限制评论的feed指定到一个具体的project。例如,如果我们只想要project #2的评论的feed,URL格式是:http://localhost/trackstar/2/commentfeed.xml
     
    14、日志
     
    根目录的index.php文件中的如下代码,决定了应用程序是否处于调试模式:
    defined('YII_DEBUG') or define('YII_DEBUG',true);
     
    可以在SiteController类添加一个小action来看看被记录的内容,代码如下:
     
    public function actionShowLog() 
    {
        echo "Logged Messages:<br><br>"; 
        var_dump(Yii::getLogger()->getLogs());
    }
     
    可以通过以下2个静态方法中的一个来记录信息:
    Yii::log($message, $level, $category) 
    Yii::trace($message, $category)
     
    类型和等级当记录一个信息,我们需要指定它的类型和等级。类型是表现为xxx.yyy.zzz格式的类似路径代理的字符串。例如,如果在SiteController类中记录一条信息,我们可以选择使用application.controllers.SiteController作为类型。类型为被记录信息提供了而外的内容。另外当使用Yii::log为被记录信息指定一个类型时可以同时指定一个等级。等级可以被认为是该消息的缩略。虽然你可以自定义等级,但是一般我们使用以下的一种:
     
    Trace:这一等级一般被用来基于开发环境的应用程序工作流 
    Info:这个是日志的大概内容,而且也是未指定下的默认类型 
    Profile:这一等级被用来描述上面提到的性能方面的功能 
    Warning:警告信息 
    Error:错误信息
     
    例:添加一个登录日志信息:
     
    public function actionLogin() 
    {
        Yii::app()->language = 'rev';
       Yii::trace("The actionLogin() method is being requested",
            "application.controllers.SiteController");
     
        if(!Yii::app()->user->isGuest) 
        {
            $this->redirect(Yii::app()->homeUrl);
        } 
     
        $model=new LoginForm;
     
        // if it is ajax validation request 
        if(isset($_POST['ajax']) && $_POST['ajax']==='login-form') 
        {
            echo CActiveForm::validate($model); 
            Yii::app()->end();
        }
     
        // collect user input data 
        if(isset($_POST['LoginForm'])) 
        {
            $model->attributes=$_POST['LoginForm']; 
            // validate user input and redirect to the previous page if valid
            if($model->validate() && $model->login()) 
            {
               Yii::log("Successful login of user: " . Yii::app()->user- >id,
                    "info", "application.controllers.SiteController");
                $this->redirect(Yii::app()->user->returnUrl);
            }
            else {
                Yii::log("Failed login attempt", "warning", "application. controllers.SiteController");
            }
        }
     
        // display the login form 
        //public string findLocalizedFile(string $srcFile, string $srcLanguage=NULL, string $language=NULL)
        $this->render('login',array('model'=>$model));
    }
     
    消息路由
     
           如我们所说,默认的,Yii::log和Yii::trace将信息存储在内存中。一般的,将这些消息显示在浏览器窗口中会使得它们非常有价值,或者存储到一些持久化介质中,或者是发送email,甚至是数据库中。Yii的消息路由功能允许将日志信息路由至不同目的地.
    在Yii中消息路由是由CLogRouter应用程序组件管理的。它允许你定义一系列消息目的地。
     
            为了利用消息路由的功能,我们需要在protected/config/main.php中配置CLogRouter应用程序组件。我们通过设置它的routes属性为需要的路由地址来完成该动作。
     
    'log'=>array(
        'class'=>'CLogRouter', 
        'routes'=>array(
            array( 
                'class'=>'CFileLogRoute', 
                'levels'=>'error, warning',
            ), 
            // uncomment the following to show log messages on web pages 
            /* 
            array(
                'class'=>'CWebLogRoute',
            ), 
            */
        ),
    ),
     
    此处把信息记录在了文件中(protected/runtime/application.log中),如果打开
            array(
                'class'=>'CWebLogRoute',
            ),
    则可将信息显示到页面中。
     
    Yii 1.1版的消息路由列表:
    CDbLogRoute: 将消息存储到数据库表中 
    CEmailLogRoute:将消息发送至特定的e-mail地址 
    CFileLogRoute:将消息保存至应用程序runtime文件夹下的一个文件中 
    CWebLogRoute:在当前页面的结尾显示消息 
    CProfileLogRoute:在当前页面结尾显示profiling消息
     
    15、缓存:
     
    Yii提供了很多基于不同存储介质实现缓存的缓存组件类。下面是Yii 1.1.2所支持的缓存实现列表:
    CMemCache : 使用PHP memcache 扩展。 
    CApcCache : 使用PHP APC扩展。 
    CXCache : 使用PHP XCache扩展。 
    CEAcceleratorCache : 使用PHP EAccelerator扩展。 
    CDbCache : 使用数据库表存储缓存数据。默认的,它将在runtime文件夹下建立一个SQLite3数据库。你可以通过connectionID属性指定数据库。 
    CZendDataCache : 使用Zend Data Cache作为优先的缓存媒介。 
    CFileCache : 使用文件来存储缓存数据。特别适合存储类似页面的大块数据。 
    CDummyCache : 这里实现一般的缓存接口,但不做任何实际缓存。这一实现的原因是你需要执行缓存,但是你的开发环境不支持缓存。这允许你在实现真正缓存之前持续编码。你不需要为缓存环境而改变编码。
    所有的这些组件都扩展自CCache,并且提供相同的接口。也就是说你可以改变不同的缓存策略而不需要改变代码。
     
            配置缓存如前面所说,在Yii中使用缓存,需要选择一个缓存组件,然后在应用程序配置文件(/protected/config/main.php)中进行配置。不同的缓存实现决定了不同的配置。如果要使用memcached就要使用CMemCache类,是一个分布式内存对象缓存系统,允许你使用多台主机进行缓存,如果要使用2台服务器应该如下配置:
     
    array( 
        ......
        'components'=>array( 
            ......
            'cache'=>array( 
                'class'=>'system.caching.CMemCache', 
                'servers'=>array(
                    array('host'=>'server1', 'port'=>12345, 'weight'=>60),
                    array('host'=>'server2', 'port'=>12345,'weight'=>40), ),
                ),
        ),
    );
     
            CFileCache提供了一个基于文件系统的缓存结构。当使用它的时候,每一个数据值都会被缓存并存储在一个独立的文件中。默认的,这些文件被存储在/protected/runtime/cache文件夹下,但是可以通过修改cachePath属性来轻松改变这一位置。对我们来说默认已经ok了,所以我们只需要在配置文件/protected/config/main.php中进行如下配置:
     
    // application components 
    'components'=>array(
        ...
        'cache'=>array( 
            'class'=>'system.caching.CFileCache',
        ),
        ...
    ),
     
    当上面的都完成之后,我们可以在应用程序的任何位置通过Yii::app()->cache 来访问这一新组件。
     
    使用基于文件的缓存
    public static function getLatest() 
    {
        //see if it is in the cache, if so, just return it 
        if( ($cache=Yii::app()->cache)!==null) 
        {
            $key='TrackStar.ProjectListing.SystemMessage'; 
            if(($sysMessage=$cache->get($key))!==false)
                return $sysMessage;
        }
     
        //The system message was either not found in the cache, or 
        //there is no cache component defined for the application 
        //retrieve the system message    from the database
        $sysMessage = SysMessage::model()->find(array( 
            'order'=>'t.update_time DESC',
        ));
     
        if($sysMessage != null)
        {
            //a valid message was found. Store it in cache for future retrievals
            if(isset($key)) 
                $cache->set($key,$sysMessage,300);
            return $sysMessage;
        } 
        else
            return null;
    }
    使用$cache->set()方法将其存入缓存。该方法格式如下:
    set($key,$value,$duration=0,$dependency=null)
    key就是上面提到的唯一的字符串值,value就是希望存入缓存的数据值。可以是任何格式的,唯一的要求是可以被序列化。duration参数是一个指定生存周期的可选项。确保缓存中的数据定时被刷新。默认值为0,也就是说数据永远不会过期,将永远存在缓存中。(实际上,在Yii中将小于等于0的持续时间理解为1年后过期。所以,并非永远,只是一个很长的时间。)
     
       注:如果当前还不知道使用何种缓存机制,可以使用CDummyCache。它不会存储任何实质数据到缓存中,但是可以使代码正常运行。
     
    缓存dependencies(依赖)
    dependency参数允许以选择并且更复杂的形式来决定存储在缓存中的数据是否需要刷新。并非简单的定义一个过期时间,你的缓存策略可能为在特殊用户发出请求后缓存数据变为非法,或者是应用程序的状态,或者是文件系统中的文件最近刚被更新过。该参数允许你指定相关的缓存校验规则。
    dependency是CCacheDependency或其子类的一个实例。Yii允许下面的缓存依赖:
    CFileCacheDependency : 缓存数据将在特殊文件最后更新时间自上次检查后发生改变时变为非法。 
    CDirectoryCacheDependency : 类似上面的文件缓存依赖,不过该方法将检查指定文件夹下的所有文件和子文件夹。 
    CDbCacheDependency : 缓存中的数据将在自上次检查后相同语句在数据库中查询结果发生改变后变得非法。 
    CGlobalStateCacheDependency : 缓存中的数据将在特殊标识全局状态值发生改变后变得非法。全局状态是应用程序中的一个在多页面多请求中持久保存的一个变量。通过调用CApplication::setGlobalState()来设置。
    CChainedCacheDependency : 该项允许你将多个缓存依赖链接起来。当链上的任一缓存依赖发生改变时,缓存中的值变为非法。 
    CexpressionDependency : 当特殊php表达式的结果发生改变时缓存中的数据变为非法。
     
     修改我们的set方法调用,设置持续时间为0,所以它不会基于时间过期,同时传入一个新的基于特定SQL语句的依赖实例:
    $cache->set($key, $sysMessage->message, 0, 
          new CDbCacheDependency('select id from tbl_sys_message order by update_ time desc'));
    将持续时间改为0并非使用依赖的先决条件。我们可以将持续时间保持为300。这只会增加一条缓存合法的验证规则。缓存中的数据会按照5分钟为最大值来完成校验,但是当小于5分钟的情况下,update_time发生了改变也会触发缓存更新。
    如果缓存的数据足够复杂,这样一个简单的sql语句做缓存刷新判断就有一定价值了。
     
    Fagment(片段)缓存
    片段缓存用来缓存一个页面的一部分。我们可以在view脚本中使用片段缓存。我们通过使用CController::beginCache()和CController::endCache()方法来实现。
    ...some HTML content... 
    <?php if($this->beginCache($key)) { ?> 
    ...content to be cached... 
    <?php $this->endCache(); } ?> 
    ...other HTML content...
    一般来说,应该在view文件中按照如下的形式使用片段缓存:如果调用beginCache()返回false,缓存中的内容将会被自动插入指定位置。反之,如果if语句返回true,endCache()之前的内容将被缓存。
     
    声明片段缓存可选参数
    当调用beginCache()方法时,我们提供一个数组作为第二个参数,该数组包含了自定义片段缓存的可选项。事实上,beginCache()和endCache()方法是一个方便的COutputCache过滤器/部件的包裹器。因此,这里的缓存选项可以为任意COutputCache的属性。
    无可厚非的一个最常用属性就是持续时间,即指定了缓存中的内容保留的时间。它很像我们在之前系统消息缓存中使用的duration参数。你可以按照如下格式为beginCache()提供duration参数:
    $this->beginCache($key, array('duration'=>3600))片段缓存的默认设置与数据缓存不同。如果我们不设置持续时间,默认为60秒,也就是60秒后更新。当使用片段缓存时有很多可选参数。
     
    使用片段缓存
    <?php 
    $key = "TrackStar.ProjectListing.RecentComments"; 
    if($this->beginCache($key, array('duration'=>120))) {
        $this->beginWidget('zii.widgets.CPortlet', array( 
            'title'=>'Recent Comments',
        )); 
        $this->widget('RecentComments'); 
        $this->endWidget(); 
        $this->endCache();
    ?>
     
    页面缓存
    作为片段缓存的扩充,Yii提供了对整个页面进行缓存的选项。页面缓存和片段缓存很相似。然而,因为页面的内容经常是一个view文件调用布局文件的结果,所以我们无法简单的在布局文件中调用beginCache()和endCache()方法。原因是布局被应用到CController::render()方法中的view内容生成时。所以我们将错过从缓存获取数据的机会。
    所以,想要缓存整个页面,我们需要跳过页面生成的过程。为了达到这一点,我们可以使用COutputCache类作为一个我们控制器类中的一个行为过滤器。
     
    例:
    打开 protected/controllers/ProjectController.php,并且将已经存在的filters()方法修改为如下形式:
    public function filters() 
    {
        return array( 'accessControl', // perform access control for CRUD operations
            array(
                //cache the entire output from the actionView() method for 2 minutes
                'COutputCache + view', 
                'duration'=>120, 
                'varyByParam'=>array('id'),
            ),
        );
    }
     
    该filter配置为利用COutputCache过滤器来缓存整个被应用程序调用ProjectController::actionView()方法生成的内容。+ view 添加在 COutputCache后,如你所能记得的,是对特殊方法添加过滤器的标准的方式。持续时间被设置为页面生成后的2分钟。
     
    varyByParam是我们之前提起过的一种很重要的可选项。为了给你减轻压力,减少编写标识被缓存内容key的工作量,该功能允许key被框架自动控制。也就是说,通过指定一系列来自GET参数中的名称。当我们开始通过project_id请求project时,系统将会很好的使用该id作为唯一key的一部分来生成缓存内容。通过指定'varyByParam'=>array('id'),COutputCache为我们完成了基于输入请求字符串中id的余下工作。这里有很多可选项,在我们使用COutputCache来缓存数据时,来作为自动生成key名字的策略。下面是可以使用的一个列表: 
    varyByRoute:通过将该选项设置为true,具体请求的路由部分将会作为独立标识符的一部分用于生成缓存数据。所以,你可以使用请求controller和acion的组合来区别缓存内容。 
    varyBySession:通过设置该选项为true,将使用唯一的session id来区分缓存中的内容。每个用户的session都是不同的,但是可以用来为缓存服务。 
    varyByParam:如前面所说,这里是用输入的GET中的参数来区分缓存内容。 
    varyByExpression:给该选项设置PHP表达式,我们可以使用相应表达式的结果来区分缓存的内容。
    所以,当在ProjectController类中配置了上面的过滤器后,每次针对某个项目的请求内容都会被缓存,并且在2分钟后刷新缓存。你可以通过先缓存一个项目的细节,然后使用某种方法刷新缓存来查看。所有的更新都会在其生存周期结束后才可以观察到。
    缓存全部页面内容是极大提升性能的一种方式,但是对每一个应用程序中的每一个页面进行缓存没有意义。做一个上面3种方式的总结:数据,片段和页面缓存,在大多数真实的项目中是需要的。我们只简单的了解了一下Yii中提供的缓存功能。希望这能为你迅速看清Yii的缓存功能提供助力。
     
    16、 Yii中更多与AR关联查询相关的
     
    以下方法采用的是延迟加载。当我们第一次创建该项目的实例时,该查询不返回相关的所有问题(issue)。它只是一个初步的查询,当执行$project->issues才会进一步确定相关的问题。这被叫做惰性查询,因为它会等待加载问题(issue)。
    // retrieve the project whose ID is 1 
    $project=Project::model()->findByPk(1);
    // retrieve the project's issues: a relational query is actually being performed behind the scenes here
    $issues=$project->issues;
     
    这种方法很方便,也非常有效,尤其是在不需要那些相关问题(issue)的情况下。但是,在其他情况下,这种方法效率可能有点低。例如,如果我们查询N个项目的问题(issue),使用这种惰性方式将执行N次连接查询。如果N很大,这可能非常低效。在这种情况下,我们选择另一种方式叫做预加载(Eager Loading)
    预加载方式的关相AR实例同时也是主AR实例的请求。这是通过使用with()方法与find()或findAll()方法两者一起的AR查询。继续我们的项目实例,我们可以执行以代码,使用预加载方式立即查询所有项目的问题(issue):
    //retrieve all project AR instances along with their associated issue AR instances 
    $projects = Project::model()->with('issues')->findAll();
    在这种情况下,$projects数组中的每一个project AR实例的issues属性都已经被赋值了。这一结果仅使用了一个连接查询。
    我们在findRecentComments()方法中使用了两种关联查询。一种是限制了获得的评论是在一个具体的项目(project)中。正如你看到的,我们在预加载问题(issue)时指定一个查询条件。让我们看看下面这行代码:
    Comment::model()->with(array('issue'=>array('condition'=>'project_ id='.$projectId)))->findAll();这个查询连接了tbl_comment表和tbl_issue表。继续project id等于#1这个例子,上面的AR关联查询基本执行的是类似下面的SQL语句:
    SELECT tbl_comment.*, tbl_issue.* FROM tbl_comment LEFT OUTER JOIN tbl_issue ON
    (tbl_comment.issue_id=tbl_issue.id) WHERE (tbl_issue. project_id=1)我们在findAll方法的参数数组中指定了一个排序(order)和限定(limit)的条件来执行SQL语句。
    最后一点需要注意的是,在两个查询中我们是如何处理两个表相同列名的歧义。显示,当两个正在连接的表具有相同的列名,我们要在查询时,区别两者。就这个例子而言,两个表都定义了create_time列。我们尝试排序的列是在tbl_comment表中而不是定义在issue表中。在Yii的AR的关联查询中,对主表的别名被固定为t和,而对关联表的别名,默认情况下与关联名相同。因此,在我们这两个查询中,我们指定t.create_time表示我们要使用主表的列。如果我们想使用issue表的create_time列,我们将要修改例子中的第二个查询为如下这样:
    return Comment::model()->with('issue')->findAll(array( 
        'order'=>'issue.create_time DESC', 
        'limit'=>$limit,
    ));
     
    17、添加管理模块
     
    (1)建立一个模块:
    使用Gii代码生成工具建立一个新模块是非常容易的。打开以后选择,左边菜单的Module Generator选项。
    我们需要给该模块取一个唯一的名字。因为我们在创建一个管理模块,我们可以命名为admin。
    (2)使用一个模块:
    在看到建立成功的消息后,我们需要在应用程序中设置modules属性,才可以使用它。在添加gii模块到应用程序的时候,我们使用过该方法来允许我们使用Gii代码生成工具。我们对主配置文件 : protected/config/main.php进行配置,如下的高亮代码需要被修改 :
    'modules'=>array( 
        'gii'=>array(
            'class'=>'system.gii.GiiModule', 
            'password'=>'iamadmin',
        ),
        'admin',
    ),
    保存以上改变后,我们的新admin模块已经可以使用了。我们可以先通过以下地址访问一下http://localhost/test/index.php/admin/default/index。(http://localhost/test/index.php?r=admin/default/index)
    (3)在模块中建立模型和CRUD脚手架
    进入gii页面,使用Model Generator来新建模型类,然后使用Crud Generator来完成对应脚手架操作。为模块建立模型时,在Model Path处需手动添加路径,例如:为admin模块添加模型,则此处application.modules.admin.models
    为模块添加Crud Generator时,Model Class:admin.models.SysMessage,Controller ID:admin/SysMessage
    这样就会告诉开发工具,我们的模型类是在admin模块下的,包括控制器类在内的其他相关文件也需要被生成在admin模块内
    (4)在应用程序级导入新模型类
    为了在应用程序中随时访问我们新创建的模型,我们应当将其配置为应用程序的一部分。修改 protected/config/main.php文件内容如下:
    'import'=>array(
        'application.models.*',
        'application.components.*',
        'application.modules.admin.models.*',
    ),
     
     18、性能调整技巧
     
    (1)启用APC
    启用PHP APC扩展可能是最简单的增进整个应用程序性能的方式。扩展的缓存和优化控制的PHP中间代码并且减少了每次请求时花费在PHP脚本分析上的时间。
    (2)禁用调试模式
    在本章的早些时候我们提到过这一概念,在这里再提一次也不为过。禁用调试模式是另外一个提高安全和性能的方式。如果位于主index.php脚本中的YII_DEBUG常量被定义为true,Yii应用程序将运行在调试模式下。在调试模式下,许多包括在框架内的组件,将导致额外的损耗。
    (3)使用yiilite.php
    当使用PHP APC扩展,一件可以做的事是使用Yii bootstrap(引导)文件yiilite.php代替yii.php。这可以很好的增加Yii应用程序的性能。yiilite.php文件包含在每一个yii发行版本中。它是一些常用Yii类文件合并的产物。因此使用yiilite.php可以减少文件的included量和trace语句。
    (4)使用缓存技术
    (5)启用schema缓存
    如果应用程序使用了Active Record,可以在生产环境中启用schema缓存来减少分析数据库schema的时间。可以通过设置CDbConnection::schemaCachingDuration属性的值大于0来实现。
    值得一提的是这些都是基于应用程序级的缓存技术,我们也可以使用服务器端缓存技术来提升应用程序的性能。上面提到的启用APC就是这个范畴的。还有一些其他的服务器端技术,例如:Zend Optimizer, eAccelerator, Squid,等。
     
    注:以上为学习《应用Yii1.1和PHP5进行敏捷Web开发》笔记。
     
    学习地址为:
     
     
  • 相关阅读:
    Ubuntu中root用户和user用户的相互切换
    MVCC
    vs2010和C#4.0
    使用命令选项连接到MySQL服务器(参考MySQL官方文档)
    使用外部数据源连接WIN版本的MySQL时,测试连接无法通过
    MySQL学习进阶路线
    解决linux(centos7)重新安装mysql systemctl start mysqld.service时报错
    最最完整的 MySQL 规范都在这了
    Linux性能测试与调优的15条常用命令
    (转载)libevent源码深度剖析二
  • 原文地址:https://www.cnblogs.com/imxiu/p/3418620.html
Copyright © 2011-2022 走看看