CakePHP


Q:CakePHP官方文档在哪里

A:http://book.cakephp.org/cn/view/876/The-Manual

Q: 如何替换cake默认的layout(全局模板页)?
A: 把在/cake/libs/view/templates/layouts/default.ctp 复制到 /app/views/layouts/default.ctp ,然后按需修改

Q: 使用UTF8 库时出现乱码(页面和?菘舛际荱TF8,只是显示取出的数据时乱码)?
A: 在1.2x中:在/app/config/databases.php的配置中添加’encoding’ => ‘UTF8′,cake则会在执行SQL前先执行一次SET NAMES $encoding

Q: model/behavior,view/helper,controller/component 之间是什么关系?
A: model view controller是常说的MVC模式,model一般负责数据存储,view负责页面显示(一般是页面模板),controller负责控制调用哪个model以及哪个view来显示结果,其他则是他们各自的辅助部分。

Q: 如何建立一个公共的controller(如何使所有controller都有相同的属性或方法)?
A: 把/cake/app_controller.php 复制到 /app/app_controller.php ,按需修改即可。(为什么是放到/app目录下而不是/app/controllers中呢?)

Q: 如何建立一个公共的model(如何使所有model都有相同的属性或方法)?
A: 把/cake/app_model.php 复制到 /app/app_model.php,按需修改即可。(为什么是放到/app目录下而不是/app/moclels中呢?)

Q: 如何建立一个公共的helper(如何使所有helper都有相同的属性或方法)?
A: 同上,推理可得。

Q: 如何使controller不自动加载model(建立一个不需要model的controller)?
A: 在controller中添加一个空值属性:var $uses = ”;

Q: 如何建立不需要读取数据库的model?
A: 添加属性声明:var $useTable = false;

Q: 如何在controller中调用多个model?
A: 添加属性声明:var $uses = array(‘Model1′, ‘Model2′);

Q: 如何在controller中临时(手工)调用其他model?
A: How to properly create a Model instance manually
Creating Reusable Elements with requestAction

Q: 在controller中如何调用component?
A: 在controller中声明:var $components = array(‘Mycomponent’);,然后就可以在方法中通过 $ths->Mycomponent 来调用

Q: 如何在component中访问controller
A: 在1.1.x中可以这样:
class RequestComponent extends Object
{
var $controller;
function startup(&$controller)
                                {
                                 $this->controller = &$controller;
                                }

}

Q: 如何使controller的方法不能直接通过URL访问?
A: 在方法名前加个_,如:function _test()

Q: 在controller的一个方法中,如何调用另一个方法的输出结果?
A: $this->render(‘另一个方法名’);,相关的还有$this->requestAction,详细见手册。

Q: 如何让view可以使用其他helper?
A: 在controller中声明:var $helpers = array(‘Form’,'Text’); (注:html是默认就有的,在1.2x中不需要再包含进去)

Q: 怎样在cake中使用smarty?
A:

Q: 如何获取由$form->input(‘var’)提交的数据?
A: 在controller中通过$this->params['url']['data'][$this->controller->modelClass]['var'] 取得

Q: 如何取得URL中如/store/buy/12 的参数值?
A: 在controller中通过$this->params['pass'][0] 取得

Q: 如何在cake中使用AJAX?

Q: 如何映射一个controller(不建立controller但可以使不同的URL指向同一个controller)?

Q: 如何在一个model中调用其他model?

Q: 如何使controller的action不调用它的view(没有view的action)?

Q: 如何动态关闭cakeSqlLog?
A: /app/config/core.php中,将Configure::write(‘debug’, 2);修改为Configure::write(‘debug’, 0);

Q: 如何在一个helper中调用另一个helper?
A: 设置var $helpers = array(‘Myhelper’); ,然后就可以在类中用$this->Myhelper来调用(注意属性大小写)

1. 禁止布局
如果需要在全局禁止布局则在app_controller.php中设置$this->autoLayout = false,其子类可以继承/重写该设置;如果需要有条件,则可以将$this->autoLayout = false放在app_controller.php的before_filter()过滤器中。
如果只是个别的controller/action的话,那么最好是直接在具体的action定义中设定$this->autoLayout = false,而不是在控制器层级设定。

2. HTML助手
在模板里使用图片的时候,最好是使用助手的方式,如:echo $html->image(’pic.gif’),而不是直接手动编写<img>标签,因为如果硬编码的话,一旦网站目录结构出现变化,问题就严重了。同样的情况还出现在链接上,应该使用助手的方式,如:echo $html->url(array(’action’ => ‘foobar’)。

图片链接生成的两种方式:

 

//由$html->image()方法生成,简单而实用。但不够灵活,不能为<a>链接添加额外的属性
 <?=$html->image('/img/icons/review.png',array('alt'=>__('Review',true),'url'=>'/admin/members/review/'.$member['Account']['id']))?>
//由$html->link()生成,可以添加额外的属性,如提示信息。注意其中最后一个参数必须设置为false,否则会将$html->image转义
<?=$html->link($html->image('/img/icons/destroy.png',array('alt'=>__('Trash',true))),
                                  '/admin/members/destroy/'.$member['Account']['id'],
                                  array(),
                                  'Are you sure you want to delete this record?',
                                  false
                    )
?>

3. 分页助手

分页助手一般使用的都是文字链接,但实际上也可以使用图片链接,方法如下:

<?php echo $paginator->prev($html->image('prev.gif', array('border' => 0)), array('escape' => false));?>

类似的,表单提交按钮如果想使用图片的话,方法如下:

<?php $form->submit(‘pic.gif’)?>

注意所有图片文件都被认为是存放在webroot目录下的img文件夹内的。

分页默认是由div包裹,这个是可以自定义的:

 <?=$paginator->prev('« '.__('Previous', true), array(), null, array('class'=>'disabled prev_page','tag'=>'span'));?>

有时候分页时需要通过URL传递一些查询参数,此时应该在模板文件里按如下设置:

<?php $paginator->options(array('url' => $this->passedArgs));?>

4. Form助手

在CakePHP里,Form助手可以说是所有助手里最重要的,也是最复杂的,其中,尤以input方法为甚,比如说文章属于一个目录,那么在录入文章的表单里我们可以这样生成一个目录的下拉菜单:

<?php
$form->input('category_id');
//当然,仅仅这样还不够,还需要在控制器里提供数据才OK
$this->set('categories', $this->Article->Category->find('list'));
?>

相应表有一个name字段用于显示,当然你也可以在模型里设定var $displayField属性。总体来说非常简单,甚至有点奇幻的感觉,这是因为CakePHP在这里做了点小动作,参考form.php文件:

<?php
if (!isset($options['options']) && in_array($options['type'], $types)) {
    $view =& ClassRegistry::getObject('view');
    $varName = Inflector::variable(
        Inflector::pluralize(preg_replace('/_id$/', '', $this->field()))
    );
    $varOptions = $view->getVar($varName);
    if (is_array($varOptions)) {
        if ($options['type'] !== 'radio') {
            $options['type'] = 'select';
        }
        $options['options'] = $varOptions;
    }
}
?>

CakePHP会把表单元素名字中的_id部分去掉,并转换成复数形式,然后在当前视图变量里查找是否已经有了同名的变量,如果有,且未设置成radio单选标签,就把它当做select下拉菜单。

表单助手缺省创建的input会有div包裹,还有label等等修饰,很多时候这和美工设计的页面结构不同,这时:

$form->input(’password’, array(’div’ => false, ‘label’ => false, ‘error’ => false))

输出记得转义,CakePHP提供了h()方法,很简单,但是总容易忘。

这里还有一个技巧,就是在渲染select的时候,如果原来的数据库表里有一个名为name或者title的字段,那么会自动被当做下拉菜单的显示部分。

5. saveAll方法

saveAll方法可以同时保存一对一,一对多的关系。比如说一个question有多个answer,那么在question的表单里,我们就可以这样设定:

<?php
echo $form->input('Question.title');
echo $form->input('Answer.0.content');
echo $form->input('Answer.1.content');
echo $form->input('Answer.2.content');
echo $form->input('Answer.3.content');
?>

经过这样简单的设定后,在question控制器里就可以使用saveAll方法一次性保存所有的数据了。

6. Configure最多支持三级设置

如果超过三级,比如说Configure::write(’A.B.C.D’, ‘…’);这样是无效的,做多A.B.C三级。


7. 通过HTTP_X_FORWARDED_FOR得到客户端IP

如果想通过HTTP_X_FORWARDED_FOR得到客户端IP,必须传递一个false参数:

<?php $this->RequestHandler->getClientIP(false);?>

就是说要传递一个false参数,不过这样做仅适合安全性要求不高的应用。

8. 钩子方法afterFilter并不一定会执行

这是CakePHP的一个硬伤,因为redirect会直接跳转,所以afterFilter有可能会被忽略,这点要注意。

9. Auth组件缺省设置的弊端

缺省实现里,提交表单时,如果有password字段,会自动哈希处理,但是有的时候反倒麻烦,比如说添加用户时,如果验证未通过,再显示出错表单时,密码字段已经被哈希了,已经不是初始值了,再提交就不对了,所以为了屏蔽问题,就不应该再使用password字段名,而应该改名,以注册表单为例:

原始密码:

<?php echo input(’encrypt_password’); ?>

确认密码:

<?php echo input(’confirm_password’); ?>

这样的话,字段值在提交前后始终保持是初始值,就不会再有问题了。

如果在CakePHP项目中使用AJAX使用AJAX,输出就不需要视图。但程序会提示:Missing View。这个时候只要在方法里加入以下代码:

function someMethod() {
	 $this->autoRender = false;
}

同样如果你开启了debug,在处理AJAX时需要关闭。


function someMethod() {
	 $this->autoRender = false;
	 if ( $this->RequestHandler->isAjax() ) {
		  Configure::write ( 'debug', 0 );
	 }
}

如果项目中使用多数据库Master+Slave实现数据负载分享,那么CakePHP如何对应实现读写分离呢?记得上一篇我们读到beforeFind和beforeSave方法吗?没错,整个实现过程非常简单。

首先修改database.php设置:


 'mysql',
'persistent' => false,
'host' => '192.160.1.110',
'port' => '',
'login' => 'root',
'password' => '1234',
'database' => 'cakephp',
'schema' => '',
'prefix' => '',
'encoding' => 'UTF8'
);
public $master = array(
'driver' => 'mysql',
'persistent' => false,
'host' => '192.168.1.100',
'port' => '',
'login' => 'root',
'password' => '',
'database' => 'cakephp',
'schema' => '',
'prefix' => '',
'encoding' => 'UTF8'
);
}
?>

然后修改app_module.php


useDbConfig = 'master';

}

function afterSave() {

$this->useDbConfig = 'default';

}

function beforeDelete() {

$this->useDbConfig = 'master';

}

function afterDelete() {

$this->useDbConfig = 'default';

}

}

?>

如果是多台Slave数据库呢?可以配置$slave_db1, $slave_db2….$slave_db10,然后在用随机数来简单实现从多台Slave获取数据。当然实际上会有更高效的方法实现均衡从多台Slave获取数据,这个下次讲。

CakePHP默认是使用utf-8编码的,但有时候因为环境等问题,导致中文数据乱码。

方法一:解决方法是修改cake/libs/module/app_module.php,修改后代码如下:

 

class AppModel extends Model {

	public $actsAs = array("Containable");

	public function beforeFind() {
		$this->query("SET NAMES utf8");
	}

	public function beforeSave() {
		$this->query("SET NAMES utf8");
		return true;
	}
}

方法二:修改app/config/database.php

增加:encoding=>’utf8’


搞定收工。 之所以把方法一放在前面,是为了让大家知道有beforexxx的方法。建议使用方法二

« 上一页