CakePHP manual的中文翻译(粗略翻译,学习笔记)

说明:
可以修改和发布,但是请保留原作者信息
author:Liuchen
Email:[email protected]  [email protected]
blog:  liuchen.cnblogs.com
Date: 2006-03-17
version 0.1

   

1,读者

这份手册是为了那些想快速建立web程序的人所写。CakePHP是为了帮助PHP各个层次用户简单快速的创建健壮、可维护的程序

这份手册需要一些PHPHTML的基础知识,对MVC编程模式的一些了解。

2,CakePHP是免费的

    遵循MIT License,主页http://www.cakephp.org

3,社区   

    更多信息http://www.cakephp.org

第一章 CakePHP介绍

1,什么是CakePHP

       CakePHP是一个开元的PHP的快速开发框架

2,为什么用CakePHP

CakePHP拥有一些快速开发的特征

1,兼容PHP4PHP5

2,提供整合的数据库交互CRUD和简单的查询(包括 scaffolding

3Request dispatcher(原文Request dispatcher with good looking, custom URLs

4,快速可变的模版(使用helpersPHP语法)

5,许多有用的核心特征(access control lists以及AJAX整合等等)

6,在任何网站子目录下面都正常工作,很少需要Apache的配置(原文Works from any website subdirectory, with little to no Apache configuration involved

3CakePHP的历史

    2005年,Michal TatarynowiczPHP写了一个快速开发的框架并发现这是一个好的框架的开始,于是Michal TatarynowiczMIT License下公布了这个框架并命名为Cake,并向开发者社区公布,后者现在维护项目并命名为CakePHP

 

第二章 基本概念

1 MVC模式

    为了更好的理解类似Cakeweb程序,你需要了解一些 Ruby on Rails这个框架,Cake的灵感就来自于Ruby on RailsRuby on Rails是编程语言Ruby的网站开发框架。它实现了Active RecordMVC模式。文章 What goes Where?详细解释了Rails的结构,Cake也使用了类似的结构。

    Model View ControllerGang of Four描述的一个软件的设计模式,Dean Helman介绍:“MVC模式,将一个项目,甚至是一个接口分成三个部分:modelviewcontroller。开发MVC是为了将传统的输入,处理,输出映射到GUI领域

 

Input -> Processing -> Output

Controller -> Model -> View

 

用户输入,外部世界的模型和显示用户的输出被model,view portcontroller objects所操作。controller将用户的鼠标、键盘操作解释并映射到对应的命令,然后发送给model或者view并影响相应的变化。model管理一个或若干数据元素,根据状态的查询、变化状态的操作做对应的响应。view port管理一个矩形的显示,并通过图形和文字的结合对给用户准备好的数据作出响应(注:我认为就是显示出来)

 

关于MVC,你可以通过这个文章了解更多的机制 MVC: Most vexing conundrum

 

2Cake的文件结构

    当你解压缩安装包,你会发现四个文件夹app, cake, tmp vendors.其中cake文件夹是cake的核心库,基本上你不需要进行修改除非你需要对Cake进行一些定制

    0.10.0 版本发布之前,CakePHP并不是这样的,老版本都是在一个统一的文件夹Cake下面,这种结构证明有一些问题 

    1,如果你有许多的web应用程序,你需要下载并安装Cake两次,这样核心库就重复了,这个是空间的一种浪费。并且违背了CakePHP试图遵循的DRY哲学原则

    2,当CakePHP新的版本发布时,你必须非常小心的以免你的app文件夹下面的程序被默认的程序覆盖

 

app文件夹是你的程序和文件所在的地方。核心库文件夹cake和程序文件夹app的愤慨使得你可以有许多的程序,但只需要一份cake库,并且使得升级CakePHP变得更加容易:你只需要下崽最新版本的Cake并把你当前的核心库cake文件夹覆盖掉,而不需要旦夕覆盖掉你的app文件夹

 

    tmp文件夹是用于存储cake操作的变量,比如bakingcachinglogging

    vendors文件夹用于存放第三方库文件,你需要在稍后更多的了解vendors

 

    下面的列表显示了主要的文件夹和他们的基本目的

cake(根目录)

app(存放你的程序)

    config(配置文件,比如ACLcore, database connectionroutes, paths, tags

    controllers(放置controllers)

        (components,帮助你使用controller的类)

    index.php(cake中有三个该文件,方便用户用不同的方法配置cake)

    models(放置models

    plugins(放置plugins或者第三方程序)

    viewsview相关文件)

        elements(一些重复使用的较小的layout item

        errors(错误文件)

        helpers(自定义的helpers文件)

        layouts(layout文件)

        pagesPagesController管理的静态内容)

    webroot(把这个目录设置成为网站根目录,并将public files放在这里)

        css

        files

        img

        js

cake(库文件:最好不要修改)

index.php

tmp(用来放置logs,baking)

vendors(粘贴第三方库文件)

 

第三章 安装CakePHP

1Requirements

    你必须有一个服务器,具备程序和库来运行CakePHP

1.1 服务器的要求   

    1.HTTP服务端(比如Apache),下面的选项要打开:sessions, mod_rewrite(虽然不是必须但是建议有)

    2.PH P 4.3.2 或者更高版本,CakePHPPHP45下都能很好工作

    3.数据库引擎(现在已经支持MySQLPostgreSQL and a wrapper for ADODB

 

2.安装CakePHP

2.1 得到最新的稳定版本

    www.cakephp.org 点击Downloads>Release

2.2 解压缩

    放置到根目录,解压缩,有两种安装方式,开发方式安装使得你可以容易的在一个域名下面察看许多CakePHP程序,产品安装方式使得一个域名下面只有一个程序

 

3. 建立CakePHP

    第一种方法在开发环境下比较合适,但是并不安全。第二种方法更安全可以安装在最终产品的环境下

3.1 开发方式安装

为了开发,我们可以将整个Cake的安装目录放到特殊的DocumentRoot下,如下:

/wwwroot/
    /cake
        /.htaccess
        /app/
        /cake/
        /index.php
        /tmp/
        /vendors

这种安装wwwroot当作整个网站的目录,所以你的URL如下显示

www.example.com/cake/index.php

如果你使用了mod_rewrite, 你的URLs会变成下面的这种形式

http://www.example.com/cake/controller_name/action_name/param1/param2 pattern

3.2 产品方式安装

为了实现产品方式的安装,你必须用于修改服务器上网站根目录的权限,修改根目录,使得整个域像只有一个CakePHP程序

安装后的程序结构如下

.. / path_to_cake_install /
    
/ .htaccess
    
/ app /
        
/ config /
        
/ conftrollers
        
/ index .php
        
/ models
        
/ plugins
        
/ views
        
/ webroot  < --  This should be your new DocumentRoot
     / cake /
    
/ index .php
    
/ tmp /
    
/ vendors

3.1 建议的httpd.conf

DocumentRoot  / path_to_cake / app / webroot

在这种配置下,webroot就当作了网站的根目录,你的URL就可能像下面这样

http: // www.example.com /

如果你使用了mod_rewrite,你的URL就会类似于下面的

http: // www.example.com / controller_name / action_name / param1 / param2 pattern

一些共享主机的用户可能没有权限通过修改http.conf来改变DocumnentRoot来指向他们的产品安装。在这种情况下,用户可以安装下面的方式,修改CakePHP的结构。Cake安装在 /path_to_cake_install,文件目录(不可以修改)指向/public_html

/ path_to_cake_install
    
/ app
    
/ cake
    
/ index .php
    
/ models
    
/ plugins
    
/ views
    
/ webroot
/ public_html ( =  contents  of   / app / webroot)
    
/ .htaccess
    
/ css    
    
/ css.php         
    
/ favicon.ico     
    
/ files           
    
/ img             
    
/ index .php       
    
/ js


实际上,你将Cake/app/webroot文件夹的内容拷贝到你已经存在的DocumentRoot。为了告诉Cake你的webroot文件在哪里,将下面几行田间到你DocumentRoot文件夹下面的index.php中(针对上面的例子就是/public_html/index.php

define('ROOT', BASE_DIR.'/path_to_cake_install');
define ('APP_DIR', 'app');
define ('WEBROOT_DIR', '/public_html');

4. 配置Apachemod_rewrite

       CakePHP没有mod_rewrite支持时候,我们发现许多用户由于不能完美运行他们的系统而苦恼。下面是一些可能需要尝试并且使之正确运行的事情:

     确定 .htaccessoverride是允许的:在你的httpd.conf中,你需要有一段代码,在你的服务器上每个目录。确定AllowOverride对当前的目录设置成为All

     确定你修改的是系统的httpd.conf,而不是用户或者特定站点的httpd.conf

     在某些情况下,你可能得到一份缺少 .htaccess文件的CakePHP,这可能是因为某些系统把 .开头的文件当作隐藏文件就不拷贝。确定你拷贝的文件来中包含.htaccess

     确定你正确上传mod_rewrite。你可以查看一下 httpd.conf中类似于LoadModule rewrite_module libexec/httpd/mod_rewrite.so AddModulemod_rewrite.c

 

5. 确定CakePHP正确工作

现在,我们实际查看一下。根据你选择不同的安装方式,你应该将你的浏览器的URL指向 http://www.example.com或者http://www.example.com/cake.这时,你会看到CakePHP的默认目录,以及一条数据库连接状态的消息。

恭喜!你现在已经可以创建你的第一个基于Cake的程序了。如果你现在什么都没有看到或者受到一条错误信息,可以到http://wiki.cakephp.org或者#cakephp on irc.freenode.net寻找更多的帮助。

 

第四章  配置

1. 数据库配置

    app/config/database.php文件是数据库配置文件。默认安装后并没有database.php文件,所以你需要拷贝database.php.defaultdatabase.php. 之后,你可以看到如下:

4.1

var $default = array('driver'   => 'mysql',
                     'connect'  => 'mysql_pconnect',
                     'host'     => 'localhost',
                     'login'    => 'user',
                     'password' => 'password',
                     'database' => 'project_name' );

根据你的数据库连接信息替换上面的配置

CakePHP支持下面的数据库驱动

 

mysql 
postgres 
sqlite 
pear-drivername (so you might enter pear-mysql, for example) 
adodb-drivername 

$default 连接中的connect key允许你设置是否需要持久连接数据库,请仔细阅读database.php.default文件中的注释,以配置你的数据库连接类型。

你的数据库中的表也应该遵循下面的命名规则:

     cake使用的表名(Table name)应该有英文的复数形式组成,比如users, authors, articles. 注意,对应的model是单数形式

     所有的表 都必须有一个主键叫做 id

     如果你需要关联tables,使用外键比如 article_id 。表的名字是单数,必须是小写,比如id

     另外,最好遵从下面的命名规则以便更方便的使用某些功能

Include a ‘created’

Include a ‘modified’

    你也可能注意到了database.php文件中有一个$test的连接,填上这个配置(或者添加其他类似的配置文件),在你使用的时候将下面的代码

添加到你的一个models

var $useDbConfig = 'test';

2. 全局配置

    CakePHP的全局配置可以在/app/config/core.php找到。尽管我们确实不喜欢配置文件,但是配置确实很难做。在这个文件中你可以修改一些,每一项设置都可以在core.php的注释中找到。

 

DEBUG: 设置这个变量不同的值可以帮助你在运行文件的时候debug你的程序。江这个值设成不同的非0值,可以使得Cake打印出SQL语句并且阻止程序下一步进行(原文:Specifiying this setting to a non-zero value will force Cake to print out SQL statements and stop flash messages from forwarding.)

CAKE_SESSION_COOKIE:在你的Cake应用中,这个变量可以设置成为保存用户sessioncookie名字

CAKE_SECURITY:这个变量不同的值达标不同的sessions检查等级。Cake创建新的session,删除旧的session都基于这个变量。下面是可能的值:

        high: session十分钟后失效

        medium: session 二十分钟后失效

        low: session 三十分钟后失效

CAKE_SESSION_SAVE: 设置如何保存session。下面是可能的值

        cake: 保存在tmp/目录下

        php: 根据php.ini中的设置保存

        database: 被保存到默认(现在还没有实现,以后继续完善)

 

3.路径设置

Routing是类似于mod_rewrite pared-down pure-PHP(机制),可以帮助将URL影射到 controller/action/params. Cake 添加这个可以帮助我们更好的实现URL转化并使得我们可以脱离mod_rewrite的要求。然而使用mod_rewrite,使得我们的address bar显得更加整洁。

    Routes是映射URLs到特定的controllersactions的独立规则。Routes被配置在app/config/routes.php文件中,设置形式如下:

4.2 Route Pattern

<?php
$Route->connect (
    'URL'
,  
    array('controller'
= >'controllername' ,  
    'action'
= >'actionname' ,  'firstparam')
)
;
?>

在这里

URLCakeURL你想要映射的(URL is the Cake URL you wish to map

controllername 是你想要调用的controller的名字

actionname 是你想要调用controlleraction的名字

firstparam是特定的action的第一个参数

 

下面的这个例子将/blog下面的所有URL连接到了BlogController. 默认的actionBlogController::index()

4.3 Route Example

 

 

<?php
$Route->connect ('/blog/:action/*'
,  array('controller' = >'Blog' ,  'action' = >'index')) ;
?>

一个URL 比如 /blog/history/05/june 处理如下:  

4.4 Route Handing in a Controller

<?php
class BlogController extends AppController
{
function history ($year
,  $month = null)
     {
           //..display appropriate content
     }
}
?>

URL中的’history’被匹配到 Blog route中的:action.( The 'history' from the URL was matched by :action from the Blog's route.) URL中被*匹配的元素被传递到活动的controller的处理方法,这里是$year$month。比如这个URL /blog/history/05, 仅仅传递一个参数05history()

    接下来的例子是默认的CakePHP route,指向 PagesController::display(‘home’).其中home是一个view,位于/app/views/pages/home.thtml

 

4.5 Setting the Default Route

<?php
$Route->connect ('/*'
,  array('controller' = >'Pages' ,  'action' = >'display' ,  'home')) ;
?>

第五章 Scaffolding (脚手架?)

Scaffolding是一个很棒的途径,使得早期开发的部分web应用能够运行起来。早期的数据库模式是不稳定的,很容易变化。Scaffolding有个下降趋势:web程序员憎恨创建以后可能根本用不到的forms。为了减少程序员的这种重复劳动, Cake中包含了ScaffoldingScaffolding分析数据库,创建一些标准的使用adddelete、和edit按钮的lists,创建输入的forms,以及查看数据库中一个item的标准views。为了在程序中的controller中添加Scaffolding,需要添加$scaffold变量:

 

class CategoriesController extends AppController
{
    var $scaffold
;
}

有关Scaffold,要注意一个重要的问题: Scaffold期望每个以_id结尾的filed name是一个外键并且指向一个tabletable的名称和_id前方的一样(只不过是小写的)。所以,举个例子来说,如果你嵌套了分类,你最好有个列叫做parent_id。在这个版本中,最好能够命名为parentid.同样,在表中有一个外键(比如,titles table有个category_id,并且你已经合适的联结到models(查看6.2理解联结),在show/edit/newdviews中,选择的表将会和外键的表(category)一起自动的表现出来(原文:a select box will be automatically populated with the rows from the foreign table (category) in the show/edit/new views.)。在foreign model中设置$displayField来决定foreign中哪些field会被显示。继续我们的例子,category有个标题
class Title extends AppModel 
{
    var $displayField 
=  'title' ;
}

第六章 Models

本章内容:

1. Model Function

       1.1 用户定义的Function

       1.2 检索(retrieving)你的数据

       1.3 保存你的数据

       1.4 Model的回调(callbacks

2. Model的变量

3. Associations

 

Model是什么,它是MVC模式中的M

Model做些什么。它使得domain logicpresentation分隔开,独立application logic(It separates domain logic from the presentation, isolating application logic.)

      

       一个Model概要的说就是一个指向数据库的access,更具体,就是数据库中的特定的table。默认的,每个model都使用自身名字复数形式的table,比如,User Mode使用 users

tableModels可以维护数据特定的规则,联结信息以及它使用的table的方法。

 

 

1. Model的方法

       PHP的观点看,models都是从AppModel类继承来的类。类AppModel原始是定义在 /cake目录下。你也可以创建自己的放在 app/app_model.php.这个文件应该包含一些可供多个models共享的方法。AppModel本身也是从Model类继承而来的,Model类是一个标准的Cake库,定义在 libs/model.php

       注意

       虽然本节介绍的是Model中常用的方法,然而记住:更详细的参考请到http://api.cakephp.org

 

1.1 用户定义的方法

       下面是model中一个特定table的例子,该例子实现了在blog中显示和隐藏两种方法

6.1  Example Model Functions

<?php
class Post extends AppModel
{
   function hide ($id
= null)
   {
      if ($id) $this->setId($id)
;
      $this->set('hidden' ,  ' 1 ') ;
      $this->save() ;
   }
 
   function unhide ($id
= null)
   {
      if ($id) $this->setId($id)
;
      $this->set('hidden' ,  ' 0 ') ;
      $this->save() ;
   }
}
?>

1.2 检索数据

下面是使用model得到数据的一些标准方法

findAll($conditions,$fields,$order,$limit,$page,$recursive)

○返回特定的fieldsfields$limit(默认是50)个记录,匹配$conditions(如果有),从第$page(默认1)页开始列表,$conditions内容应该像SQL语句中的一样,比如:$conditions=”race = ‘wookie’ AND thermal_detonators> 3”

○当$recursive选项设置成13的整数,findAll()将会试图返回在联结到该model中发现的所有项的models.这项递归寻找可以深入3层。

find($conditions, $fields, $order, $recursive)

    ○返回匹配$conditions的第一条记录的制定的fields(如果没有指定则返回全部)

    $recursive作用同上

findAllBy<FieldName>($value) and findBy<FieldName>($value)

○这些奇妙的方法可以用于指定特定的field和特定的value快速查找行,你要做的就是把你的field用驼峰表达法添加在后面。举个例子(用于controller中)

$this->Post->findByTitle('My First Blog Post') ;
$this->Author->findByLastName('Rogers') ;
$this->Property->findAllByState('AZ') ;
$this->Specimen->findAllByKingdom('Animalia') ;

返回的结果是一个数组,和find()以及findAll()返回的结果是一个形式

field($name,$conditions,$order)

○根据$order排序,根据条件$conditions,将第一条记录中的field值,作为string返回

findCount($conditions)

    ○返回匹配$conditions的记录的个数

generateList

($conditions=null,$order=null,$limit=null,$keyPath=null,$valuePath=null)

    ○根据modelslists,得到一系列key的值,特别是根据model list创建<select>list$conditions, $order, $limit参数使用方法和上面相同。$keyPath$valuePath是你告诉model那里去找keysvalues来成list。举个例子,基于Role model,你想生成一个由ids(类型integer)当作key,由roles当作valuelist,这个方法调用形式如下:

$this->set(
    'Roles'
,
    $this->Role->generateList(null
,  'role_name ASC' ,  null ,  'id' ,  'role_name')
)
;

//This would return something like:
array(
    '
1 = > 'Account Manager' ,
    '
2 = > 'Account Viewer' ,
    '
3 = > 'System Manager' ,
    '
4 = > 'Site Visitor'
)
;

read($fields=null, $id=null)

    ○使用这个方法从当前装载的记录或者由$id指定的记录中得到fields和值

 

 

    特定的Sql调用可以使用modelfindBySql()方法。举例,在blog应用中,我想存储一个发贴者的first name到一个table中,但是这个table并不是我的cake schema中的一部分。我就可以通过这个model中的一个特定的方法

 

6.2 Custom Sql Calls With findBySql()

<?php
class Post extends AppModel
{
        function posterFirstName()
        {
          $ret 
=  $this->findBySql( " SELECT first_name FROM posters_table 
                                   WHERE poster_id = 1
" ) ;
          $firstName  =  $ret [ 0 ][ 'first_name' ] ;
          return $firstName ;
        }
}
?>

当然也有query()方法,如果执行成功返回true,失败返回false。因为query语句并不是都返回结果集。比如“DELETE FROM problems WHERE solved = true

 

1.3 保存数据

    为了保存你的数据到model中,你应该向model提供你想要保存的数据。这些数据提交给save()方法应该以下面的形式保存

Array
(
    
[ modelname ]   = > Array
        (
            
[ fieldname1 ]   = > value
            
[ fieldname2 ]   = > value
        )
)

   

form表单提交(post方法)的数据会自动排列成这种形式,并且放置到controller中的$this->params[‘data’],因此,通过webform表单保存数据非常简单。一个controller的编辑方法可能会像下面这样显示:


function edit($id) 
{
   //Note: The property model is automatically loaded for us at $this->property.     
   // Check to see if we have form data 
   if (isset($this->params
[ 'form' ][ 'data' ][ 'property' ] )) 
   {  
      // Here's where we try to save our data
      if ($this->property->save($this->params
[ 'data' ] )) 
      {
         //Show the user that her data has been saved
         $this->flash('Your information has been saved.'
,             
 '/properties/edit/'.$this->params
[ 'data' ][ 'property' ][ 'id' ] ,   2 ) ;
         exit() ;
      }
      else
      {
         //If the data couldn't be validated
,  show the validation errors
         //and repopulate form fields with submitted data
         $this->set('form'
,  $this->params [ 'data' ] ) ;
         $this->validateErrors($this->property) ;
         $this->render() ;
      }      
   }   
   //If no form data was submitted
,  just render the edit view
   $this->render()
;
}

注意save操作是如何放置在一个条件语句中:如果你试图保存数据到model中,cake自动尝试确数据正确(根据你提供的规则)。可以查看第十章了解更多关于正确规则(validation.如果不想查看正确性直接保存数据,使用save($data,false);

 

    其他有用的保存方法:

savaFieldId($name,$value)

    ○保存一个单field的值

getLastInsertID()

○返回最近创建记录的ID

 

14 ModelCallbacks

    在我们接近0.10.x最终版的时候,我们添加了一些model的回调函数,允许用户能够逻辑上悄悄的在model操作前或操作后执行。为了在应用中获得这种方法,在model中使用提供的参数,重载下面的这些方法

beforeFind$conditions

○这个回调函数在一个查询操作开始之前执行。将查询前的操作逻辑放到这个方法里面。当你在model中重写(override)这个方法时,当你想要find操作执行时候返回true,当你想要执行中止时候返回false

afterFind$results

○使用这个回调函数可以修改从find操作中返回的结果,或者实现其他任何的find后逻辑。这个函数的参数是modelfind操作的结果,返回的是修改后的结果。

beforeSave()

○在这个函数中放置任何保存前的逻辑。如果你像保存操作执行则返回true,否则返回false

afterSave()

    ○放置任何你想要在保存后执行的代码在这个回调函数中

beforeDelete()

    ○放置删除前的逻辑代码。想要删除操作执行则返回true,否则返回false

afterDelete()

    ○放置任何你想要在删除后执行的代码在这个回调函数中

 

2 Model 变量

    当你创建你的models时候,你可以设置一些特殊的变量,来获得对Cake函数的使用。

$primaryKey

○如果这个model关联到一个数据库的table,而且数据库的主键并不是id,那么使用这个变量来告诉Cake主键的名字

$transactional

○告诉Cakemodel是否支持传输(举例 begin/commit/rolback,设置为boolea值。

$useTable

○如果你想使用的数据库的table并不是model名的复数形式,而且你也不想改变table名,设置这个变量为table

$validate

    ○确认传递给model的数据是否正确的一个数组。查看第十章

$useDbConfig

○还记得数据库设置中,你可以在/app/config/database.php文件中设置么?使用这个变量可以交换他们――仅仅使用数据库链接变量的名称你在database 配置文件中创建的。

 

3.联结(Associations

链接是两个逻辑相关单元之间的关联。CakePHP中有四种类型的联结

hasOne

hasMany

belongsTo

hasAndBelongsToMany

因为他们比较容易混淆,所以最好举例来解释联结。

我们假设你有很多的书,有一天你坐在自己很大的图书馆里面,你突然觉得你应该将所有的书分下类。每一本书,你认为在分类里要有以下属性

Title

Author or Authors

Short Description

Categories   

    现在我们使用上面的例子来分别单独来看每种类型的关联

hasOne关联类型确定了这样一种情况:一个逻辑单元有一个且仅有一个其他的X类型的逻辑单元和它关联。在我们的分类例子中,每一本书都有且仅有一个title

    hasMany关联类型确定了这样一种情况:一个逻辑单元有许多X类型的逻辑单元和它关联。在我们的分类例子中,每一本书可能有许多个不同的作者。

    belongsTo关联类型是hasOnehasMany关系的兄弟。一个逻辑断员属于另一个X类型的逻辑单元。一个作者属于一本书。注意到这个关系并不能确定这本书仅有一个还是有多个作者。从belongsTo关联你仅仅能得到的就是该作者属于这本书。查看这本书是否还所有其他作者,你必须使用这本书的关联关系,查看这本书是否有hasOnehasMany关联到某些作者。

    最后的关联hasAndBelongsToMany确定了这样一种情况:一个逻辑单元包含(has)许多其他的X类型的逻辑单元,这些X类型逻辑单元本身又有许多相互作用的单元。这个关联可能是最复杂的关联,但是我们也可以使用上面使用的分类例子来帮助我们更好的理解。

    你可以根据下面的分类来归类每一本书

●科幻小说(Science Fiction)Liuchen注:我们coder应该多看的书籍)

●传记

●幻想(Fantasy,不知道如何确切翻译)

●历史

    现在假设你有一本Alan TuringLiuchen注,还是不翻译成中文好,大家都知道是谁)的传记,这本书将属于(belong to)传记和历史两个分类,所以你可能认为这是hasMany关联,每一本书有许多的分类。但是,下一本书是空间编程(space program)的历史介绍,所以这本书也可以属于历史分类。这样就破坏了hasMany的规则,每一本书都可以有许多的分类,而且每个分类都可以属于多本书。这个就是hasAndBelongsToMany关联

    CakePHP中这些关联需要做些什么呢?Cake可以控制许多在传统编程中各种错综复杂的关系,仅仅需要再controller中的一行代码。(原文:Cake can handle much of the blood, sweat, and tears that traditionally go into programming association with just a line of code in the controller.我们创建一个table叫做books,每一本书都是table中的一个实体或记录,如下

Title

Author(s)

Description

Categories

 

 

 

 


开始,我们按照history of space exploration来归类,进展顺利。接着是Mr. Truing的历史自传这本书,我们遇到了麻烦。category只有一列,但是这本书却属于两个categories. 你也许认为这有两种解决方法

●将类别放到categories列,并使用逗号隔开,比如

    history, biography

    问题是如何选择,不久也许我们要通过categories列来找所有历史方面的书,但是你不能在SQL语句使用category=’history, biography’来代替 category=’history’ ,所以这不是一个好的解决办法

●为每个分类将一个实体放在table,如下面的形式:


 

<? php
/* *
* @var mixed $belongsTo this can be a string or an array.
*
* Example below is using an array and setting more than one belongsTo.
*
* Using $belongsTo as an array gives you more control over the association
*
* association  - Table holding the association
* className    - Specify the class name of the association.
*                   Use it only if that name can not be inferred from the association
*                   name.
*                     So
*                       [code]
*                         var $belongsTo = array(array('Author'));
*                       [/code]
*                     will by default be linked to the Author class, but if the real 
*                     class name is Person, you will have to specify it with this 
*                     option. 
* conditions   - Specify the conditions that the associated object must meet in order
*                  to be included as a "WHERE" SQL fragment, such as "authorized = 1".
* order        - Specify the order from which the associated object will be picked at 
*                   the top. Specified as an "ORDER BY" SQL fragment, such as 
*                   "last_name, first_name DESC"
* foreignKey   - Specify the foreign key used for the association.
*                  By default this is guessed to be the name of the associated class 
*                  in lower-case and "_id" suffixed. So a Person class that makes a 
*                  belongsTo association to a Boss class will use "boss_id" as the 
*                  default foreign_key.
* counterCache - Caches the number of belonging objects on the associate class 
*                  through use of increment_counter and decrement_counter. The 
*                  counter cache is incremented when an object of this class is 
*                  created and decremented when it is destroyed. This requires that a
*                  column named "#{table_name}_count" (such as comments_count for a 
*                  belonging Comment class) is used on the associated class (such as 
*                  a Post class).
*
* Setting $belongsTo to a string limits you a lot.
* To use $belongsTo as a string like this:
* [code]
* var $belongsTo = 'Association';
* [/code]
*
* You can also set more than one association by separating them with a comma
* [code]
* var $belongsTo = 'Association,Association2,Association3';
* [/code]
*/
 
var   $belongsTo             =   array ( ' Association1 '   =>
                       
array ( ' className '      =>   ' ClassName ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by DESC ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' counterCache '   =>   ' table name _count '  ) ,
                                    
                             
' Association2 '   =>
                       
array ( ' className '      =>   ' ClassName ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' counterCache '   =>   ' table name _count '  ) ,
                                    
                             
' Association3 '   =>
                       
array ( ' className '      =>   ' ClassName ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' counterCache '   =>   ' table name _count '  ));
                                   
                                   
/* *
* @var mixed $hasOne this can be a string or an array.
*
* Example below is using an array and setting more than one hasOne.
*
* Using $hasOne as an array gives you more control over the association
*
* association  - Table holding the association
* className    - Specify the class name of the association.
*                  Use it only if that name can not be inferred from the association 
*                  name.
*                     So
*                       [code]
*                         var $hasOne = array(array('Manager'));
*                       [/code]
*                  will by default be linked to the Manager class, but if the real 
*                  class name is Person, you will have to specify it with this option.
* conditions   - Specify the conditions that the associated object must meet in order
*                  to be included as a "WHERE" sql fragment, such as "authorized = 1".
* order        - Specify the order from which the associated object will be picked at
                   the top. Specified as an "ORDER BY" sql fragment, such as 
                   "last_name, first_name DESC"
* dependent    - If set to true, the associated object is destroyed when this object 
                   is. It is also destroyed if another association is assigned.
* foreignKey   - Specify the foreign key used for the association.
*                  By default this is guessed to be the name of the associated class 
                   in lower-case and "_id" suffixed. So a Person class that makes a 
                   belongsTo association to a Boss class will use "boss_id" as the 
                   default foreign_key.
*
* Setting $belongsTo to a string limits you a lot.
* To use $hasOne as a string like this:
* [code]
* var $hasOne  = 'association';
* [/code]
*
* You can also set more than one association by separating them with a comma
* [code]
* var $hasOne = 'Association,Association2,Association3';
* [/code]
*/
var   $hasOne                =   array ( ' association1 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by ' ,
                             
' dependent '      =>    true ,
                             
' foreignKey '     =>   ' foreign key ' ) ,
                                    
                             
' association2 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by ' ,
                             
' dependent '      =>    true ,
                             
' foreignKey '     =>   ' foreign key ' ) ,
                                    
                             
' association3 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' this order by ' ,
                             
' dependent '      =>    true ,
                             
' foreignKey '     =>   ' foreign key ' ));
                                           
                                    
/* *
* @var mixed $hasMany this can be a string or an array.
*
* Example below is using an array and setting more than one hasMany.
*
* Using hasMany as an array gives you more control over the association
*
* association - Table holding the association
* className   - Specify the class name of the association.
*                  Use it only if that name can not be inferred from the association 
                   name.
*                     So
*                       [code]
*                         var $hasMany = array(array('products'));
*                       [/code]
*                  will by default be linked to the Product class, but if the real 
                   class name is SpecialProduct, you'll have to specify it with this 
                   option.
* conditions  - Specify the conditions that the associated objects must meet in order
                 to be included as a "WHERE" sql fragment, such as "price > 5 AND 
                 name LIKE 'B%'".
* order       - Specify the order in which the associated objects are returned as a 
                  "ORDER BY" sql fragment, such as "last_name, first_name DESC"
* foreignKey  - Specify the foreign key used for the association.
*                 By default this is guessed to be the name of this class in 
                  lower-case and "_id" suffixed. So a Person class that makes a 
                  has_many association will use "person_id" as the default 
                  foreign_key.
* dependent   - If set to true all the associated object are destroyed alongside 
                  this object. May not be set if exclusive is also set.
* exclusive   - If set to true all the associated object are deleted in one SQL 
                  statement without having their beforeBestroy callback run. This 
                  should only be used on associations that depend solely on this 
                  class and don not need to do any clean-up in beforeDestroy. The 
                  upside is that it's much faster, especially if there's a 
                  counterCache involved. May not be set if dependent is also set.
* finderSql   - Specify a complete SQL statement to fetch the association.
*                 This is a good way to go for complex associations that depends 
                  on multiple tables. Note: When this option is used, 
                  findInCollection is not used.
* counterSql  - Specify a complete SQL statement to fetch the size of the association.
*                 If finderSql is specified but counterSql, counterSql will be 
                  generated by replacing SELECT * FROM with SELECT COUNT(*) FROM.
*
*
* Setting $hasMany to a sting limits you alot.
* To use $hasMany as a string like this:
* [code]
* var $hasMany  = 'association';
* [/code]
*
* You can also set more than one association in the string by seperating them with a comma
* [code]
* var $hasMany = 'association,association2,association3';
* [/code]
*/                                     
var   $hasMany               =   array ( ' association1 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' order by ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' dependent '      =>    true ,
                             
' exclusive '      =>    false ,
                             
' finderSql '      =>   ' custom SQL ' ,
                             
' counterSql '     =>   ' custom SQL ' ) ,
                                   
                             
' association2 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' order by ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' dependent '      =>    false ,
 
                             
' exclusive '      =>    true ,
                             
' finderSql '      =>   ' custom SQL ' ,
                             
' counterSql '     =>   ' custom SQL ' ) ,
                                      
                             
' association3 '   =>
                       
array ( ' className '      =>   ' class ' ,
                             
' conditions '     =>   ' these conditions ' ,
                             
' order '          =>   ' order by ' ,
                             
' foreignKey '     =>   ' foreign key ' ,
                             
' dependent '      =>    true ,
                             
' exclusive '      =>    false ,
                             
' finderSql '      =>   ' custom SQL ' ,
                             
' counterSql '     =>   ' custom SQL ' ));                                
                                    
/* *
* @var mixed $hasAndBelongsToMany this can be a string or an array.
*
* Example below is using an array and setting more than one hasAndBelongsToMany.
*
* Using hasAndBelongsToMany as an array gives you more control over the association
*
* association - Table holding the association
* className - Specify the class name of the association.
*                Use it only if that name can not be inferred from the association 
                 name.
*                   So
*                       [code]
*                         var $hasAndBelongsToMany = array(array('projects'));
*                       [/code]
*                    will by default be linked to the Project class, but if the real 
                     class name is SuperProject, you will have to specify it with 
                     this option.
* joinTable - Specify the name of the join table if the default based on lexical 
                order is not what you want. WARNING: If you're overwriting the table 
                name of either class, the tableName method MUST be declared 
                underneath any hasAndBelongsToMany declaration in order to work.
* foreignKey - Specify the foreign key used for the association.
*                By default this is guessed to be the name of this class in 
                 lower-case and "_id" suffixed. So a Person class that makes a 
                 has_and_belongs_to_many association will use "person_id" as the 
                 default foreign_key.
* associationForeignKey - Specify the association foreign key used for the 
                 association. By default this is guessed to be the name of the 
                 associated class in lower-case and "_id" suffixed. So the associated
                 class is Project that makes a hasAndBelongsToMany association will 
                 use "project_id" as the default association foreignKey. 
* conditions - Specify the conditions that the associated object must meet in order 
                 to be included as a "WHERE" SQL fragment, such as "authorized = 1".
* order - Specify the order in which the associated objects are returned as an "ORDER
                 BY" SQL fragment, such as "last_name, first_name DESC"
* uniq - If set to true, duplicate associated objects will be ignored by accessors 
                 and query methods
* finderSql - Overwrite the default generated SQL used to fetch the association 
                 with a custom one
* deleteSql - Overwrite the default generated SQL used to remove links between the 
                 associated classes with a custom one
* insertSql - Overwrite the default generated SQL used to add links between the 
                 associated classes with a custom one
*
*
* Setting $hasAndBelongsToMany to a string limits you a lot.
* To use $hasAndBelongsToMany as a string like this:
* [code]
* var $hasAndBelongsToMany  = 'Association';
* [/code]
*
* You can also set more than one association, by separating them with a comma:
* [code]
* var $hasAndBelongsToMany = 'Association,Association2,Association3';
* [/code]
*/                         
var   $hasAndBelongsToMany   =   array ( ' Association1 '            =>
                       
array ( ' className '               =>   ' ClassNameInCamelCase ' ,
                             
' joinTable '               =>   ' table to join on ' ,
                             
' foreignKey '              =>   ' foreign key ' ,
                             
' associationForeignKey '   =>   ' foreign key ' ,
                             
' conditions '              =>   ' these conditions ' ,
                             
' order '                   =>   ' ORDER BY ' ,
                             
' uniq '                    =>    true ,
                             
' finderQuery '             =>   ' custom SQL ' ,
                             
' deleteQuery '             =>   ' custom SQL ' ,
                             
' insertQuery '             =>   ' custom SQL ' ) ,
 
                             
' association2 '    =>
                       
array ( ' className '               =>   ' class ' ,
                             
' joinTable '               =>   ' table to join on ' ,
                             
' foreignKey '              =>   ' foreign key ' ,
                             
' associationForeignKey '   =>   ' foreign key ' ,
                             
' conditions '              =>   ' these conditions ' ,
                             
' order '                   =>   ' ORDER BY ' ,
                             
' uniq '                    =>    true ,
                             
' finderQuery '             =>   ' custom SQL ' ,
                             
' deleteQuery '             =>   ' custom SQL ' ,
                             
' insertQuery '             =>   ' custom SQL ' ) ,
 
                             
' association3 '            =>
                       
array ( ' className '               =>   ' class ' ,
                             
' joinTable '               =>   ' table to join on ' ,
                             
' foreignKey '              =>   ' foreign key ' ,
                             
' associationForeignKey '   =>   ' foreign key ' ,
                             
' conditions '              =>   ' these conditions ' ,
                             
' order '                   =>   ' ORDER BY ' ,
                             
' uniq '                    =>    true ,
                             
' finderQuery '             =>   ' custom SQL ' ,
                             
' deleteQuery '             =>   ' custom SQL ' ,
                             
' insertQuery '             =>   ' custom SQL ' ));
?>


第七章 Controllers

1.Controller 方法

       1.1 和你的Views交互

       1.2 使用Redirection

       1.3 Controller的回调函数

       1.4 其他有用的方法

2. Controller的变量

       一个Controller是用来管理你应用某个方面的逻辑。大多数来说,controllers用来管理一个model的逻辑。比如,你正在建设一个站点来管理一个videocollection,你可能有一个VideoController以及一个RentalControlle来管理你的视频和租金。分别的,cake中每个controller的名字通常是复数。

程序的Controllers都是从AppController类继承来的类,AppController又是从核心的类Controller继承来的。Controller类可以包含任意数量的action:各种显示Views的方法

AppController类可以在/app/app_controller.php中第一,它里面包含了许多可以被更多controllers共享的方法,它本身是从核心类Controller继承来的。

一个Actioncontroller中的一个单独的方法,这个方法可以被Dispatcher自动的运行,运行的根据是从routes配置解析的页面请求。回到我们的 video collection的例子,VideoController类可以包含actions比如view(), rent(), search()等等,这个controller可以在/app/controllers/video_controller.php找到,并且文件内容为:

class  VideosController  extends  AppController
{
    
function  view( $id )
    {
        
// action logic goes here..
    }
    
function  rent( $customer_id ,   $video_id )
    {
        
// action logic goes here..
    }
    
function  search( $query )
    {
        
// action logic goes here..
    }
}

你可以通过使用下面的URLs来调用这些方法:

http : // www.example.com/videos/view/253
http : // www.example.com/videos/rent/5124/0-235253
http : // www.example.com/videos/search/hudsucker+proxy


但是这些页面将如何显示?你需要为每个action定义一个view,你可以在下一章查看具体内容。但是本章中,你会掌握Cakecontroller,并且能够更好的使用。具体的说,你将学到如何用controller将你的数据传递给view,使用户转向以及其他更多功能。

 

1. Controller Functions

    重要: 

    尽管本章中介绍了许多Cake中常用的方法,更多的手册内容请参考http://api.cake.org

 

1.1 views交互

set($var,$value)

     ○这个方法是将controller中的数据传递给view的主要方法。你可以使用这个方法控制任何值:single values, 整个数组等等。一旦你使用了set(),view中也可以使用这个变量:在controller中使用set(‘color’,’blue’)可以使得$color变量在view中使用

validate()

    ○通过收集错误的保存,返回错误的个数

validateErrors()

○根据model中第一的正确性规则,检查一个model的数据是否正确,更多信息参考第十章

render($action=null, $layout=null, $file=null)

○你并非时刻需要这个方法,因为在每个controller方法的最后,render都被自动调用,并且调用后定义(或者使用)相应的view

 

1.2 使用转向

redirect($url)

    ○使用这个方法告诉用户将跳转到哪里。这里的URL可以使Cake规则的URL或者使一个完整定义的URL(http://...)

flash($message, $url, $pause=1)

○这个方法在你的flash layoutapp/views/layouts/flash.thtml)中显示$message信息$pause秒钟,之后跳转到指定的URL

 

1.3 Controller的回调函数

    Cake Controller定义了一系列回调函数,你可以使用他们在重要的controller function之前或者之后插入功能逻辑。实现这些功能,适用下面介绍的参数和返回值声明这些方法

beforeFilter()

○在每个controller action之前调用,非常有用的地方去检查sessions是否有效,并检查相应的权限

afterFilter()

    ○在每个controlleraction之后调用

beforeRender()

    ○在controller逻辑之后,view显示之前调用

 

1.4 其他有用的方法

尽管这些方法是在CakeObject类中,他们在Controller中也可以使用

requestAction($url, $extra=array())

○这个方法根据任何地方(location)调用controlleraction,然后返回已经显示的view.$urlCake规范的URL(/controllername/actionname/params),如果$extra数组包含了一个键‘render,controller action将自动设置AutoRender

log($msg, $type = LOG_ERROR)

○你可以使用这个方法在你的程序应中记录发生的任何事件。记录文件Logs放在/tmp文件目录下

 

2. Controller的变量

    数量使用controller中定义的变量可以使你更好的使用cake的某些附加功能

$name

PHP4 并不能以驼峰表示法将当前类的名称提供给我们。如果你遇到问题,使用这个变量将你的类名设置成正确的驼峰表示法

$uses

○你的controller是否使用了很多的model?比如你的Fragglescontroller会自动调用$this->fraggle,但是你也想同时能够调用$this->smurf,那就将下面的语句加入到你的controller

var   $uses   =   array ( ' Fraggle ' , ' Smurf ' );

$helpers

○使用这个变量使得你的controller装在helpers到它的views. 这个HTML helper会自动装载,但是你可以使用这个变量来指定其他的

var   $helpers   =   array ( ' html ' , ' ajax ' , ' javascript ' );


$layout

○将这个变量设置成为你在这个controller中想使用的layout

$autoRender

    ○将这个变量设置成为false将会使得actions停止自动显示(rendering

beforeFilter

○如果你需要在某一个或者任何一个action调用之前都要运行一小段代码,使用$beforefilter.这个函数处理access control十分有用,你可以在任何action处理之前检查用户的权限。你需要做的就是将这个变量设置成为一个数组,数组中包含了你想运行的controlleraction,如下所示

class  ProductsController  extends  AppController
{
    
var   $beforeFilter   =   array ( ' checkAccess ' );
    
function  checkAccess()
    {
        
// Logic to check user identity and access would go here.
    }
    
function  index()
    {
        
// When this action is called, checkAccess() is called first.
    }
}

$components

    ○和$helpers$uses类似,这个变量用来装载你需要的components
var   $components   =   array ( ' acl ' );

第八章 Views

1.Views

       一个View就是一个页面的模版,经常以action的名字来命名。举例来说,Postscontroller::add()方法的view存放在/app/views/posts/add.thtmlCakeviews文件都是简单的PHP文件,所以你可以在里面使用任何PHP代码,几乎所有的view文件都包含HTML,一个view可以使特定数据集的任何体现,包括XML,图片等等

       view的模版文件中,你可以从对应的Model中使用数据,这个数据以数组$data的形式传递过来,你在controller中使用set()传递过来的任何数据在view中都可以使用

 

              注意

       HTML helper默认情况下在任何一个view都是可用的。而且是views中使用最多的。它创建forms包括scriptsmedia、链接以及数据正确性检查中都非常有用。参考第九章第1.1节可以了解HTML helper更多的内容

 

       views中许多可用的发放都是Helpers提供的。Cake提供了很多的helpers(参考第九章),你也可以引用自己定义的。因为views不应该包含过多的逻辑,所以views类中并没有很多public的方法。其中一个有用的方法就是renderElement(),这个方法我们在1.2节中讨论

 

1.1 Layouts

       一个布局(layout)包括了围绕view的所有代码。你想在view中见到的所有东西都应该被放在你的layout中。       布局文件位于/app/views/layouts

Cake的默认layout可以在/app/views/layouts/default.thtml被新的默认layout重写。一旦一个新的默认layout创建,controller view的代码将在页面被显示的时候替换到默认的layout

当你常见一个layout的时候,你需要告诉Cake你的controller view的代码位置:为了

达到这个目的,一定要确保layout包含$content_for_layout($title_for_layout更好)下面是一 个默认的layout的例子

<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > <? php echo $title_for_layout ?> </ title >
< link  rel ="shortcut icon"  href ="favicon.ico"  type ="image/x-icon" >
< body >
<!--  IF you'd like some sort of menu to show up on all of your views, include it here  -->
< div  id ="header" >
    
< div  id ="menu" > </ div >
</ div >
<!--  Here's where I want my views to be displayed  -->
<? php echo $content_for_layout  ?>
<!--  Add a footer to each displayed page  -->
< div  id ="footer" > </ div >
</ body >
</ html >



      
你可以为你的cake站点创建任意多的layout,你所要做的就是把他们放到app/views/layouts这个目录下,并在使用controller actions的时候使用controllers$layout

变量或者是setLayout()方法

       举例来说,如果站点的一部分需要包含一个小的广告banner空间。可以创建一个新的带有小的广告空间的layout,并将这个layout设置成为controller actions将要使用的layout.方法如下:

var   $layout   =   ' default_small_ad ' ;

1.2 Elements

       很多应用都有一些很多页面都会重复的代码段,有时候在layout中的位置不相同。Cake可以帮助你重现这些需要复用的部分。这些复用的部分叫做元素(Elements)。广告,帮助框,导航控制条,额外的菜单,插图编号在cake中就被实现为元素。一个元素就是其他views可以引用的小型viewa mini-view

       元素位于 /app/views/elements文件夹,并且都有.thtml的文件扩展名

8.1 Calling an Element without parameters

<? php  echo   $this -> renderElement( ' helpbox ' );  ?>

8.2 Calling an Element passing a data array

<? php  echo  
$this -> renderElement( ' helpbox ' ,   array ( " helptext "   =>   " Oh, this text is very helpful. " ));
?>

在一个元素文件中,所有传递的变量名称都是以通过传递过来数组的keys名获得(和controller中的set()views中起到的作用很类似)。上面举的这个例子中 /app/views/elements/helpbox.thtml文件就会使用$helptext变量。当然,传递一个数组到元素文件会更有用的多。

       使用元素可以使得view更易读,同时可以在一个文件中重复使用元素。他们也可以帮助你在网站建设中复用部分内容。

第九章 Helpers

Helpers设计的目的是提供一些方法,views通过使用这些方法能够更好的规范和显示数据。

1.1 HTML

1.1.1 介绍

       HTML helperCake里快速开发,减少单调工作的一种途径。HTML helper有两个目的:为在HTML代码插入经常使用的代码提供帮助,为快速创建web form标单提供帮助。下面的这一节将会着重介绍这些方法,更多内容请参考http://api.cakephp.org

       HTML helper中许多方法都使用的HTML tag都是定义在 tags.ini.phpCake的核心库中包含了一个tags.ini.php,但是如果你想做些改动,请在/app/conifg下面创建一份/cake/config/tags.ini.php. HTML helper将会使用这个文件中的tag定义来生成你需要的tags。使用HTML helper来创建自己的view代码将会非常有用,因为tags.ini.php文件中的改动将会在整个站点上都有显示。

       另外,如果核心库文件(/app/config/core.php)AUTO_OUTPUT被设置成truehepler将会自动输出这些tag,而不是返回这些值。这样做是为了满足那些不喜欢在view中使用短标签(<?= ?>)或者许多echo()调用。包含$return参数的方法允许你该写自己的核心库配置。如果不考虑AUTO_OUTPUT的设置,你可以将$return设置为true这样html helper将会返回HTML代码。

       HTML helper方法同样包含了$htmlAttibutes参数,这个参数是的你可以将其他的属性粘贴在标签上。比如,你想给一个标签添加一个class属性,你可以把下面这个作为$htmlAttribute的属性。

array ( ' class ' => ' someClass ' )

1.1.2 插入正确组织的元素(well-formatted elements)

       如果你想要在你的HTMl代码中插入正确组织的、经常使用的元素,HTML helper起到很大的作用。这里有四个方法可以插入media,协助tables,甚至用可视化的列表树创建基于PHP数组的未排序的列表。

charset($charset,$return)

    ○这个方法可以创建一个charsetmeta标签(META-tag

css($path ,$rel =’stylesheet’ , $htmlAttriutes= null , $return =false)

       ○创建一个css模版页(stylesheet),$rel参数允许用户提供一个 rel=value作为标签(原文:The $rel parameter allows you to provide a rel= value for the tag.)

image($path, $htmlAttributes =null, $return=false)

    ○显示一个图片的标签。返回的代码可以用做link()方法的输入,这样就可以自动的产生一个linked images(liuchen注:我的理解就是创建了一个可以点击的图片,链接到别处)

link($title,$url=null,$htmlAttributes=null,$confirmMessage=false,

$escapeTitle=True, $return=false)

○使用这个方法可以在view里面创建一个链接,$confirmMessage可以在你需要一条javascript的确认信息的时候使用,这样,点击这个链接则跳出这个确认信息,一条删除对象的链接经常需要一条“你确定么?”的确认信息,这样在删除之前要求用户的确认。如果你想让HTML helper不用管理你的数据(保存在$title变量中),可以将$escapeTitle设置成为true

tableHeaders($names,$tr_options=null,$th_options=null)

    ○用来创建格式化的表格头

tableCells($data,$odd_tr_options=null,$even_tr_options=null)

    ○用来创建格式化的表格单元

guiListTree($data,$htmlAttributes=null,$bodyKey=’body’

                     $childrenKey=’children’,$return=false)

       ○根据一个数组创建一个未排序的整齐的列表

1.1.3 表格和正确性 Forms and Validation

Cakeview中快速编写html代码时候确实非常有效,它自动生成form标签,如果有错误还能自动填入值和错误消息。下面我们举个例子来实现。假设,你的程序有了一个Note model,你想创建一个controller逻辑和一个viewaddedit Note的对象。在你的NotesController中,你可以有一个edit action,这个action可以像下面这样:

function  edit( $id
   {
      
// First, let's check to see if any form data has been submitted to the action.      
       if  ( isset ( $this -> params[ ' form ' ][ ' data ' ][ ' note ' ])) 
      {
         
// Here's where we try to validate the form data (see Chap. 10) and save it
          if  ( $this -> note -> save( $this -> params[ ' data ' ]))
         {
            
// If we've successfully saved, take the user to the appropriate place
             $this -> flash( ' Your information has been saved. ' ,   ' /notes/edit/ '   .   $id );
            
exit ();
         }
         
else
         {
            
// If the data didn't validate, hand the form data back to the view
             $this -> set( ' form ' ,   $this -> params[ ' data ' ]);            
            
// Generate the error messages for the appropriate fields
             $this -> validateErrors( $this -> note);
            
// And render the edit view code
             $this -> render();
         }      
      }      
      
//  If we haven't received any form data, get the note we want to edit, and hand
      // its information to the view

       $this -> set( ' note ' ,   $this -> note -> find( " id = $id " ));
      
$this -> render();
   }


一旦我们的controller建立,我们来看一下view的代码(位于app/views/notes/edit.thtml)。我们的Note model是非常简单的。而且仅仅包含了一个id,一个提交着的idbody。这个view 的代码意思是显示Note的数据并且让用户输入新的值并将提交的新值输到model中。

       任何views默认情况下都可以得到HTML helper,使用$html就可以了。

       特别的,可以看下面的table

 

9.2 Edit View code(edit.thtml)

 

<!--  This tag creates our form tag  -->
<? php  echo   $html -> formTag( ' /notes/edit/ '   .   $note [ ' note ' ][ ' id ' ]) ?>
< table cellpadding = " 10 "  cellspacing = " 0 " >
< tr >
   
< td align = " right " > Body :   </ td >
   
< td >
      
<!--  Here ' s where we use the HTML helper to render the text area tag and its possible error message the $note variable was created by the controller, and contains the data for the note we ' re editing .   -->
      
<? php  echo  
      
$html -> textarea( ' note/body ' ,   array ( ' cols ' => ' 60 ' ,   ' rows ' => ' 10 ' ,  
           
' value '   =>   $note [ ' note ' ][ ' body ' ]))
      
?>
      
<? php  echo   $html -> tagErrorMsg( ' note/body ' ,   ' Please enter in a body for this note. ' ?>
   
</ td >
</ tr >
< tr >  
   
< td ></ td >
   
< td >
      
<!--  We can also  use  the HTML helper to  include  hidden tags inside our table  -->
      
<? php  echo   $html -> hiddenTag( ' note/id ' ,   $note [ ' note ' ][ ' id ' ]) ?>
      
<? php  echo   $html -> hiddenTag( ' note/submitter_id ' ,   $_SESSION [ ' user_id ' ]) ?>
   
</ td >
</ tr >
</ table >
<!--  And finally ,  the submit button -->
<? php  echo   $html -> submit() ?>
</ form >

大多数的表单标签生成方法(包括tagErrorMsg)都需要你提供一个$fieldName。这个$fieldName可以让Cakezhidao你想要传递什么数据,进而检查这个数据并保存。$fieldName参数传递的字符串要满足这种形式“modelname/fieldname”,如果你想要添加一个title field进入Note,你需要向view中添加下面这些代码
<? php  echo   $html -> input( ' note/title ' ,   $note [ ' note ' ][ ' title ' ])  ?>
<? php  echo   $html -> tagErrorMsg( ' note/title ' ,   ' Please supply a title for this note. ' ) ?>

错误信息将会有tagErrorMsg()方法显示在<div class=”error_message”></div>这个标签中,使用简单的CSS模式

       下面是一些HTML helper可以创建的form tags(大多数都是直接创建)。

formTag($target=null, $type=’post’,$htmlAttributes=null)

       ○创建一个打开的表单标签,使用$target来确定表单的action。记住,如果你要提交一个文件,你需要向$hatmAttrbutes参数提供合适的字符编码信息(?enctype infomation

submit($caption=’Submit’, $htmlAttributes=null, $return= false)

       ○通过$caption参数可以修改按钮名

password($fieldName, $htmlAttributes=null, $return=false)

textarea($fieldName, $htmlAttributes=null, $return = false)

checkbox($fieldName, $title=null, $htmlAttributes=null, $return=false)

file($fieldName, $htmlAttributes = null, $return=false)

hidden($fieldName, $htmlAttributes=null, $return=false)

input($fieldName, $htmlAttributes=null, $return=false)

radio($fieldName,$options,$inbetween=null,$htmlAttributes=null,$return=false)

tagErrorMsg($field, $text)

       HTML helper 也包含了一系列方法来帮助创建数据库相关的 tag $tagName 参数应该像 $filedName 参数一样处理。基金提供 date option tag 相关的 field name. 处理数据时,你可以在 controller 里面使用则各数据一直到该 field 的结尾。举例来说,如果我的 Note 有个 deadline 列(作为 data ),我的 dayOptionTag $tagName 参数被设置成‘ note/deadline ’,一旦表单被提交, day 数据将作为 $params 变量显示出来
$this -> params[ ' form ' ][ ' data ' ][ ' note ' ][ ' deadline_day ' ]

你可以使用这个来连接你的时间数据到跟你当前数据库配置相符合的形式。这段代码可以放在你尝试保存数据之前,保存到$data数组,这个数组可以用来保存信息到model

9.3 Concatenating time data before saving a mode(excerpt from NotesController)   
function  edit( $id
   {
      
// First, let's check to see if any form data has been submitted to the action.      
       if  ( isset ( $this -> params[ ' form ' ][ ' data ' ][ ' note ' ])) 
      {
         
// Concatenate time data for storage
          $this -> params[ ' data ' ][ ' note ' ][ ' deadline ' =  
            
$this -> params[ ' form ' ][ ' data ' ][ ' note ' ][ ' deadline_year ' .   " - "   .
            
$this -> params[ ' form ' ][ ' data ' ][ ' note ' ][ ' deadline_month ' .   " - "   .
            
$this -> params[ ' form ' ][ ' data ' ][ ' note ' ][ ' deadline_day ' ];                           
         
// Here's where we try to validate the form data (see Chap. 10) and save it
          if  ( $this -> note -> save( $this -> params[ ' data ' ]))
         {
         


dayOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

yearOptionTag ($tagName, $value=null, $minYear=null, $maxYear=null,

$selected=null, $optionAttr=null)

monthOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

hourOptionTag ($tagName, $value=null, $format24Hours=false,

$selected=null, $optionAttr=null)

minuteOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

meridianOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

dateTimeOptionTag ($tagName, $dateFormat= 'DMY', $timeFormat= '12',

$selected=null, $optionAttr=null)

 

1.2 AJAX

Cake Ajax helper实现了更加popularPrototypescript.aculo.us库赖提供Ajax操作和客户端效果。如果想使用这些helper,你必须有从http://script.aculo.us下载一份JavaScript libraries/app/webroot/js目录下

这个helper里面的削夺方法多扩展了特殊的$options数组作为参数。这个数组用来确定你的Ajax操作中的各种东西

 

liuchenAjax暂且略过,以后补充)

 

1.3 JavaScript

       JavaScript helper用来帮助开发者输出标准的tag和数据

codeBlock($script)

       ○用来返回$script,变量$script已经包含了<script>标签

link($url)

       ○返回包含tag,指向特定$url指定script的脚本

linkOut($url)

       ○跟link($url)的作用一样,就是参数$url不在本地

escapeScript($script)

       Escapes carriage returns and single and double quotes for JavaScript code segments.

event($object, $event, $observer, $useCapture=true)

○使用Prototype库,将一个事件链接到一个元素

cacheEvents()

○缓存event()创建的JavaScript事件

writeEvents()

○写cacheEvent()保存的内容

includeScript($script=””)

       ○返回含有标签的JavaScript,一般是从Cakejs库中(/app/webroot/js/

 

1.4 Number

       Number helper包括一些在views中转化数字数据的方法

precision ($number, $precision=3)

       ○返回由$precision确定的近似精度的值到$number

toReadableSize ($size)

       ○将bytes为单位的数字转化为用KBMBGBTB等用户比较容易明白的数字

toPercentage ($number, $precision=2)

○转化为百分数

 

1.5 Text

The Text Helper提供了一些方法,开发者可以使用这些方法来更好的将text输出到浏览器

highlight ($text, $phrase, $highlighter= '< span class="highlight">\1</span >')

       ○将$text中所有$phrase都放在一个<span>标签里,返回$text

stripLinks ($text)

       ○将所有的链接<a>标签都删除后返回

autoLinkUrls ($text, $htmlOptions=array())

       ○将所有的URL自动添加<a>标签

autoLinkEmails ($text, $htmlOptions=array())

       ○将所有的email地址自动添加<a>标签

autoLink ($text, $htmlOptions=array())

       ○将所有的URLemail地址都自动添加<a>标签

truncate ($text, $length, $ending='...')

       Returns the first $length number of characters of $text followed by $ending ('...' by default).(不明白)

trim ()

Alias for truncate().

excerpt ($text, $phrase, $radius=100, $ending="...")

Extracts an excerpt from the $text, grabbing the $phrase with a number of characters on each side determined by $radius.

flay($text, $allowHtml=false)

Text-to-html parser, similar to Textile or RedCloth, only with a little different syntax.

 

 

1.6 Time

Time Helper提供了一些方法,卡发者可以使用这些方法将时间方便的显示到浏览器上。时间可以提供的形式包括PHPdatatime字符串或者是Unix的时间戳

fromString ($date_string)

       ○根据输入的两种类型的时间返回Unix时间戳

nice ($date_string=null, $return=false)

       ○返回一个良好格式的时间字符串。比如Mon, Jan 1st 2005, 12:00

niceShort ($date_string=null, $return=false)

○跟nice类似,就是返回昨天和今天的时候,返回Yesterday, 12:00Today, 12:00

isToday ($date_string)

       ○返回给定的时间是否是今天

daysAsSql ($begin, $end, $field_name, $return=false)

       ○根据前后两个时间,返回一条sql查询语句,查找两个时间段内的记录

dayAsSql ($date_string, $field_name, $return=false)

       ○返回给定时间内的所有记录

isThisYear ($date_string, $return=false)

       ○返回是否是今年

wasYesterday ($date_string, $return=false)

       ○返回是否是去年

isTomorrow ($date_string, $return=false)

       ○返回是否是明天

toUnix ($date_string, $return=false)

       ○返回Unix时间戳

toAtom ($date_string, $return=false)

Returns a date formatted for Atom RSS feeds.

toRSS ($date_string, $return=false)

○格式化的RSS时间

timeAgoInWords ($datetime_string, $return=false)

       Returns either a relative date or a formatted date depending on the difference between the current time and given datetime. $datetime should be in a strtotime-parsable format like MySQL datetime.

relativeTime ($datetime_string, $return=false)

Works much like timeAgoInWords(), but includes the ability to create output for timestamps in the future as well (i.e. "Yesterday, 10:33", "Today, 9:42", and also "Tomorrow, 4:34").

wasWithinLast ($timeInterval, $date_string, $return=false)

       Returns true if specified datetime was within the interval specified, else false. The time interval should be specifed with the number as well as the units: '6 hours', '2 days', etc.

第十章 数据正确性(Data Validation

创建用户的数据正确规则可以确保model中的数据能够按照程序的业务规则,比如密码必须是8个字符,用户名仅仅包含字母等等

保证数据正确性,第一步要做的就是在model中创建数据正确的规则。使用Model::validate这个数组在model中定义,比如

10.1 /app/models/user.php

<? php
class  User  extends  AppModel {
   
var   $validate   =   array (
      
' login '   =>   ' /[a-z0-9\_\-]{3,}/i ' ,
      
' password '   =>  VALID_NOT_EMPTY ,
      
' email '   =>  VALID_EMAIL ,
      
' born '   =>  VALID_NUMBER
   );
}
?>

Validations定义使用perl的正则表达式,其中有一些事先定义在/libs/validators.php比如

VALID_NOT_EMPTY 
VALID_NUMBER 
VALID_EMAIL 
VALID_YEAR

如果model的定义中(比如在$validate数组)出现了任何的validateions,都会在保存过程中被转化和检查(比如在Model::save()方法中)。确保数据正确可以直接使用Model::validates()(如果数据不正确则直接返回false)或者Model::invalidFields()(这个方法返回错误信息的一个数组)

但是通常,controller代码中数据都是隐式的,下面的例子解释了如何创建一个处理form的方法

<? php
class  BlogController  extends  AppController {
   
function  add () {
      
if  ( empty ( $this -> params[ ' data ' ])) {
         
$this -> render();
      }
      
else  {
         
$this -> post -> set( $this -> params[ ' data ' ]);
         
if  ( $this -> post -> save()) {
            
$this -> flash( ' Your post has been saved. ' , ' /blog ' );
         }
         
else  {
            
$this -> set( ' data ' ,   $this -> params[ ' data ' ]);
            
$this -> validateErrors( $this -> post);
            
$this -> render();
         }
      }
   }
}
?>

这个方法使用的view如下:

< h2 > Add post to blog </ h2 >  
<?= $this -> formTag( ' /blog/add ' ) ?>  
< div  class = " blog_add " >
< p > Title :   <?=   $html -> inputTag( ' title ' ,   40 ) ?>
   
<?= $this -> tagErrorMsg( ' title ' ,   ' Title is required. ' ) ?></ p >
< p ><?= $this -> areaTag( ' body ' ?>
   
<?= $this -> tagErrorMsg( ' body ' ,   ' Body is required. ' ) ?></ p >  
< p ><?= $this -> submitTag( ' Save ' ) ?></ p >
</ div >
</ form >

Controller::validates($model[,$model…])方法用来检查添加到model的用户数据是否正确。Controller::validationErrors()方法返回model得到的错误信息,这些信息被viewtagErrorMsg()方法显示出来

 

第十一章 访问控制表(Access Control Lists)

1 理解ACL如何工作

       大多数权限很大的程序都需要某种形式的访问控制。ACL就是一种管理程序权限的简单持久的方法。ACL主要管理两件事情。需要东西的主体,和被需要的客体。在ACL系统中,想要东西的主体(经常情况下是用户)叫做access request objects,简称AROs。系统中被需要的客体(经常是方法或数据)叫做access control objects,简称ACOs。这些实体被成为objects是因为有时候被请求的object并不一定是人――有时候你可能想限制某个特定的Cake controller在程序其他的地方运行。ACOs可以是你想控制的任何东西,从一个controlleraction,一个web服务,甚至是祖母的在线日记的一行。

       一句话:ACL用来判断一个ARO是否可以访问一个ACO

       现在,为了帮你你更好的理解,我们来举一个实际的例子。假如某个时候,一群探险家有一个计算机系统。这些冒险者的组织者维护组织成员的健康状况时,想根据要求来编写权限。AROs(这里就是用户)包括

Aragorn        Bilbo        Frodo        Gollum        Legolas
Gimli        Pippin        Merry

系统中有许多实体都会被请求(ACOs)。需要注意到,ACL并不是用来鉴别用户权限的系统。一颗能早有一种方法来存储用户的信息,当他们进入系统后也可以修改用户的身份。一旦你明白什么时用户,ACL就非常有用了。好,还是回到我们的话题

接下来,Gandalf需要做的就是做一份原始的表,列出ACO等系统可以管理的东西,可能如下所示:


Weapons            The One Ring            Salted Pork
Diplomacy        Ale

一般的做法时,系统使用一个矩阵表来管理,这个矩阵表显示了用户和到物体权限的一个基本的集合。如果表中存储了信息,信息可能如下所示,其中X表示拒绝访问,O表示允许访问。

         Weapons    The One Ring    Salted Pork      Diplomacy       Ale
Gandalf     X             X              O               O            O
Aragorn     O             X              O               O            O
Bilbo       X             X              X               X            O
Frodo       X             O              X               X            O
Gollum      X             X              O               X            X
Legolas     O             X              O               O            O       
Gimli       O             X              O               X            X
Pippin      X             X              X               O            O
Merry       X             X              X               X            O

你可能说这个矩阵已经可以很好的工作了,但是这个仅仅针对于一个较小的系统,当一个很大的逐渐增长的系统,这个矩阵可能就无法很好的处理,比如说有成千上万的武器……

 

 

ACL一般使用tree结构来事先。通常有个AROs的树和ACOs的树。举例如下:

Fellowship of the Ring :
Warriors
    Aragorn
    Legolas
    Gimli
Wizards
    Gandalf
Hobbits
    Frodo
    Bilbo
    Merry
    Pippin
Vistors
    Gollum

通过这样构造树,我们可以将权限分配给其中的子节点。默认情况下,节点不可以访问任何东西。你可以顺着树往下,选择一些权限并实现他们。比如使用ACL可以如下:

如果你想用ACL来查看Pippin是否允许访问ale,我们首先在树中找到他的路径,在这个例子中是Fellowship-> Hobbites-> Pippin.接着我们可以看到许多不同的权限
Fellowship of the Ring :  [Deny :  ALL]
    Warriors                [Allow
:  Weapons ,  Ale ,  Elven Rations ,  Salted Pork]
        Aragorn
        Legolas
        Gimli
    Wizards                 [Allow
:  Salted Pork ,  Diplomacy ,  Ale]
        Gandalf
    Hobbits                 [Allow
:  Ale]
        Frodo
        Bilbo
        Merry
        Pippin
    Vistors                 [Allow
:  Salted Pork]
        Gollum

Fellowship = DENY ale, so deny(因为设置的是不允许访问任何ACO)

Hobbites = Allow Ale,所以允许

Pippin ? 这个并没有说明特定的信息

● 最终结果,允许访问ale

(译注:大概的意思就是每个分类有个总的权限,可以是allow,也可以是deny,然后每个组员在整个组的权限基础上,还可以补充自己的权限。)

 

2确定权限:基于ini文件的Cake ACL

    Cake最初ACL的实现是用iniw文件,尽管这种方法有用而且稳定,但是我们还是建议您使用基于数据库的ACL解决方案,这是因为创建新的ACOARO十分方便。这里,我们介绍ini主要是为了小型的开发,还有那些不想使用数据库的人。

    ARO/ACO的权限定义在/app/config/acl.ini.php。对特定访问权限的介绍可以在文件的开头找到。类似于下面


;  acl.ini.php - Cake ACL Configuration 
;
 ---------------------------------------------------------------------
;
 Use this file to specify user permissions. 
;
 aco = access control object (something in your application)
;
 aro = access request object (something requesting access)
;
 
;
 User records are added as follows:
;
;
 [uid]
;
 groups = group1, group2, group3
;
 allow = aco1, aco2, aco3
;
 deny = aco4, aco5, aco6
;
;
 Group records are added in a similar manner:
;
 
;
 [gid]
;
 allow = aco1, aco2, aco3
;
 deny = aco4, aco5, aco6
;
;
 The allow, deny, and groups sections are all optional.
;
 NOTE: groups names *cannot* ever be the same as usernames!

使用ini文件,你可以确定一个用户,确定他所属的组,确定他自己的权限。你也可以确定组的属性。你可以在11.4节找到更多如何用ini进行用户权限的检查。

 

3. 定义权限:使用数据库

3.1 开始

    默认的情况下,cake使用数据库来存储ACL访问权限。数据库ACL,或者dbACL有一组core models组组成,另外有命令行的脚本来执行Cake的安装。models用来插入或者查询ACL树。命令行脚本用来帮助你和树交互。

    开始要做的是确保/app/config/database.php文件存在而且正确配置。接下来,使用ACL命令行脚本来初始化数据库并存数ACL信息。脚本位于/cake/scripts/acl.php,它为帮助你完成。在/cake/scripts/目录下用下面的命令来初始化命令

 

11.1 Initializing your database using acl.php

$ php acl . php initdb

Initializing Database

Creating access control objects table (
acos )
Creating access request objects table (
acos )
Creating relationships table (aros_acos)


Done .

这时候,你就可以看到你数据库中添加了新的表。如果你对Cake如何存储树信息感到好奇,可以直接参看数据库中的信息。通常,acosaros表存储节点信息,aros_acos表用来连接aros到可访问的acos

    现在你就可以来创建你的AROsACOs树了。

 

3.2 创建AROSACOs

    这里有两种方法来引用AROs/ACOs,第一种是给他们一个整数id,通常就是他们所属表的主键。另一种方法就是给他们一个字符串的别称。

    创建一个新的ARO通常使用Aro Cake mode中定义的方法。Create()方法使用下面的参数:$link_id, $parent_id, $alias。这个方法创建了一个新的ACK对象,把$parent_id作为它的父亲(如果$parent_id是空,则该对象是根)。$link_id允许你把当前用户对象链接到一个ACL结构上。$alias参数允许使用一个非integerid赋给对象。

    举例说明:

$aro   =   new  Aro();
//  首先创建一些ARO,这些对象没有父节点。
$aro -> create(  1 ,   null ,   ' Bob Marley '  );
$aro -> create(  2 ,   null ,   ' Jimi Hendrix ' );
$aro -> create(  3 ,   null ,   ' George Washington ' );
$aro -> create(  4 ,   null ,   ' Abraham Lincoln ' );
// 现在我们来创建组来组织这些用户,注意到这些对象的id都是0,
$aro -> create( 0 ,   null ,   ' Presidents ' );
$aro -> create( 0 ,   null ,   ' Artists ' );
// 现在将这些ARO连接到对应的组
$aro -> setParent( ' Presidents ' ,   ' George Washington ' );
$aro -> setParent( ' Presidents ' ,   ' Abraham Lincoln ' );
$aro -> setParent( ' Artists ' ,   ' Jimi Hendrix ' );
$aro -> setParent( ' Artists ' ,   ' Bob Marley ' );
// 简单说,下面就是如何创建ARO
$aro   =   new  Aro(); 
$aro -> create( $user_id ,   $parent_id ,   $alias );

你可以通过命令行脚本来创建ARO,脚本是 $acl.php create are <link_id> <parent_id> <alias>

    创建ACO也是类似的

$aco   =   new  Aco();
// Create some access control objects:
$aco -> create( 1 ,   null ,   ' Electric Guitar ' );
$aco -> create( 2 ,   null ,   ' United States Army ' );
$aco -> create( 3 ,   null ,   ' Fans ' );
//  这个例子中我们省略将ACO链接到组
//So, to create an ACO:

$aco   =   new  Aco();
$aco -> create( $id ,   $parent ,   $alias );

3.3 确定权限

创建完ACOARO之后,我们要决定两者之间的权限,我们通常使用Cakecore acl组件。继续我们的例子

//  首先,在controller中,我们需要访问Cake的acl组件
class  SomethingsController  extends  AppController
{
    
// 你可能想把代码放在AppController中,但是放在这里也能很好的工作
     var   $components   =   array ( ' Acl ' );
    
//  记住:ACL总是阻止那些没有信息的东西,
//所以我们只要设置ARO访问ACO允许权限就可以了。

     function  someAction()
    {
        
// 允许权限设定如下:    
        // 这里你可以设定一个ARO完全访问ACO

         $this -> Acl -> allow( ' Jimi Hendrix ' ,   ' Electric Guitar ' );
        
$this -> Acl -> allow( ' Bob Marley ' ,     ' Electric Guitar ' );
        
//  我们还可以设定组的权限
         $this -> Acl -> Allow( ' Presidents ' ,   ' United States Army ' );       
        
// allow()方法还有第三个参数,$action。你可以使用这个参数设定部分
//的访问权限,$action可以设置为create,read,update,delete。如果
//没有说明,则设定所有权限s assumed.

         $this -> Acl -> allow( ' George Washington ' ,   ' Electric Guitar ' ,   ' read ' );
        
$this -> Acl -> allow( ' Abraham Lincoln ' ,     ' Electric Guitar ' ,   ' read ' );
        
// 阻止权限设置方法类似
         $this -> Acl -> deny( ' Abraham Lincoln ' ,   ' United States Army ' );
    }
}

一旦有用户创建,就可以将它的权限放到ACL树的对应位置,更多帮助可以使用命令行$php acl.php help

 

4 检查权限

检查权限是使用cake ACL最简单的部分,仅仅需要使用ACL组件的方法check().一个很好的方法来实现ACL就是将在Appcontroller中放置一个检查ACLaction,一旦有了这个action,你就可以访问ACL组件,并进行整个程序域的权限检查了。下面是一些实现的例子

class  AppController  extends  Controller 
{
    
//  得到我们的组件
     var   $components   =   array ( ' Acl ' );
    
function  checkAccess( $aco )
    {
        
//  使用组件来进行权限检查
         $access   =   $this -> Acl -> check( $_SESSION [ ' user_alias ' ] ,   $aco ,   $action   =   " * " ); 
        
// 不允许访问
         if  ( $access   ===   false )
        {
            
echo   " access denied " ;
            
exit ;
        }
        
// 允许访问
         else
        {
            
echo   " access allowed " ;
            
exit ;
        }
    }
}

通过在AppController使用ACL组件,你可以在程序的任何controller中使用它

 

//  Here's the basic format:
$this -> Acl -> Check( $aro ,   $aco ,   $action   =   ' * ' );


 

第十二章 数据安全

1,使用Sanitize

Cake使用Sanitize来避免用户提交的恶意请求或者其他不希望的结果。Sanitize是一个核心库,所以你可以在代码的任何地方使用,但是最好还是在controllers或者models中使用


 

//  实现包含这个库文件
uses( ' sanitize ' );
//  接下来,创建一个Sanitize对象
$mrClean   =   new  Sanitize();
// 下面你可以使用Sanitize来检测数据,具体方法下一节介绍


 

2.SQLHTML中使数据安全

本节主要介绍如何用Sanitize提供的方法

paranoid($string, $allowed = array())

$badString   =   " ;:<script><html><   // >@@# " ;
echo   $mrClean -> paranoid( $badString );
//  output: scripthtml
echo   $mrClean -> paranoid( $badString ,   array ( '   ' ,   ' @ ' ));
//  output: scripthtml    @@


 

html($string, $remove = false)    

$badString   =   ' <font size="99" color="#FF0000">HEY</font><script></script> ' ;
echo   $mrClean -> html( $badString );
//  output: &lt;font size=&quot;99&quot;color=&quot;#FF0000&quot;&gt;HEY&lt;
/ font & gt; & lt;script & gt;  & lt; / script & gt;
echo   $mrClean -> html( $badString ,   true );
//  output: font size=99 color=#FF0000 HEY fontscriptscript

sql($string)

       添加/号使得SQL语句是小,/号取决于用户系统当前的magic_quotes_gpc设定

cleanArray(&$toClean)

 

 

第十三章 cakesession组件

       cake存数session有三种方法:临时文件,php机制,数据库实现。默认情况下,cake使用php机制。如果使用临时文件或者是数据库,请在/app/config/core.php文件中修改CAKE_SESSION_SAVE成为cakephp,database三种之一。


 

/* *
* CakePHP includes 3 types of session saves database or file. Set this to your preferred method.
* If you want to use your own save handler place it in app/config/name.php 
*DO NOT USE file or database as the name. and use just the name portion below. *
* Setting this to cake will save files to /cakedistro/tmp directory 
* Setting it to php will use the php default save path Setting it to database will use the database
*/  
define ( ' CAKE_SESSION_SAVE ' ,   ' php ' );

如果要使用数据库来存储session,可以在数据库中创建一个新的表,表的结构可以在/app/config/sql/sessions.sql找到

 

2. 使用cakesession组件

       Cake seesion组件用来和session信息交互,包括基本的session的读写操作,同时也包括一些利用session表示信息的一些特性。如果你想使用session组件,确定有如下代码

 

class  SomeController  extends  AppController
{
    
var   $components   =   array ( ' Session ' );
}


下面是一些你可能使用的方法

check($name)

○检查一下当前$name确定的key是否设置到session

del($name) and delete($name)

○删除$name确定的session

error()

       ○返回最近的错误

flash($key = 'flash')

       ○返回最新的使用setFlash()的信息,如果$key设置了,那么返回的是$key存储的信息●read($name = null)

       ○读$name确定的session

renew()

       ○重新创建当前活跃的session,删除旧的id,并创建新的id,并将就的session值传递给新的session

setFlash($flashMessage, $layout = 'default', $params = array(), $key = 'flash')

       ○将$flashMessage中的message写入到session(或者待会儿被flash()取走),如果$layout设置成default,消息将会存储为'<div class="message">'.$flashMessage.'</div>'.如果设置为空, 消息将按照传递过来的样子存储。传递过来的信息将在Cake View中按照$layout存储起来。●valid()

       ○如果session可得,则返回true

write($name, $value)

       ○将$name$value确定的变量写入到当前活跃的session




第十四章 处理请求组件(the request handler component

1. 介绍

       Request Handler组件用来监测HTTP请求的信息。你可以使用它在controller中更好的了解ajax请求,得到远程客户端的ip以及请求的类型,或者过滤掉不想要的信息,使用这个组件,你需要确定它在controller$componets数组中,如下

class  ThingsController  extends  AppController
{
    
var   $components   =   array ( ' RequestHandler ' );
//  
}

2. 得到客户端或者请求信息

getAjaxVersion()

       ○返回version

getClientIP ()

       ○返回客户端ip

getReferrer ()

       ○返回服务器名称

isAjax()

       ○返回当前请求是否是XMLHttpRequest

isGet()

       ○返回是否通过GET方法

isMobile()

       ○返回是否移动浏览器

isPost()

       ○返回是否是Post方法

isPut()

       ○返回是否是Put方法

 

3. 过滤掉数据

有些情况下,你想要将请求或者输出中删除掉一些数据。

stripAll($str)

       ○过滤掉空格,图像,脚本

stripImages($str)

       ○过滤掉图像

stripScripts($str)

       ○过滤掉脚本

stripTags($str, $tag1, $tag2, $tag3...)

       ○过滤掉标签

$someString   =   ' <font color="#FF0000"><bold>Foo</bold></font> <em>Bar</em> ' ;
echo   $this -> RequestHandler -> stripTags( $someString ,   ' font ' ,   ' bold ' );
//  output: Foo <em>Bar</em>stripWhitespace($str)


 

stripWhitespace($str)

    ○过滤掉空格

4. 其他有用的方法

       当用户请求中含有ajax请求,Request Handler组件就十分有用。setAjax()方法用来自动检测Ajax求情,并且设置controllerlayout到请求的ajax layout

 

//  list.thtml
< ul >
<?   foreach  ( $things   as   $thing ) :?>
< li ><? php  echo   $thing ; ?></ li >
<? endforeach ; ?>
</ ul >

// -------------------------------------------------------------

//The list action of my ThingsController:

function   list ()
{
    
$this -> RequestHandler -> setAjax();
    
$this -> set( ' things ' ,   $this -> Thing -> findAll());



 

你可能感兴趣的:(cakephp)