Added Kohana v3.0.8
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
# 约定
|
||||
|
||||
鼓励大家遵循 Kohana 的编码样式,Kohana 基于 [BSD/Allman style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) 的编码样式(这里还有一些更多[关于 Kohana 编码样式的描述](http://dev.kohanaframework.org/wiki/kohana2/CodingStyle))
|
||||
|
||||
## 类名和文件位置 {#classes}
|
||||
|
||||
在 Kohana 系统中类名严格遵循命名约定才能够[自动加载](using.autoloading)。类名的首字母必须大写,且使用下划线连接单词,千万要注意下划线的重要性,因为它直接关系到文件在文件系统中所存放的位置。
|
||||
|
||||
请遵循以下约定:
|
||||
|
||||
1. 类名不允许使用骆驼命名法,除非需要创建新一级的目录文件。
|
||||
2. 所有的类文件的文件名和目录名都必须是小写。
|
||||
3. 所有的类文件都应该存放在 `classes` 目录下面,它可以是在[级联文件系统](about.filesystem)的任何一级。
|
||||
|
||||
[!!] 不像 Kohana v2.x,这里不再区分 "controllers","models","libraries" 和 "helpers" 文件夹。所有的类都存放在 "classes/" 目录,既可以是完全静态的 辅助函数("helpers")或对象形式的类库("libraries")。你可以使用任意形式的设计模式的类库:静态,单例,适配器等。
|
||||
|
||||
## 实例
|
||||
|
||||
请大家记着一点在类文件中,类名到下划线意味着是一个新的目录,参考下面例子:
|
||||
|
||||
类名 | 文件路径
|
||||
----------------------|-------------------------------
|
||||
Controller_Template | classes/controller/template.php
|
||||
Model_User | classes/model/user.php
|
||||
Database | classes/database.php
|
||||
Database_Query | classes/database/query.php
|
||||
Form | classes/form.php
|
||||
|
||||
## 编码标准 {#coding_standards}
|
||||
|
||||
In order to produce highly consistent source code, we ask that everyone follow the coding standards as closely as possible.
|
||||
|
||||
### Brackets
|
||||
Please use [BSD/Allman Style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracketing.
|
||||
|
||||
### 命名约定
|
||||
|
||||
Kohana 使用下划线连接命名,而不是驼峰命名。
|
||||
|
||||
#### 类
|
||||
|
||||
// 库,使用 _Core 作后缀
|
||||
class Beer_Core {
|
||||
|
||||
// 库的继承不需要使用后缀
|
||||
class Beer extends Beer_Core
|
||||
|
||||
// 控制器类,使用 _Controller 作后缀
|
||||
class Apple_Controller extends Controller {
|
||||
|
||||
// 模型类,使用 _Model 作后缀
|
||||
class Cheese_Model extends Model {
|
||||
|
||||
// 辅助类
|
||||
class peanut {
|
||||
|
||||
当你实例化一个不需要附带参数的类时不需要使用圆括号:
|
||||
|
||||
// 正确:
|
||||
$db = new Database;
|
||||
|
||||
// 错误:
|
||||
$db = new Database();
|
||||
|
||||
#### 函数和方法
|
||||
|
||||
函数尽量全小写,并使用下划线分割单词:
|
||||
|
||||
function drink_beverage($beverage)
|
||||
{
|
||||
|
||||
#### 变量
|
||||
|
||||
所有变量尽量全小写,并使用下划线分割单词而不是驼峰:
|
||||
|
||||
// 正确:
|
||||
$foo = 'bar';
|
||||
$long_example = 'uses underscores';
|
||||
|
||||
// 错误:
|
||||
$weDontWantThis = 'understood?';
|
||||
|
||||
### 缩进
|
||||
|
||||
代码在逻辑上缩进使用制表符(TAB)代替空格。
|
||||
|
||||
垂直间距(即多行)使用空格。制表符并不适用于垂直间距主要是因为不同的人可能设置类不同的制表符宽度。
|
||||
|
||||
$text = 'this is a long text block that is wrapped. Normally, we aim for '
|
||||
. 'wrapping at 80 chars. Vertical alignment is very important for '
|
||||
. 'code readability. Remember that all indentation is done with tabs,'
|
||||
. 'but vertical alignment should be completed with spaces, after '
|
||||
. 'indenting with tabs.';
|
||||
|
||||
### 字符串连接
|
||||
|
||||
不要在连接符左右使用空格:
|
||||
|
||||
// 正确:
|
||||
$str = 'one'.$var.'two';
|
||||
|
||||
// 错误:
|
||||
$str = 'one'. $var .'two';
|
||||
$str = 'one' . $var . 'two';
|
||||
|
||||
### 单行表达式
|
||||
|
||||
单行 IF 表达式仅用于破坏正常执行的情况(比如,return 或 continue):
|
||||
|
||||
// 可接受:
|
||||
if ($foo == $bar)
|
||||
return $foo;
|
||||
|
||||
if ($foo == $bar)
|
||||
continue;
|
||||
|
||||
if ($foo == $bar)
|
||||
break;
|
||||
|
||||
if ($foo == $bar)
|
||||
throw new Exception('You screwed up!');
|
||||
|
||||
// 不可接受:
|
||||
if ($baz == $bun)
|
||||
$baz = $bar + 2;
|
||||
|
||||
### 比较操作
|
||||
|
||||
使用 OR 和 AND 作为比较符:
|
||||
|
||||
// 正确:
|
||||
if (($foo AND $bar) OR ($b AND $c))
|
||||
|
||||
// 错误:
|
||||
if (($foo && $bar) || ($b && $c))
|
||||
|
||||
if/else Blocks
|
||||
|
||||
使用 elseif 而不是 else if:
|
||||
|
||||
// 正确:
|
||||
elseif ($bar)
|
||||
|
||||
// 错误:
|
||||
else if($bar)
|
||||
|
||||
### Switch 结构
|
||||
|
||||
每个 case,break 和 default 都应该是独立的一行。每个 case 或 default 里面必须使用一个制表符(TAB)。
|
||||
|
||||
switch ($var)
|
||||
{
|
||||
case 'bar':
|
||||
case 'foo':
|
||||
echo 'hello';
|
||||
break;
|
||||
case 1:
|
||||
echo 'one';
|
||||
break;
|
||||
default:
|
||||
echo 'bye';
|
||||
break;
|
||||
}
|
||||
|
||||
### 括号
|
||||
|
||||
There should be one space after statement name, followed by a parenthesis. The ! (bang) character must have a space on either side to ensure maximum readability. Except in the case of a bang or type casting, there should be no whitespace after an opening parenthesis or before a closing parenthesis.
|
||||
|
||||
// 正确:
|
||||
if ($foo == $bar)
|
||||
if ( ! $foo)
|
||||
|
||||
// 错误:
|
||||
if($foo == $bar)
|
||||
if(!$foo)
|
||||
if ((int) $foo)
|
||||
if ( $foo == $bar )
|
||||
if (! $foo)
|
||||
|
||||
### 三元操作
|
||||
|
||||
所有的三元操作都应该遵循一种标准格式。表达式左右使用括号,而变量则不需要。
|
||||
|
||||
$foo = ($bar == $foo) ? $foo : $bar;
|
||||
$foo = $bar ? $foo : $bar;
|
||||
|
||||
所有的比较和操作都必须使用括号括起来作为一个组:
|
||||
|
||||
$foo = ($bar > 5) ? ($bar + $foo) : strlen($bar);
|
||||
|
||||
分离复杂的三元操作(三元的第一部分超过了 80 个字符)为多行形式。spaces should be used to line up operators, which should be at the front of the successive lines:
|
||||
|
||||
$foo = ($bar == $foo)
|
||||
? $foo
|
||||
: $bar;
|
||||
|
||||
### 强制类型转换
|
||||
|
||||
强制类型转换需要在两边使用空格:
|
||||
|
||||
// 正确:
|
||||
$foo = (string) $bar;
|
||||
if ( (string) $bar)
|
||||
|
||||
// 错误:
|
||||
$foo = (string)$bar;
|
||||
|
||||
如果可能,请使用强制类型转换,而不是三元操作:
|
||||
|
||||
// 正确:
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// 错误:
|
||||
$foo = ($bar == TRUE) ? TRUE : FALSE;
|
||||
|
||||
如果强制类型转换整形(int)或布尔型(boolean),请使用短格式:
|
||||
|
||||
// 正确:
|
||||
$foo = (int) $bar;
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// 错误:
|
||||
$foo = (integer) $bar;
|
||||
$foo = (boolean) $bar;
|
||||
|
||||
### 常量
|
||||
|
||||
常量尽量使用全大写:
|
||||
|
||||
// 正确:
|
||||
define('MY_CONSTANT', 'my_value');
|
||||
$a = TRUE;
|
||||
$b = NULL;
|
||||
|
||||
// 错误:
|
||||
define('MyConstant', 'my_value');
|
||||
$a = True;
|
||||
$b = null;
|
||||
|
||||
请把常量放在比较符号的末端:
|
||||
|
||||
// 正确:
|
||||
if ($foo !== FALSE)
|
||||
|
||||
// 错误:
|
||||
if (FALSE !== $foo)
|
||||
|
||||
这是一个略有争议的选择,所以我会解释其理由。如果我们用简单的英语写前面的例子中,正确的例子如下:
|
||||
|
||||
if variable $foo is not exactly FALSE
|
||||
|
||||
但是错误的例子可以理解为:
|
||||
|
||||
if FALSE is not exactly variable $foo
|
||||
|
||||
由于我们是从左向右读,因此把常量放在第一位根本没有意义。
|
||||
|
||||
### 注解
|
||||
|
||||
#### 单行注解
|
||||
|
||||
单行注解使用 //,或许你在使用下面几种注解方式。请在注解符后面保留一个空格在添加注解。坚决不能使用 #。
|
||||
|
||||
// 正确
|
||||
|
||||
//错误
|
||||
// 错误
|
||||
# 错误
|
||||
|
||||
### 正则表达式
|
||||
|
||||
如果编码中使用到正则表达式,请尽量使用 PCRE 风格而不是 POSIX 风格。相比较而言 PCRE 风格更为强大,速度更快。
|
||||
|
||||
// 正确:
|
||||
if (preg_match('/abc/i'), $str)
|
||||
|
||||
// 错误:
|
||||
if (eregi('abc', $str))
|
||||
|
||||
正则表达式使用单引号括起来而不是双引号。单引号的字符串简单而且解析起来更快。
|
||||
Unlike double-quoted strings they don't support variable interpolation
|
||||
nor integrated backslash sequences like \n or \t, etc.
|
||||
|
||||
// 正确:
|
||||
preg_match('/abc/', $str);
|
||||
|
||||
// 错误:
|
||||
preg_match("/abc/", $str);
|
||||
|
||||
当需要使用正则搜索活替换时,请使用 $n 符号作反向引用,它的效率优于 \\n。
|
||||
|
||||
// 正确:
|
||||
preg_replace('/(\d+) dollar/', '$1 euro', $str);
|
||||
|
||||
// 错误:
|
||||
preg_replace('/(\d+) dollar/', '\\1 euro', $str);
|
||||
|
||||
最后,请注意如果使用 $ 符号匹配字符串末尾是否允许后换行符的话,如果需要可以附加 D 修饰符解决此问题。[更多详情](http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html)。
|
||||
|
||||
$str = "email@example.com\n";
|
||||
|
||||
preg_match('/^.+@.+$/', $str); // TRUE
|
||||
preg_match('/^.+@.+$/D', $str); // FALSE
|
@@ -0,0 +1,75 @@
|
||||
# 级联文件系统
|
||||
|
||||
Kohana 文件系统单一的目录结构。
|
||||
当使用 [Kohana::find_file] 加载一个文件时,系统会以下顺序搜索:
|
||||
|
||||
Application 路径
|
||||
: 在 `index.php` 文件中常量被定义为 `APPPATH`,默认值是 `application`。
|
||||
|
||||
Module 路径
|
||||
: 这是在 `APPPATH/bootstrap.php` 文件中使用 [Kohana::modules] 设置的一组数组。
|
||||
数组的每个值都会按照顺序搜索并添加进来。
|
||||
|
||||
System 路径
|
||||
: 在 `index.php` 文件中常量被定义为 `SYSPATH`。默认值是 `system`。
|
||||
所有 “core” 核心文件和类文件都在这里定义。
|
||||
|
||||
目录中的文件包含了优先顺序建立的从高到低的优先级,这就有可能使得具有"高等级"目录的同名文件的会重载任何可以低于它的文件内容。
|
||||
|
||||

|
||||
|
||||
如果在 `APPPATH/views` 目录和 `APPPATH/views` 目录均有一个名为 `welcome.php` 视图文件,
|
||||
当 `welcome.php` 被加载的时候由于 application 目录在文件系统的最上面所以只有它会被返回。
|
||||
|
||||
## 文件类型
|
||||
|
||||
目录的级别从高到低依次是 application,module 和 system 路径,分别都有下面的目录结构:
|
||||
|
||||
classes/
|
||||
: 所有你想要 [autoload](using.autoloading) 的类库均保存在这里。
|
||||
本目录包含了控制器,模型和其他类库。所有的库文件都必须遵循[类的命名规则](about.conventions#classes)。
|
||||
|
||||
config/
|
||||
: 配置文件是使用 [Kohana::config] 返回的数组项。
|
||||
详情请查阅[配置的用法](using.configuration)。
|
||||
|
||||
i18n/
|
||||
: 多语言文件返回的包各国语言的字符串数组。多语言是使用 `__()` 方法实现。
|
||||
如果想把 "Hello, world" 多语言化,只需要调用 `__('Hello, world!')` 并设置
|
||||
[I18n::$lang] 为 "zh-cn"。
|
||||
详情请查阅[多语言的用法](using.translation)。
|
||||
|
||||
messages/
|
||||
: 消息文件是使用 [Kohana::message] 返回的字符串数组。消息和 i18n 文件唯一不同的就是无法多语言化,
|
||||
但是总是携程默认语言并通过单键引用。
|
||||
详情请查阅[消息的用法](using.messages)。
|
||||
|
||||
views/
|
||||
: 视图是标准的 PHP 文件被用于生成 HTML。视图文件被加载到 [View] 对象中并得到变量的设置,
|
||||
最后在转换为 HTML 片段或其他输出。多个视图可以相互引用。
|
||||
详情请查阅[视图的用法](using.views)。
|
||||
|
||||
## 查找文件
|
||||
|
||||
使用 [Kohana::find_file] 方法可以找到在文件系统中任意路径下的文件:
|
||||
|
||||
// 查询的路径 "classes/cookie.php"
|
||||
$path = Kohana::find_file('classes', 'cookie');
|
||||
|
||||
// 查询的路径 "views/user/login.php"
|
||||
$path = Kohana::find_file('views', 'user/login');
|
||||
|
||||
|
||||
## 第三方扩展
|
||||
|
||||
调用扩展并非限定在 Kohana 。
|
||||
比如,如果你想使用 [DOMPDF](http://code.google.com/p/dompdf),
|
||||
只需把他复制到 `application/vendor/dompdf` 并加载 DOMPDF 的自动加载类:
|
||||
|
||||
require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config.inc');
|
||||
|
||||
现在无需再加载任何文件就可以使用 DOMPDF:
|
||||
|
||||
$pdf = new DOMPDF;
|
||||
|
||||
[!!] 如果你想使用 DOMPDF 转换试图到 PDFs,可以试试 [PDFView](http://github.com/shadowhand/pdfview) 扩展。
|
73
includes/kohana/modules/userguide/guide/zh-cn/about.flow.md
Normal file
73
includes/kohana/modules/userguide/guide/zh-cn/about.flow.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 请求流程
|
||||
|
||||
每个应用都遵循同样的流程:
|
||||
|
||||
1. 程序从 `index.php` 文件加载
|
||||
2. 设置 application,module 和 system 目录到路径
|
||||
3. 设置错误报告的级别
|
||||
4. 加载 install.php 文件(如果存在的话)
|
||||
5. 加载 [Kohana] 类
|
||||
6. 加载 `APPPATH/bootstrap.php` 引导文件
|
||||
7. 调用 [Kohana::init] 方法初始化错误句柄,缓存和日志设置
|
||||
8. 设置 [Kohana_Config] 读取器和 [Kohana_Log] 记录器
|
||||
9. 调用 [Kohana::modules] 方法加载激活的模块
|
||||
* 模块路径附加到[文件级联系统](about.filesystem).
|
||||
* 加载模块的 `init.php` 文件(如果存在的话)
|
||||
* `init.php` 文件可以增强系统环境设置,同时也包括路由
|
||||
10. [Route::set] 会被多次调用来定义[程序路由](using.routing)
|
||||
11. 调用 [Request::instance] 方法来处理请求
|
||||
1. 检测每个路由直到发现匹配的
|
||||
2. 加载控制器实例化并传递请求
|
||||
3. 调用 [Controller::before] 方法
|
||||
4. 调用控制器的方法生成请求的响应
|
||||
5. 调用 [Controller::after] 方法
|
||||
* 当使用 [HMVC sub-requests](about.mvc) 时以上五步会多次循环调用
|
||||
12. 显示 [Request] 响应
|
||||
|
||||
## index.php
|
||||
|
||||
Kohana 遵循[前端控制器]模式,因此所有的请求都要发送到 `index.php` 文件。这样就可以允许保持一个非常整洁的[文件系统](about.filesystem)设计。在 `index.php` 文件中有一些非常重要而又基础的配置变量。你可以改变 `$application`,`$modules` 和 `$system` 的路径以及设置错误报告级别。
|
||||
|
||||
`$application` 变量让目录包含着你的程序文件。默认情况下,就是 `application` 目录。`$modules` 变量让目录包含着你的扩展文件。默认情况下。`$system` 变量让目录包含着默认的 Kohana 文件。默认情况下。
|
||||
|
||||
你可以移动下面三个目录到任意路径。假如你的目录结构是:
|
||||
|
||||
www/
|
||||
index.php
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
|
||||
你想转移这些目录到 web 目录以外:
|
||||
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
www/
|
||||
index.php
|
||||
|
||||
那么你应该在 `index.php` 文件改变下面变量的配置:
|
||||
|
||||
$application = '../application';
|
||||
$modules = '../modules';
|
||||
$system = '../system';
|
||||
|
||||
Now none of the directories can be accessed by the web server. It is not necessary to make this change, but does make it possible to share the directories with multiple applications, among other things.
|
||||
|
||||
[!!] There is a security check at the top of every Kohana file to prevent it from being accessed without using the front controller. However, it is more secure to move the application, modules, and system directories to a location that cannot be accessed via the web.
|
||||
|
||||
### 错误报告
|
||||
|
||||
默认情况下,Kohana显示所有错误,包括严格的警告。
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
对于已经上线并在运行的程序,一个保守的推荐,可以忽略掉提醒:
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
|
||||
如果在错误被触发后得到的是一个空白的结果,你的服务器可能关闭了错误提示。你可以在 `error_reporting` 调用前使用下面的代码开启错误提醒:
|
||||
|
||||
ini_set('display_errors', TRUE);
|
||||
|
||||
在发送错误提示时,错误应该**实时**显示,甚至是在上线发布之后,因为它允许你使用[异常和错误句柄](debugging.errors) 指引到一个友好的错误页面从而代替空白的页面。
|
@@ -0,0 +1,95 @@
|
||||
# 系统安装
|
||||
|
||||
1. 从 [Kohana 官方网站](http://kohanaframework.org/)下载最新**稳定**版本的框架
|
||||
2. 创建一个名为 'kohana' 的目录并解压缩到这个目录
|
||||
3. 上传到这个目录的所有文件到你的服务器上
|
||||
4. 编辑 `application/bootstrap.php` 文件并按实际情况修改下面配置:
|
||||
- 为你的程序设置默认[时区](http://php.net/timezones)
|
||||
- 在 [Kohana::init] 方法中设置 `base_url` 的值为 kohana 目录的路径(或域名地址)
|
||||
6. 确保 `application/cache` 目录和 `application/logs` 目录让服务器可写权限
|
||||
7. 在你喜欢的浏览器地址栏中输入 `base_url` 来测试 Kohana 是否安装成功
|
||||
|
||||
[!!] 根据系统平台的不同,安装的目录可能会随着解压缩而失去原先的权限属性。如果有错误发生请在 Kohana 根目录设定所有文件属性为 755。命令为:`find . -type d -exec chmod 0755 {} \;`
|
||||
|
||||
如果你可以看到安装页面(install.php)则说明已经安装成功(一片绿色),如果它报告有任何的错误(红色显示),你应该在立刻修复。
|
||||
|
||||

|
||||
|
||||
一旦安装页面报告你的环境确认无误,并且可以改名或删除在跟目录的 `install.php` 文件,然后你就能看到 Kohana 的欢迎界面:
|
||||
|
||||

|
||||
|
||||
|
||||
## 设置产品(Production)环境
|
||||
|
||||
在转移到产品环境之前有些事情需要完成:
|
||||
|
||||
1. 查看文档的[配置页面](about.configuration)。
|
||||
它涵盖了大多数的环境全局设置。
|
||||
一般来讲,在产品环境下需要开启缓存并关闭概况分析(profiling)([Kohana::init] 设置)。
|
||||
如果设置了很多路由,路由缓存也是很有必要的。
|
||||
2. 在 application/bootstrap.php 捕获所有的异常,已保证敏感信息不会被堆栈跟踪泄漏。
|
||||
下面有一个从 Shadowhand 的 wingsc.com 网站源代码提取出来的样例。
|
||||
3. 打开 APC 或某些类型的指令缓存。
|
||||
这是最简单容易的提升 PHP 自身性能的方法。程序越复杂,使用指令缓存带来越大的利益。
|
||||
|
||||
/**
|
||||
* Set the environment string by the domain (defaults to 'development').
|
||||
*/
|
||||
Kohana::$environment = ($_SERVER['SERVER_NAME'] !== 'localhost') ? Kohana::PRODUCTION : Kohana::DEVELOPMENT;
|
||||
/**
|
||||
* Initialise Kohana based on environment
|
||||
*/
|
||||
Kohana::init(array(
|
||||
'base_url' => '/',
|
||||
'index_file' => FALSE,
|
||||
'profile' => Kohana::$environment !== Kohana::PRODUCTION,
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
));
|
||||
|
||||
/**
|
||||
* Execute the main request using PATH_INFO. If no URI source is specified,
|
||||
* the URI will be automatically detected.
|
||||
*/
|
||||
$request = Request::instance($_SERVER['PATH_INFO']);
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to execute the response
|
||||
$request->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if ( Kohana::$environment == 'development' )
|
||||
{
|
||||
// Just re-throw the exception
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Log the error
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
|
||||
// Create a 404 response
|
||||
$request->status = 404;
|
||||
$request->response = View::factory('template')
|
||||
->set('title', '404')
|
||||
->set('content', View::factory('errors/404'));
|
||||
}
|
||||
|
||||
if ($request->send_headers()->response)
|
||||
{
|
||||
// Get the total memory and execution time
|
||||
$total = array(
|
||||
'{memory_usage}' => number_format((memory_get_peak_usage() - KOHANA_START_MEMORY) / 1024, 2).'KB',
|
||||
'{execution_time}' => number_format(microtime(TRUE) - KOHANA_START_TIME, 5).' seconds');
|
||||
|
||||
// Insert the totals into the response
|
||||
$request->response = str_replace(array_keys($total), $total, $request->response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the request response.
|
||||
*/
|
||||
echo $request->response;
|
||||
|
@@ -0,0 +1,15 @@
|
||||
# 什么是 Kohana?
|
||||
|
||||
Kohana 是由志愿者团队开发的一个开源形式使用 [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") 开发的[面对对象](http://wikipedia.org/wiki/Object-Oriented_Programming)模式 [MVC](http://wikipedia.org/wiki/Model–View–Controller "Model View Controller") 架构的 [Web 框架](http://wikipedia.org/wiki/Web_Framework)。它目标旨在快速开发,高安全性,轻量级代码。
|
||||
|
||||
[!!] Kohana 是基于 [BSD license](http://kohanaframework.org/license) 发布,所以大家可以用它开发任何的开源形式的,公司形式的或者个人形式的应用。
|
||||
|
||||
## Kohana 的特点是什么?
|
||||
|
||||
使用独有的 [文件系统](about.filesystem) 设计可以任意继承库类而经可能少的(或不需要)[配置](about.configuration),[错误句柄](debugging.errors)能够在开发过程中迅速定位错误源,并有内置的[调试器](debugging.overview)和[分析器](debugging.profiling)作为辅助开发工具。
|
||||
|
||||
并且提供为您的应用程序提供安全系数相关的工具:[XSS removal](security.xss),[input validation](security.validation),[signed cookies](security.cookies),[form](security.forms) 和 [HTML](security.html)。于此同时,[数据库](security.database)层提供对 [SQL 注入](http://wikipedia.org/wiki/SQL_Injection)的保护。这是因为所有的官方代码经过精心编写和安全审查的。
|
||||
|
||||
## 这文档太逊了!
|
||||
|
||||
我们正在全力提供完整的文档。如果你想从问题中找到答案,请查阅[非官方 Wiki](http://kerkness.ca/wiki/doku.php)。如果你想要添加或修改文档的内容,请 [fork](http://github.com/kohana/userguide) 本文档保存后发送 pull 请求。如果你不善于使用 git,你同样可以提交[feature request](http://dev.kohanaframework.org/projects/kohana3/issues)(需要注册)。
|
@@ -0,0 +1,7 @@
|
||||
# (层次结构)模型 视图 控制器
|
||||
|
||||
模型 视图 控制器,英文全称为 Model View Controller(缩写 MVC)是一个流行的设计模式,它从呈现/模板(视图)和请求流程(控制器)中分离了数据源(模型)。
|
||||
|
||||
使用此模式设计开发系统级别的应用程序会更加容易和最大限度的重用代码,这就意味着你不必在写那么多不必要的代码了!
|
||||
|
||||
[!!] Stub
|
288
includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md
Normal file
288
includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# 从 2.3.x 升级
|
||||
|
||||
Kohana v3 大部分功能都不同于 Kohana 2.3 版本,下面列出了一系列的升级建议:
|
||||
|
||||
## 命名约定
|
||||
|
||||
在 2.x 体系中不同的类的'类型'(比如 controller,model 等)使用后缀来加以区分。文件夹在模型/控制器目录下没有任何类名的关系。
|
||||
|
||||
在 3.0 版本中废弃了上面的形式转而使用 Zend framework 的文件体系的约定,也就是类名包含类名和其路径,之间是有下划线分割而不是斜杠符(比如 `/some/class/file.php` 变为了 `Some_Class_File`)
|
||||
详情请参见 [约定文档](start.conventions)
|
||||
|
||||
## Input 库
|
||||
|
||||
Input 库已经从 3.0 版本中移除,请使用 `$_GET` 和 `$_POST` 获取。
|
||||
|
||||
### XSS 保护
|
||||
|
||||
假如你需要使用 XSS 清除用户输入数据,你可以使用 [Security::xss_clean] 处理输入数据,比如:
|
||||
|
||||
$_POST['description'] = security::xss_clean($_POST['description']);
|
||||
|
||||
你也可以把 [Security::xss_clean] 当作 [Validate] 类的过滤器使用:
|
||||
|
||||
$validation = new Validate($_POST);
|
||||
|
||||
$validate->filter('description', 'Security::xss_clean');
|
||||
|
||||
### POST & GET
|
||||
|
||||
Input 库有一个最大的方便之处在于如果你试图从一个超全域阵列(superglobal arrays)访问它的值,假若其值不存在 Input 库则会返回一个指定的默认值,比如:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id 获得的值是 1
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
$_GET['id'] = 25;
|
||||
|
||||
// $id 现在获得的值是 25
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
在 3.0 版本你可以使用 [Arr::get] 方法实现同样的效果:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id 获得的值是 1
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
$_GET['id'] = 42;
|
||||
|
||||
// $id 现在获得的值是 42
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
## ORM 库
|
||||
|
||||
自 2.3 版本到现在已经有一些主要的改动,下面是常见的通用升级问题:
|
||||
|
||||
### 成员变量
|
||||
|
||||
现在所有的成员变量都添加了 下划线(_) 作为前缀而且无法再通过 `__get()` 方法获得访问权利。相反的你可以把属性名并去掉下划线当作函数去调用。
|
||||
|
||||
例如,在 2.3 版本中有一个 `loaded` 属性,现在改名为 `_loaded` 并且如果需要在外边类库中访问此属性只需要 `$model->loaded()`。
|
||||
|
||||
### 关系
|
||||
|
||||
在 2.3 版本中如果你想要迭代一个模型相关对象的话,你需要:
|
||||
|
||||
foreach($model->{relation_name} as $relation)
|
||||
|
||||
然而,在新的系统中这已经失效。在 2.3 版本中任何使用 Databate 库生成的查询都是在全局作用域生成,这就意味着你不能同时尝试和构建两个查询语句。这里有个例子:
|
||||
|
||||
# TODO: 需要一个具体的实例!!!!
|
||||
|
||||
第二此查询则会失效而不能查询,内部查询将 '继承' 作为第一条件,从而造成混乱。在 3.0 版本中此问题得到了有效的解决,创建每条查询都是其自身的作用域之中,尽管如此,这也意味着有些东西没法按实际的预期正常工作。这里有个例子:
|
||||
|
||||
foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
[!!] (相关新的查询语法请查看 [Database 教程](tutorials.databases))
|
||||
|
||||
在 2.3 版本中你希望它可以返回用户为 3 且 `post_date` 在最近 24 小时内发布的所有 posts 的迭代器,然而相反的,它将适用 where 语句到 user 模型中并返回带有指定加入语句的 'Model_Post' 对象。
|
||||
|
||||
为了达到 2.3 版本的同样效果,你只需要略微修改结构即可:
|
||||
|
||||
foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
这同样也应用到 `has_one` 关系中:
|
||||
|
||||
// 错误
|
||||
$user = ORM::factory('post', 42)->author;
|
||||
// 正确
|
||||
$user = ORM::factory('post', 42)->author->find();
|
||||
|
||||
### Has and belongs to many relationships
|
||||
|
||||
在 2.3 版本中你可以设置 `has_and_belongs_to_many` 关系。但是在 3.0 版本此功能已经融合到了 `has_many` *through*。
|
||||
|
||||
在你的模型中定义一个 `has_many` 关系到其他模型中,并且添加一个 `'through' => 'table'` 属性,其中 `'table'` 是连接表的名称。比如(posts<>categories):
|
||||
|
||||
$_has_many = array
|
||||
(
|
||||
'categories' => array
|
||||
(
|
||||
'model' => 'category', // 外部模型
|
||||
'through' => 'post_categories' // 连接表
|
||||
),
|
||||
);
|
||||
|
||||
如果你的数据库配置设置了表前缀,这也不用担心去添加表前缀。
|
||||
|
||||
### 外键
|
||||
|
||||
如果你想在 2.x 版本的 ORM 中覆写一个外键,你必须指定关系属于谁,并且你的新外键在成员变量 `$foreign_keys` 之中。
|
||||
|
||||
在 3.0 版本中你只需要在关系数组中定义一个 `foreign_key` 键即可,比如:
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
$_belongs_to = array
|
||||
(
|
||||
'author' => array
|
||||
(
|
||||
'model' => 'user',
|
||||
'foreign_key' => 'user_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
在上面的实例中我们应该在 posts 表中存在一个 `user_id` 字段。
|
||||
|
||||
|
||||
|
||||
In has_many relationships the `far_key` is the field in the through table which links it to the foreign table & the foreign key is the field in the through table which links "this" model's table to the through table.
|
||||
|
||||
考虑以下设定,"Posts" have and belong to many "Categories" through `posts_sections`.
|
||||
|
||||
| categories | posts_sections | posts |
|
||||
|------------|------------------|---------|
|
||||
| id | section_id | id |
|
||||
| name | post_id | title |
|
||||
| | | content |
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
protected $_has_many = array(
|
||||
'sections' => array(
|
||||
'model' => 'category',
|
||||
'through' => 'posts_sections',
|
||||
'far_key' => 'section_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Class Model_Category extends ORM
|
||||
{
|
||||
protected $_has_many = array (
|
||||
'posts' => array(
|
||||
'model' => 'post',
|
||||
'through' => 'posts_sections',
|
||||
'foreign_key' => 'section_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
显然,这里的别名设定是有点疯狂,但它是如何让 foreign/far 键很好工作的绝佳范例。
|
||||
|
||||
### ORM 迭代器
|
||||
|
||||
`ORM_Iterator` 也是值得注意的改动,它已经融合到了 Database_Result 之中。
|
||||
|
||||
如果你想要获得带有对象主键的 ORM 对象数组,你只需要调用 [Database_Result::as_array],比如:
|
||||
|
||||
$objects = ORM::factory('user')->find_all()->as_array('id');
|
||||
|
||||
其中的 `id` 就是 user 表的主键。
|
||||
|
||||
## Router 库
|
||||
|
||||
在 2.x 版本中有一个 Router 库用于处理主要的请求工作。它允许你在 `config/routes.php` 配置文件中定义基本的路由,而且它还允许支持自定义的正则表达式路由,尽管如此,如果你想做极端的话它就显得相当呆板。
|
||||
|
||||
## 路由
|
||||
|
||||
在 3.0 版本中路由系统(现在成为请求系统)有了更多的灵活度。路由现在全部定义在 bootstrap 文件中(`application/bootstrap.php`)以及模块(Module)的 init.php 文件之中(`modules/module/init.php`)。(另外值得一提的是,现在的路由是按照他们定义的顺序评估)
|
||||
|
||||
替换定义的路由数组,你现在为每个路由创建一个新的 [Route] 对象。不像在 2.x 体系一样没有必要映射一个 uri 到另一个。相反的你使用标记段(比如,controller,method,id)的变量来指定 uri 模式。
|
||||
|
||||
例如,在老系统的正则:
|
||||
|
||||
$config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1';
|
||||
|
||||
需要映射 uri 的 `controller/id/method` 为 `controller/method/id`,在 3.0 版本中这样修改:
|
||||
|
||||
Route::set('reversed','(<controller>(/<id>(/<action>)))')
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'));
|
||||
|
||||
[!!] 每个 uri 都必须指定一个独一无二的名称(这里定义的是 `reversed`),其背后的原因是解释在 [URL 教程](tutorials.urls) 之中。
|
||||
|
||||
尖括号的内容会当作动态解析部分。圆括号的内容则会当作是可选或不必要的字段。如果你只是想匹配 uris 的开头是 admin,你只需要:
|
||||
|
||||
Rouse::set('admin', 'admin(/<controller>(/<id>(/<action>)))');
|
||||
|
||||
但,如果你想用户必须指定一个控制器:
|
||||
|
||||
Route::set('admin', 'admin/<controller>(/<id>(/<action>))');
|
||||
|
||||
同样,Kohana 不使用任何的 '默认的默认项'。如果你想让 Kohana 去设置默认 action 为 'index',你只需要使用 [Route::defaults] 设置即可!如果你需要为 uri 字段自定义正则表达式,你只需要以 `segment => regex` 传递数组,比如:
|
||||
|
||||
Route::set('reversed', '(<controller>(/<id>(/<action>)))', array('id' => '[a-z_]+'))
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'))
|
||||
|
||||
这会迫使 id 的值必须全部是小写字母或者是数字,下划线。
|
||||
|
||||
### Actions
|
||||
|
||||
还有一点我们必须要提到的,如果控制器中的方法可以通过网址访问,现在被称为 "actions",且其前缀为 'action_'。比如,在上面的例中,如果用户访问 `admin/posts/1/edit`,那么 "actions" 就是 'edit' 而且方法在控制器将会是 `action_edit`。详情请参见 [URL 教程](tutorials.urls)
|
||||
|
||||
## Sessions
|
||||
|
||||
以下方法不再存在:Session::set_flash(),Session::keep_flash() 和 Session::expire_flash() 方法,替代这些废弃方法的函数你可以使用 [Session::get_once]。
|
||||
|
||||
## URL 辅助函数
|
||||
|
||||
URL 辅助函数仅做了略微的改动 - `url::redirect()` 方法转移到了 `$this->request->redirect()` 之中(包含控制器)/ `Request::instance()->redirect()`
|
||||
|
||||
`url::current` 现在替换为了 `$this->request->uri()`
|
||||
|
||||
## Valid / Validation
|
||||
|
||||
这恋歌类现在已经合并为一个类并命名为 `Validate`.
|
||||
|
||||
对于校验数组的语法也有些改动:
|
||||
|
||||
$validate = new Validate($_POST);
|
||||
|
||||
// 应用一个过滤器到所有数组项中
|
||||
$validate->filter(TRUE, 'trim');
|
||||
|
||||
// 定义规则使用 rule() 方法
|
||||
$validate
|
||||
->rule('field', 'not_empty')
|
||||
->rule('field', 'matches', array('another_field'));
|
||||
|
||||
// 为单字段设置多个规则也使用 rules() 方法,以 rules => params 的数组方式作为第二参数
|
||||
$validate->rules('field', array(
|
||||
'not_empty' => NULL,
|
||||
'matches' => array('another_field')
|
||||
));
|
||||
|
||||
为保证定义明确,其中 'required' 规则现已经改名为 'not_empty'。
|
||||
|
||||
## View 库
|
||||
|
||||
对于 View 库也有一些值得注意的主要改动。
|
||||
|
||||
在 2.3 版本中视图在其处理的控制器中调用呈现,并允许你使用 `$this` 作为视图应用引用到控制器中。这一点在 3.0 版本改变了。视图现在呈现在一个空白的作用域,如果你需要在视图中使用 `$this`,你可以使用 [View::bind] 绑定一个引用 - `$view->bind('this', $this)`
|
||||
|
||||
It's worth noting, though, that this is *very* bad practice as it couples your view to the controller, preventing reuse. 推荐的方法是像下面这样去传递必备的变量到视图中:
|
||||
|
||||
$view = View::factory('my/view');
|
||||
|
||||
$view->variable = $this->property;
|
||||
|
||||
// 或者如果你想使用连接方式
|
||||
|
||||
$view
|
||||
->set('variable', $this->property)
|
||||
->set('another_variable', 42);
|
||||
|
||||
// 不推荐
|
||||
$view->bind('this', $this);
|
||||
|
||||
因为视图在一个空的作用域呈现,而 `Controller::_kohana_load_view` 现在是多余的了。如果你想在它呈现之前修改视图(比如,添加一个站点的菜单),你可以使用 [Controller::after]
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
function after()
|
||||
{
|
||||
$this->template->menu = '...';
|
||||
|
||||
return parent::after();
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
# 调试
|
||||
|
||||
Kohana 默认加载一些功能强大的功能来辅助调试程序。
|
||||
|
||||
最常使用也是最基本的 [Kohana::debug] 方法。这个简单的方法会显示任何的变量数字,类似于 [var_export](http://php.net/var_export) 或 [print_r](http://php.net/print_r),但是使用了 HTML 格式输出。
|
||||
|
||||
// 显示 $foo 和 $bar 变量的相关信息
|
||||
echo Kohana::debug($foo, $bar);
|
||||
|
||||
Kohana 也提供一个方法 [Kohana::debug_source] 来显示特定文件的源代码。
|
||||
|
||||
// 显示当前行的源代码
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
|
||||
如果你希望显示你应用文件的信息而不泄漏安装路径,你可以使用[Kohana::debug_path]:
|
||||
|
||||
// 显示 "APPPATH/cache" 而不是真实路径
|
||||
echo Kohana::debug_path(APPPATH.'cache');
|
@@ -0,0 +1,22 @@
|
||||
# 错误/异常句柄
|
||||
|
||||
Kohana 同时提供了异常句柄和错误句柄使用 PHP 的 [ErrorException](http://php.net/errorexception) 类转换错误为异常。关于错误的详情和通过句柄显示应用程序的内部状态:
|
||||
|
||||
1. Exception 类
|
||||
2. 错误等级
|
||||
3. 错误信息
|
||||
4. 带有行高亮的错误源
|
||||
5. 执行流程的[调试跟踪](http://php.net/debug_backtrace)
|
||||
6. 导入(include)文件,加载扩展,全局变量
|
||||
|
||||
## 实例
|
||||
|
||||
点击任何一个链接可以切换显示额外的信息:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## 显示错误/异常句柄
|
||||
|
||||
如果您不希望使用内部错误句柄,您可以调用 [Kohana::init] 时禁用它:
|
||||
|
||||
Kohana::init(array('errors' => FALSE));
|
@@ -0,0 +1,20 @@
|
||||
# 分析器
|
||||
|
||||
Kohana 提供一种非常简单的方法来显示你的程序的统计信息
|
||||
|
||||
1. 普通 [Kohana] 方法调用
|
||||
2. 请求
|
||||
3. [Database] 查询
|
||||
4. 程序的平均运行时间
|
||||
|
||||
## 实例
|
||||
|
||||
你可以在任何时候显示或收集当前 [profiler] 统计:
|
||||
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
|
||||
## 预览
|
||||
|
||||
{{profiler/stats}}
|
@@ -0,0 +1 @@
|
||||
本页面将会列举 Kohana v3 的特性。
|
31
includes/kohana/modules/userguide/guide/zh-cn/menu.md
Normal file
31
includes/kohana/modules/userguide/guide/zh-cn/menu.md
Normal file
@@ -0,0 +1,31 @@
|
||||
1. **入门指南**
|
||||
- [什么是 Kohana?](about.kohana)
|
||||
- [约定和样式](about.conventions)
|
||||
- [模型-视图-控制器](about.mvc)
|
||||
- [级联文件系统](about.filesystem)
|
||||
- [请求流程](about.flow)
|
||||
- [安装](about.install)
|
||||
- [升级](about.upgrading)
|
||||
- [API 浏览器](api)
|
||||
3. **基本使用**
|
||||
- [配置](using.configuration)
|
||||
- [类的加载](using.autoloading)
|
||||
- [视图和 HTML](using.views)
|
||||
- [Sessions 和 Cookies](using.sessions)
|
||||
- [消息](using.messages)
|
||||
6. **调试**
|
||||
- [代码](debugging.code)
|
||||
- [错误句柄](debugging.errors)
|
||||
- [分析器](debugging.profiling)
|
||||
5. **安全**
|
||||
- [XSS](security.xss)
|
||||
- [校验](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [数据库](security.database)
|
||||
4. **教程**
|
||||
- [Hello, World](tutorials.helloworld)
|
||||
- [路由,URLs 和链接](tutorials.urls)
|
||||
- [清理 URLs](tutorials.removeindex)
|
||||
- [数据库](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [使用 Git 开发](tutorials.git)
|
@@ -0,0 +1,244 @@
|
||||
# 效验
|
||||
|
||||
使用 [Validate] 类可以对任意的数组进行校验。标签,过滤器,规则和回调函数都以数组的键(称之为 "字段名")附属于 Validate 对象。
|
||||
|
||||
标签(labels)
|
||||
: 标签是人们可读取的字段名。
|
||||
|
||||
过滤器(filters)
|
||||
: 过滤器必须在规则和回调函数之前调用执行做预处理。
|
||||
|
||||
规则(rules)
|
||||
: 规则是用于检测字段并返回结果 `TRUE` 或 `FALSE`。
|
||||
如果返回 `FALSE`,其对于的错误会添加到字段中。
|
||||
|
||||
回调函数(callbacks)
|
||||
: 回调函数是自定义函数,它可以访问整个校验对象。
|
||||
回调函数的返回值会被忽略,因此,当校验错误时回调函数必须手动的使用 [Validate::error] 添加错误到对象中。
|
||||
|
||||
[!!] 注意 [Validate] 的 callbacks 和 [PHP callbacks](http://php.net/manual/language.pseudo-types.php#language.types.callback) 是完全不同的两个方法。
|
||||
|
||||
如果想把添加的过滤器,规则或回调函数应用到所有的定义的字段需要设置字段名为 `TRUE` 。
|
||||
|
||||
**[Validate] 对象会移除所有未设置标签,过滤器,规则或回调函数的字段。以此防止未被验证的字段发生校验错误。**
|
||||
|
||||
使用 [Validate::factory] 方法创建校验对象:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
|
||||
[!!] 提示 `$post` 对象将会被用于本教程的其他实例中。
|
||||
|
||||
### 默认规则
|
||||
|
||||
校验默认提供的规则:
|
||||
|
||||
规则名称 | 函数
|
||||
------------------------- |-------------------------------------------------
|
||||
[Validate::not_empty] | 值不能为空值
|
||||
[Validate::regex] | 值使用正则表达式匹配
|
||||
[Validate::min_length] | 值的最小长度
|
||||
[Validate::max_length] | 值的最大长度
|
||||
[Validate::exact_length] | 值的长度必须是这里指定的长度
|
||||
[Validate::email] | 值必须是 Email 地址
|
||||
[Validate::email_domain] | 检查 Email 的域是否存在
|
||||
[Validate::url] | 值必须是 URL
|
||||
[Validate::ip] | 值必须是 IP 地址
|
||||
[Validate::phone] | 值必须是电话号码
|
||||
[Validate::credit_card] | 值必须是信用卡号
|
||||
[Validate::date] | 值必须是日期(时间)
|
||||
[Validate::alpha] | 仅允许英文字母
|
||||
[Validate::alpha_dash] | 仅允许英文字母和连词符号(-)
|
||||
[Validate::alpha_numeric] | 仅允许英文字母和数字
|
||||
[Validate::digit] | 仅允许整数
|
||||
[Validate::decimal] | 值必须是小数或浮点数
|
||||
[Validate::numeric] | 仅允许数字
|
||||
[Validate::range] | 值必须是某一范围内的值
|
||||
[Validate::color] | 值必须是有效的 HEX 颜色
|
||||
[Validate::matches] | 值必须匹配其他字段的值
|
||||
|
||||
[!!] 任何存在于 [Validate] 类中的方法都可以在不指定完整回调的情况下用于校验规则。
|
||||
比如,添加 `'not_empty'` 和 `array('Validate', 'not_empty')` 是等同的。
|
||||
|
||||
## 添加过滤器
|
||||
|
||||
所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数:
|
||||
|
||||
$object->filter($field, $callback, $parameter);
|
||||
|
||||
过滤器修改字段值之前请仔细检查规则或回调函数。
|
||||
|
||||
如果要转换 "username" 字段的值为全小写:
|
||||
|
||||
$post->filter('username', 'strtolower');
|
||||
|
||||
如果要对所有字段移除左右*所有*空格:
|
||||
|
||||
$post->filter(TRUE, 'trim');
|
||||
|
||||
## 添加规则
|
||||
|
||||
所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数:
|
||||
|
||||
$object->rule($field, $callback, $parameter);
|
||||
|
||||
### 实例
|
||||
|
||||
任何函数添加到 `Validate` 类都可以通过调用一个规则而不必指定 `Validate` 类:
|
||||
|
||||
$post
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty');
|
||||
|
||||
任何 PHP 可用的函数也可以当作规则。比如,如果我们要检测用户是否使用 SSL:
|
||||
|
||||
$post->rule('use_ssl', 'in_array', array(array('yes', 'no')));
|
||||
|
||||
[!!] 注意:所有的参数类数组都必须在一个数组内!
|
||||
|
||||
所有其他自定义的规则也可以作为回调函数添加进来:
|
||||
|
||||
$post->rule('username', array($model, 'unique_username'));
|
||||
|
||||
回调方法 `$model->unique_username()` 的代码如下:
|
||||
|
||||
public function unique_username($username)
|
||||
{
|
||||
// 检测用户名是否存在于数据库
|
||||
return ! DB::select(array(DB::expr('COUNT(username)'), 'total'))
|
||||
->from('users')
|
||||
->where('username', '=', $username)
|
||||
->execute()
|
||||
->get('total');
|
||||
}
|
||||
|
||||
[!!] 自定义规则可以设置许多额外的检测以可用于多种用途。这些方法运行存在于一个模型(model)中,或者是定义在任意一个类中。
|
||||
|
||||
## 添加回调函数
|
||||
|
||||
所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数:
|
||||
|
||||
$object->callback($field, $callback);
|
||||
|
||||
[!!] 不同的过滤器和规则,没有参数也可以传递到回调函数之中。
|
||||
|
||||
如果用户的密码必须是哈希值,我们可以使用回调函数哈希其值:
|
||||
|
||||
$post->callback('password', array($model, 'hash_password'));
|
||||
|
||||
假设 `$model->hash_password()` 方法是类似这样定义的:
|
||||
|
||||
public function hash_password(Validate $array, $field)
|
||||
{
|
||||
if ($array[$field])
|
||||
{
|
||||
// 如果存在此字段进行哈希操作
|
||||
$array[$field] = sha1($array[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
# 一个完整的例子
|
||||
|
||||
首先,我们使用 [View] 创建一个 HTML 表单。假设文件存放于 `application/views/user/register.php`:
|
||||
|
||||
<?php echo Form::open() ?>
|
||||
<?php if ($errors): ?>
|
||||
<p class="message">操作发生问题,请仔细检查并保证填写正确。</p>
|
||||
<ul class="errors">
|
||||
<?php foreach ($errors as $message): ?>
|
||||
<li><?php echo $message ?></li>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<dl>
|
||||
<dt><?php echo Form::label('username', '用户名') ?></dt>
|
||||
<dd><?php echo Form::input('username', $post['username']) ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('password', '密码') ?></dt>
|
||||
<dd><?php echo From::password('password') ?></dd>
|
||||
<dd class="help">密码必须保证至少六位字符</dd>
|
||||
<dt><?php echo Form::label('confirm', '重复上面密码') ?></dt>
|
||||
<dd><?php echo Form::password('confirm') ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('use_ssl', '使用 SSL') ?></dt>
|
||||
<dd><?php echo Form::select('use_ssl', array('yes' => '总是使用 SSL', 'no' => '仅当需要的时候'), $post['use_ssl']) ?></dd>
|
||||
<dd class="help">鉴于安全起见,SSL 一般用于支付时使用</dd>
|
||||
</dl>
|
||||
|
||||
<?php echo Form::submit(NULL, '申请') ?>
|
||||
<?php echo Form::close() ?>
|
||||
|
||||
[!!] 本例子我们使用了 [Form] 辅助函数生成表单。使用 [Form] 从而代替手写 HTML 代码的好处在于所有输入项都会严格处理。
|
||||
如果你喜欢手写 HTML,那请记得使用 [HTML::chars] 方法来转移用户输入。
|
||||
|
||||
接下来,我们开始编写控制器的代码来处理注册过程。假设文件存放于 `application/classes/controller/user.php`:
|
||||
|
||||
class Controller_User extends Controller {
|
||||
|
||||
public function action_register()
|
||||
{
|
||||
$user = Model::factory('user');
|
||||
|
||||
$post = Validate::factory($_POST)
|
||||
->filter(TRUE, 'trim')
|
||||
|
||||
->filter('username', 'strtolower')
|
||||
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
->rule('username', array($user, 'unique_username'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty')
|
||||
->rule('use_ssl', 'in_array', array(array('yes', 'no')))
|
||||
|
||||
->callback('password', array($user, 'hash_password'));
|
||||
|
||||
if ($post->check())
|
||||
{
|
||||
// 确保数据都通过了校验后执行注册用户
|
||||
$user->register($post);
|
||||
|
||||
// 通常在注册成功后会调整到登录前的页面
|
||||
URL::redirect('user/profile');
|
||||
}
|
||||
|
||||
// 校验失败,获得错误提示
|
||||
$errors = $post->errors('user');
|
||||
|
||||
// 显示用户注册的表单
|
||||
$this->request->response = View::factory('user/register')
|
||||
->bind('post', $post)
|
||||
->bind('errors', $errors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
另外我们还需要有一个 user 模型,假设文件存放于 `application/classes/model/user.php`:
|
||||
|
||||
class Model_User extends Model {
|
||||
|
||||
public function register($array)
|
||||
{
|
||||
// 创建一条新纪录
|
||||
$id = DB::insert(array_keys($array))
|
||||
->values($array)
|
||||
->execute();
|
||||
|
||||
// 保存新用户的 id 到 cookie
|
||||
cookie::set('user', $id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
一个简单的用户注册的例子就这么完成了!
|
@@ -0,0 +1,15 @@
|
||||
# 跨站脚本(XSS)安全
|
||||
|
||||
首先大家先要了解什么是 [XSS](http://wikipedia.org/wiki/Cross-Site_Scripting) 之后才能更好的保护自己。XSS 只能在 HTML 代码中才能触发,可能通过表单的输入或者从数据库结果显示。任何全局变量包括客户信息都可能被感染。这包括 `$_GET`,`$_POST` 和 `$_COOKIE` 中的数据。
|
||||
|
||||
## 预防措施
|
||||
|
||||
这里有一些简单的方法可以预防你的程序不受 XSS 的侵害。第一个方法是使用 [Security::xss] 方法处理所有全局变量的输入数据。如果你不想让变量里有 HTML 代码,你可以使用 [strip_tags](http://php.net/strip_tags) 从值中移除所有的 HTML 标签。
|
||||
|
||||
[!!] 如果用户提交 HTML 到你的程序之中,最好的推荐方法是使用类似 [HTML Purifier](http://htmlpurifier.org/) 或 [HTML Tidy](http://php.net/tidy) 这样的 HTML 代码清理工具。
|
||||
|
||||
第二个方法是转义输入的 HTML 代码。[HTML] 类提供生成大多数的标签,其中包括脚本(script)和样式表(stylesheet)链接,超级链接,图片,邮箱(emailto)链接。任何不可信的内容都会使用 [HTML::chars] 去转义。
|
||||
|
||||
## 参考资料
|
||||
|
||||
* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
@@ -0,0 +1,248 @@
|
||||
# 数据库 {#top}
|
||||
|
||||
Kohana 3.0 采用了更加健壮的模块方式开发。默认情况下数据库模块支持 [MySQL](http://php.net/mysql) 和 [PDO](http://php.net/pdo) 两种驱动方式。
|
||||
|
||||
默认 Kohana 3.0 中包含了数据库模块,但是使用之前必须在 `application/bootstrap.php` 文件中的 [Kohana::modules] 方法中开启它。
|
||||
|
||||
Kohana::modules(array(
|
||||
...
|
||||
'database' => MODPATH.'database',
|
||||
...
|
||||
));
|
||||
|
||||
## 配置 {#configuration}
|
||||
|
||||
开启模块后接着需要配置数据库,这样才能保证数据库的正常连接。比如说配置文件存放在 `modules/database/config/database.php` 文件中。
|
||||
|
||||
数据库配置组的结构,我们称之为 "instance",就像下面这个样子:
|
||||
|
||||
string INSTANCE_NAME => array(
|
||||
'type' => string DATABASE_TYPE,
|
||||
'connection' => array CONNECTION_ARRAY,
|
||||
'table_prefix' => string TABLE_PREFIX,
|
||||
'charset' => string CHARACTER_SET,
|
||||
'profiling' => boolean QUERY_PROFILING,
|
||||
),
|
||||
|
||||
[!!] 配置文件里可以定义多个 instances 配置组。
|
||||
|
||||
重点了解一下各项设置的含义。
|
||||
|
||||
INSTANCE_NAME
|
||||
: 配置组的名称,任意命名,但是最好保留一个名为 "default" 的默认连接。
|
||||
|
||||
DATABASE_TYPE
|
||||
: 数据库驱动类型。Kohana 目前支持 "mysql" 和 "pdo" 两种驱动。
|
||||
|
||||
CONNECTION_ARRAY
|
||||
: 配置上述驱动的连接项。(驱动连接项在[下面](#connection_settings)有说明)
|
||||
|
||||
TABLE_PREFIX
|
||||
: 表前缀,用于通过 [查询器](#query_building) 添加到所有的表名。
|
||||
|
||||
QUERY_PROFILING
|
||||
: 开始数据库查询的 [profiling](debugging.profiling)。
|
||||
|
||||
### 范例
|
||||
|
||||
范例中共给出了两种 MySQL 连接:一个是本地,一个是远程。
|
||||
|
||||
return array
|
||||
(
|
||||
'default' => array
|
||||
(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'dbuser',
|
||||
'password' => 'mypassword',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'my_db_name',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
'remote' => array(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => '55.55.55.55',
|
||||
'username' => 'remote_user',
|
||||
'password' => 'mypassword',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'my_remote_db_name',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
### 连接设置 {#connection_settings}
|
||||
|
||||
每种数据库驱动的连接方式各有不同。
|
||||
|
||||
#### MySQL
|
||||
|
||||
在 `connection` 数组中 MySQL 数据库可接受下面选项:
|
||||
|
||||
类型 | 选项 | 描述 | 默认值
|
||||
----------|------------|----------------------------| -------------------------
|
||||
`string` | hostname | Hostname of the database | `localhost`
|
||||
`integer` | port | Port number | `NULL`
|
||||
`string` | socket | UNIX socket | `NULL`
|
||||
`string` | username | Database username | `NULL`
|
||||
`string` | password | Database password | `NULL`
|
||||
`boolean` | persistent | Persistent connections | `FALSE`
|
||||
`string` | database | Database name | `kohana`
|
||||
|
||||
#### PDO
|
||||
|
||||
在 `connection` 数组中 PDO 数据库可接受下面选项:
|
||||
|
||||
类型 | 选项 | 描述 | 默认值
|
||||
----------|------------|----------------------------| -------------------------
|
||||
`string` | dsn | PDO data source identifier | `localhost`
|
||||
`string` | username | Database username | `NULL`
|
||||
`string` | password | Database password | `NULL`
|
||||
`boolean` | persistent | Persistent connections | `FALSE`
|
||||
|
||||
[!!] 如果你使用的是 PDO 而且并不确定如何去配置 `dsn` 选项,请查阅 [PDO::__construct](http://php.net/pdo.construct) 的相关资料。
|
||||
|
||||
## 连接并实例化 {#connections}
|
||||
|
||||
每个配置组都可以当作数据库的实例化对象。每个实例化都是通过调用 [Database::instance] 方法来访问:
|
||||
|
||||
$default = Database::instance();
|
||||
$remote = Database::instance('remote');
|
||||
|
||||
关闭数据库连接的最简单的方法(销毁对象):
|
||||
|
||||
unset($default, Database::$instances['default']);
|
||||
|
||||
如果你想关闭所有数据库的实例化只需:
|
||||
|
||||
Database::$instances = array();
|
||||
|
||||
## 如何查询 {#making_queries}
|
||||
|
||||
这里共有两种不同的方法进行查询。最简单的一次查询方式是通过 [DB::query] 使用 [Database_Query] 来创建查询。这些查询被称之为 "预处理语句",并且允许设置的查询参数自动的转义。而第二种查询方式是通过方法调用来组建查询。它们都是通过[查询器](#query_building) 完成。
|
||||
|
||||
[!!] 所有的查询都必须调用 `execute` 方法才能进行运行查询,可接受一个 [Database] 对象或者实例化名称。详情请参见 [Database_Query::execute]。
|
||||
|
||||
### 预处理语句
|
||||
|
||||
使用预处理语句可以让你手动编写 SQL 语句的同时还能自动转义查询的值以防止 [SQL 注入](http://wikipedia.org/wiki/SQL_Injection)。首先我们先来一个简单的查询:
|
||||
|
||||
$query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user');
|
||||
|
||||
[DB::query] factory 方法为我们创建了一个新的 [Database_Query] 类并允许串连(chaining)。查询语句包含一个 `:user` 参数,这个参数我们可以分配给它一个值:
|
||||
|
||||
$query->param(':user', 'john');
|
||||
|
||||
[!!] 参数名称可以是任意的可以使用 [strtr](http://php.net/strtr) 替换的字符串。强烈建议**不要**使用美元符号当作参数名以免混淆。
|
||||
|
||||
如果你想显示 SQL 执行的语句,只需要简单的强制转换对象为字符串即可:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// 应该显示:
|
||||
// SELECT * FROM users WHERE username = 'john'
|
||||
|
||||
如果你想更新 `:user` 参数只需要再次调用 [Database_Query::param] 即可:
|
||||
|
||||
$query->param(':user', $_GET['search']);
|
||||
|
||||
[!!] 如果你想一次设置多个参数,你需要使用 [Database_Query::parameters]。
|
||||
|
||||
当你分配完毕每个参数之后,你只需要执行下面的方法来执行查询语句:
|
||||
|
||||
$query->execute();
|
||||
|
||||
使用[变量引用]((http://php.net/language.references.whatdo)) 也可以绑定参数到一个变量中。当多次执行同条语句的时候是非常管用的:
|
||||
|
||||
$query = DB::query(Database::INSERT, 'INSERT INTO users (username, password) VALUES (:user, :pass)')
|
||||
->bind(':user', $username)
|
||||
->bind(':pass', $password);
|
||||
|
||||
foreach ($new_users as $username => $password)
|
||||
{
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
在上面的例子中,变量 `$username` 和 `$password` 在每次使用 `foreach` 语句循环的时候都会改变。如果变量改变了,那么语句中的参数 `:user` 和 `:pass` 也会跟着改变。这种方法使用得当的话是非常节省时间的。
|
||||
|
||||
### 查询器 {#query_building}
|
||||
|
||||
使用对象和方法动态查询使得查询语句可以以一种不可知论的方法迅速的组建起来。查询器也添加了和值引用一样好的标识符(表和列名)引用。
|
||||
|
||||
[!!] 目前为止,查询器无法有效的和预处理语句组合。
|
||||
|
||||
#### SELECT
|
||||
|
||||
每种数据库查询类型都是用过不同的类引用,它们每一个都有自己的方法。比如,创建一个 SELECT 查询,我们需要使用 [DB::select]:
|
||||
|
||||
$query = DB::select()->from('users')->where('username', '=', 'john');
|
||||
|
||||
默认情况下,[DB::select] 会选择所有的列(`SELECT * ...`),但是你也可以指定返回的某些列:
|
||||
|
||||
$query = DB::select('username', 'password')->from('users')->where('username', '=', 'john');
|
||||
|
||||
现在让我们花一点时间看看方法是如何串连完成的。首先,我们使用 [DB::select] 方法创建了一个选择对象。接着,我们使用 `from` 方法选择表。最后我们使用 `where` 方法查询一个指定的记录。好了,执行之后我们看看执行了怎么样的一条 SQL 语句,还是老方法,强制转换对象为字符串:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// 应该显示:
|
||||
// SELECT `username`, `password` FROM `users` WHERE `username` = 'john'
|
||||
|
||||
注意列名,表名是如何和值很好的转义啊?这就是使用查询器最重要的好处。
|
||||
|
||||
查询的时候它也支持 `AS` 方式的别名:
|
||||
|
||||
$query = DB::select(array('username', 'u'), array('password', 'p'))->from('users');
|
||||
|
||||
生成的 SQL 语句:
|
||||
|
||||
SELECT `username` AS `u`, `password` AS `p` FROM `users`
|
||||
|
||||
#### INSERT
|
||||
|
||||
向数据库插入一条记录,我们使用 [DB::insert] 方法创建一条 INSERT 语句:
|
||||
|
||||
$query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd'));
|
||||
|
||||
生成的 SQL 语句:
|
||||
|
||||
INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd')
|
||||
|
||||
#### UPDATE
|
||||
|
||||
更新已存在的记录,我们使用 [DB::update] 方法创建一条 UPDATE 语句:
|
||||
|
||||
$query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john');
|
||||
|
||||
生成的 SQL 语句:
|
||||
|
||||
UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john'
|
||||
|
||||
#### DELETE
|
||||
|
||||
删除已存在的记录,我们使用 [DB::delete] 方法创建一条 DELETE 语句:
|
||||
|
||||
$query = DB::delete('users')->where('username', 'IN', array('john', 'jane'));
|
||||
|
||||
生成的 SQL 语句:
|
||||
|
||||
DELETE FROM `users` WHERE `username` IN ('john', 'jane')
|
||||
|
||||
#### 数据库函数 {#database_functions}
|
||||
|
||||
有些时候,你可以会碰到这样的一个情况:当你需要在查询时调用 `COUNT` 或者一些其他数据库自身函数。其实查询器可以通过两种方法支持这些函数。第一种是使用别名引用:
|
||||
|
||||
$query = DB::select(array('COUNT("username")', 'total_users'))->from('users');
|
||||
|
||||
这看起来十分的相似于 `AS` 别名,但是注意列名是通过双引号括起来的。任何时候一个带有双引号的值出现在列名内部的时候,这部分在双引号内部的引用**仅仅**只能被转义。上面的查询方法生成的 SQL 语句:
|
||||
|
||||
SELECT COUNT(`username`) AS `total_users` FROM `users`
|
||||
|
||||
#### 复杂的表达式
|
||||
|
||||
别名引用可以解决大部分的问题。但是有时你可能因需要复杂的表达式陷入困境。由于这些原因,你可以使用数据库表达式 [DB::expr] 创建。数据库表达式可以作为直接输入而并不会执行转义。
|
143
includes/kohana/modules/userguide/guide/zh-cn/tutorials.git.md
Normal file
143
includes/kohana/modules/userguide/guide/zh-cn/tutorials.git.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 使用 Git 开发
|
||||
|
||||
Kohana 使用 [git](http://git-scm.com/) 作为版本控制并托管在 [github](http://github.com/kohana) 网站上面。本教程将会讲解如何让你使用 Git 并从 github 上部署一个简单的应用。
|
||||
|
||||
## 安装配置 Git
|
||||
|
||||
### 安装 Git
|
||||
|
||||
- OSX: [Git-OSX](http://code.google.com/p/git-osx-installer/)
|
||||
- Windows: [Msygit](http://code.google.com/p/msysgit/)
|
||||
- 或者从 [Git 官网](http://git-scm.com/) 下载并手动安装(步骤请参考 Git 官网)
|
||||
|
||||
### 设置全局配置
|
||||
|
||||
git config --global user.name "你的名字"
|
||||
git config --global user.email "你的邮箱"
|
||||
|
||||
### 附加偏好设置
|
||||
|
||||
为了让 git 命令和版本库在命令行达到更好的视觉效果,你可以额外设置:
|
||||
|
||||
git config --global color.diff auto
|
||||
git config --global color.status auto
|
||||
git config --global color.branch auto
|
||||
|
||||
### 设置自动补全
|
||||
|
||||
[!!] 以下步骤仅用于 OSX 机器
|
||||
|
||||
根据下面步骤一步步执行,全部完成之后自动补全就可以在 git 环境下工作了
|
||||
|
||||
cd /tmp
|
||||
git clone git://git.kernel.org/pub/scm/git/git.git
|
||||
cd git
|
||||
git checkout v`git --version | awk '{print $3}'`
|
||||
cp contrib/completion/git-completion.bash ~/.git-completion.bash
|
||||
cd ~
|
||||
rm -rf /tmp/git
|
||||
echo -e "source ~/.git-completion.bash" >> .profile
|
||||
|
||||
### 总是使用 LF 作为换行符
|
||||
|
||||
此设置主要用于 Kohana。如果你愿意捐赠代码至社区请遵循此约定。
|
||||
|
||||
git config --global core.autocrlf input
|
||||
git config --global core.savecrlf true
|
||||
|
||||
[!!] 关于换行符的更多信息请参见 [github](http://help.github.com/dealing-with-lineendings/)
|
||||
|
||||
### 参考资料
|
||||
|
||||
- [Git Screencasts](http://www.gitcasts.com/)
|
||||
- [Git Reference](http://gitref.org/)
|
||||
- [Pro Git book](http://progit.org/book/)
|
||||
|
||||
## 部署系统结构
|
||||
|
||||
[!!] 开始本教程前务必保证开发环境以及设置完毕,接下来我们要做一个可以通过 <http://localhost/gitorial/> 访问的新应用。
|
||||
|
||||
打开你的控制台(译者:Windows 平台为命令提示符,*nux 平台为终端),创建并切换到 `gitorial` 空目录下面(译者:此目录即为新应用的目录),执行 `git init`。这是为当前目录创建一个新的 git 空版本库。
|
||||
|
||||
下一步,我们为 `system` 目录要创建一个 [submodule](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html)(子模块)。访问 <http://github.com/kohana/core> 页面并复制克隆(Clone) URL:
|
||||
|
||||

|
||||
|
||||
现在使用复制后的 URL 去创建 `system` 子模块:
|
||||
|
||||
git submodule add git://github.com/kohana/core.git system
|
||||
|
||||
[!!] 上面的链接是 Kohana 为下一个稳定版本准备的当前的开发版本。开发版本几乎是可以拿来做开发的,他拥有当前稳定版本同样的 API 和一些补丁修复。
|
||||
|
||||
现在,我们准备添加自己开发所需的子模块。比如你可能需要使用 [Database](http://github.com/kohana/database) 模块:
|
||||
|
||||
git submodule add git://github.com/kohana/database.git modules/database
|
||||
|
||||
添加子模块之后,我们必须让其初始化:
|
||||
|
||||
git submodule init
|
||||
|
||||
子模块我们已经添加完毕,接着我们去提交当前版本:
|
||||
|
||||
git commit -m 'Added initial submodules'
|
||||
|
||||
下一步,创建应用文件结构。下面的是最低要求:
|
||||
|
||||
mkdir -p application/classes/{controller,model}
|
||||
mkdir -p application/{config,views}
|
||||
mkdir -m 0777 -p application/{cache,logs}
|
||||
|
||||
如果你执行 `find application` 你应该会看到:
|
||||
|
||||
application
|
||||
application/cache
|
||||
application/config
|
||||
application/classes
|
||||
application/classes/controller
|
||||
application/classes/model
|
||||
application/logs
|
||||
application/views
|
||||
|
||||
如果我们不想让 git 去追踪日志(log)或者缓存(Cache)文件,我们需要为每个目录添加一个 `.gitignore` 文件。它会忽略所有的非隐藏文件:
|
||||
|
||||
echo '[^.]*' > application/{logs,cache}/.gitignore
|
||||
|
||||
[!!] Git 会忽略空目录,所有我们添加 `.gitignore` 文件以保证 git 会追踪其目录,但是不会追踪目录下面的文件。
|
||||
|
||||
现在我们还缺 `index.php` 和 `bootstrap.php` 文件:
|
||||
|
||||
wget http://github.com/kohana/kohana/raw/master/index.php
|
||||
wget http://github.com/kohana/kohana/raw/master/application/bootstrap.php -O application/bootstrap.php
|
||||
|
||||
再次提交:
|
||||
|
||||
git add application
|
||||
git commit -m 'Added initial directory structure'
|
||||
|
||||
所有的工作都完成了!你现在可以使用 Git 作为版本控制开发 Kohana 应用了。
|
||||
|
||||
## 更新子模块
|
||||
|
||||
有时候你可能也需要更新你的子模块。更新所有子模块至最新的 `HEAD` 版本:
|
||||
|
||||
git submodule foreach 'git checkout master && git pull origin master'
|
||||
|
||||
更新单个子模块,比如 `system`:
|
||||
|
||||
cd system
|
||||
git checkout master
|
||||
git pull origin master
|
||||
cd ..
|
||||
git add system
|
||||
git commit -m 'Updated system to latest version'
|
||||
|
||||
如果你要更新单个子模块到指定的版本库:
|
||||
|
||||
cd modules/database
|
||||
git pull origin master
|
||||
git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b
|
||||
cd ../..
|
||||
git add database
|
||||
git commit -m 'Updated database module'
|
||||
|
||||
完成!
|
@@ -0,0 +1,106 @@
|
||||
# Hello, World
|
||||
|
||||
差不多每个框架提供的教程实例都会包括 Hello,World 这样的例子,于是我们也遵循这样的传统!
|
||||
|
||||
下面我们将要创建一个非常非常基础的 Hello,World,然后我们将它慢慢扩展符合 MVC 架构的样例。
|
||||
|
||||
## 基础框架
|
||||
|
||||
首先,我们先要创建一个控制器,让 Kohana 可用于处理请求。
|
||||
|
||||
在 application 目录下创建 `application/classes/controller/hello.php` 文件并敲入下面代码:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller
|
||||
{
|
||||
function action_index()
|
||||
{
|
||||
echo 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
接着,让我们讲解一下上面的代码:
|
||||
|
||||
`<?php defined('SYSPATH') OR die('No Direct Script Access');`
|
||||
: 首先你应该知道代码开头是 PHP 的开始标签(如果你不知道请先好好[学习 PHP](http://php.net))。紧跟着它后面的是一段检测代码,以它来确保此文件是由 Kohana 来加载的。它会阻止访问者由 URL 上面直接访问本文件。
|
||||
|
||||
`Class Controller_Hello extends Controller`
|
||||
: 这行代码是声明我们的控制器,每个控制器类都必须使用 `Controller_` 作为前缀,下划线的作用是划定文件夹路径下的控制器(详情请参见 [约定和样式](start.conventions))。每个控制器都必须继承基控制器 `Controller` 类,它提供了一个控制器的标准结构。
|
||||
|
||||
|
||||
`function action_index()`
|
||||
: 这里在我们的控制器定义了一个 "index" 动作。如果用户没有指定动作,那么 Kohana 默认调用这个动作。(详情请参见[路由,URLs 和链接](tutorials.urls))
|
||||
|
||||
`echo 'hello, world!';`
|
||||
: 这行就是输出 Hello world 的语句!
|
||||
|
||||
现在,打开浏览器敲入 http://localhost/index.php/hello 你将会看到:
|
||||
|
||||

|
||||
|
||||
## 继续增强
|
||||
|
||||
我们在上一节所做的是创建一个*非常*基础的 Kohana 应用是多么的容易。(实际上它太基本了以至于你可能不会再敲一次!)
|
||||
|
||||
如果你曾经听说过的 MVC 或者你可能已经意识到在控制器中输出内容是严格遵循 MVC 原则的。
|
||||
|
||||
使用 MVC 框架编程的正确方法是使用_视图_来处理程序的显示,而且最好是使用控制器来做 – 控制请求的流量!
|
||||
|
||||
让我们略微的改造原始的代码:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
public $template = 'site';
|
||||
|
||||
function action_index()
|
||||
{
|
||||
$this->template->message = 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
`extends Controller_Template`
|
||||
: 现在我们继承了模板控制器(Template Controller),使用它可以更加方便在控制器中使用视图。
|
||||
|
||||
`public $template = 'site';`
|
||||
: 模板控制器需要知道你想要使用什么模板文件。它会自动加载这个变量中定义的视图并返回一个视图对象。
|
||||
|
||||
`$this->template->message = 'hello, world!';`
|
||||
: `$this->template` 是我们站点模板的视图对象引用。这里我们分配一个名为 "message" 的变量其值为 "hello, world!" 到视图中。
|
||||
|
||||
现在让我们尝试运行代码...
|
||||
|
||||
<div>{{userguide/examples/hello_world_error}}</div>
|
||||
|
||||
出于某种原因 Kohana 会抛出一个不稳定的而没有正常显示我们期望的信息。
|
||||
|
||||
如果我们仔细查看错误信息,我们可以发现 View 库无法找到我们设定的模板文件,这可能是我们还没有创建它 – *doh*!(译注:doh 表达当发现事情朝坏的、不随人意的方向发展或某人说了傻话、做了蠢事时的情绪低落)
|
||||
|
||||
马上开始创建视图文件 `application/views/site.php`:
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>We've got a message for you!</title>
|
||||
<style type="text/css">
|
||||
body {font-family: Georgia;}
|
||||
h1 {font-style: italic;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><?php echo $message; ?></h1>
|
||||
<p>We just wanted to say it! :)</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
再次刷新刚才的错误页面,怎么样看到正确的结果了吧:
|
||||
|
||||

|
||||
|
||||
## 第三阶段 – 成果!
|
||||
|
||||
在本教程中你已经学会如何创建和使用控制器,以及使用视图分离逻辑来显示视图。
|
||||
|
||||
这绝对是一个非常基本教程来介绍如何使用 Kohana 工作,且它根本就不会影响你的潜力使用它来开发应用。
|
299
includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md
Normal file
299
includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# ORM {#top}
|
||||
|
||||
Kohana 3.0 包含一个强劲的 ORM 扩展,作用于记录模式,数据库内省来确定模型的列表。
|
||||
|
||||
ORM 扩展默认包含在 Kohana 3.0 之中,但是如要使用它则需要先开启它。修改 `application/bootstrap.php` 文件中的 [Kohana::modules] 方法并加载 ORM 扩展:
|
||||
|
||||
Kohana::modules(array(
|
||||
...
|
||||
'orm' => MODPATH.'orm',
|
||||
...
|
||||
));
|
||||
|
||||
## 配置 {#configuration}
|
||||
|
||||
通过一些配置 ORM 才能工作。通过在模型类继承 ORM:
|
||||
|
||||
class Model_User extends ORM
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
上面的例子中,模型会寻找默认数据库的 `users` 表。
|
||||
|
||||
### 模型配置属性
|
||||
|
||||
下面的属性是用于配置每个模型的:
|
||||
|
||||
类型 | 属性 | 描述 | 默认值
|
||||
----------|---------------------|----------------------------------| -------------------------
|
||||
`string` | _table_name | 表名 | `singular model name`
|
||||
`string` | _db | 数据库配置名 | `default`
|
||||
`string` | _primary_key | 主键 | `id`
|
||||
`string` | _primary_val | 主键值 | `name`
|
||||
`bool` | _table_names_plural | 表名是否是复数形式 | `TRUE`
|
||||
`array` | _sorting | 列名 => 排序方向的数组 | `primary key => ASC`
|
||||
`string` | _foreign_key_suffix | 外键的后缀 | `_id`
|
||||
|
||||
## 使用 ORM
|
||||
|
||||
### 加载一条记录
|
||||
|
||||
通过调用 [ORM::factory] 或 [ORM::__construct] 方法创建模型的实例化:
|
||||
|
||||
$user = ORM::factory('user');
|
||||
// 或者
|
||||
$user = new Model_User();
|
||||
|
||||
构造函数和 factory 方法也接受一个主键值来加载模型数据:
|
||||
|
||||
// 加载 ID 为 5 的用户
|
||||
$user = ORM::factory('user', 5);
|
||||
|
||||
// 检查用户是否加载成功
|
||||
if ($user->loaded()) { ... }
|
||||
|
||||
你同样可以使用传递键-值型数组的数据对象去加载记录:
|
||||
|
||||
// 加载 email 为 oe@example.com 的用
|
||||
$user = ORM::factory('user', array('email' => 'joe@example.com'));
|
||||
|
||||
### 搜索记录
|
||||
|
||||
ORM 支持大多数的 [Database] 方法来强劲驱动搜索模型中的数据。ORM 类的 `_db_methods` 属性列出了所有支持调用的方法列表。记录的搜索可以通过 [ORM::find] 和 [ORM::find_all] 方法调用获得。
|
||||
|
||||
// 搜索活跃用户中名为 Bob 的第一条记录
|
||||
$user = ORM::factory('user')
|
||||
->where('active', '=', TRUE)
|
||||
->where('name', '=', 'Bob')
|
||||
->find();
|
||||
|
||||
// 搜索名为 Bob 的所有用户
|
||||
$users = ORM::factory('user')
|
||||
...
|
||||
->find_all();
|
||||
|
||||
当你使用 [ORM::find_all] 搜索一批记录模型,你可以使用迭代从数据库结果中获取每条记录模型:
|
||||
|
||||
foreach ($users as $user)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
ORM 一个强大的特性是 [ORM::as_array] 方法,它把返回的记录集转为为一个数组。如果使用了 [ORM::find_all] 所有的记录都会以数组的形式返回。
|
||||
对于选择列的时候是非常好用的:
|
||||
|
||||
// 显示选择列的用户名 (使用 id 作为其值)
|
||||
form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username') ...
|
||||
|
||||
### 记录数
|
||||
|
||||
使用 [ORM::count_all] 方法返回查询返回记录集的记录数。
|
||||
|
||||
// 用户的记录数
|
||||
$count = ORM::factory('user')->where('active', '=', TRUE)->count_all();
|
||||
|
||||
如果你想在特定子集的查询语句中统计所有用户的记录数,在调用 `count_all` 方法之前先调用 [ORM::reset] 方法并赋值 `FALSE`:
|
||||
|
||||
$user = ORM::factory('user');
|
||||
|
||||
// 用户的总数 (reset FALSE prevents the query object from being cleared)
|
||||
$count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all();
|
||||
|
||||
// 仅返回前 10 条记录的记录数
|
||||
$users = $user->limit(10)->find_all();
|
||||
|
||||
### 取出模型属性
|
||||
|
||||
所有的模型属性都可以通过 PHP 的魔法方法 `__get` 和 `__set` 得到读写权。
|
||||
|
||||
$user = ORM::factory('user', 5);
|
||||
|
||||
// 输出用户名
|
||||
echo $user->name;
|
||||
|
||||
// 更改用户名
|
||||
$user->name = 'Bob';
|
||||
|
||||
假如保存的信息/属性并不存在于模型表中,使用 `_ignored_columns` 来忽略数据成员。
|
||||
|
||||
class Model_User extends ORM
|
||||
{
|
||||
...
|
||||
protected $_ignored_columns = array('field1', 'field2', ...)
|
||||
...
|
||||
}
|
||||
|
||||
使用 [ORM::values] 方法设置键-值型数组:
|
||||
|
||||
$user->values(array('username' => 'Joe', 'password' => 'bob'));
|
||||
|
||||
### 创建并存储记录
|
||||
|
||||
[ORM::save] 方法既可以用于创建新记录也可作用于更新现有记录。
|
||||
|
||||
// 创建新记录
|
||||
$user = ORM::factory('user');
|
||||
$user->name = 'New user';
|
||||
$user->save();
|
||||
|
||||
// 更新现有记录
|
||||
$user = ORM::factory('user', 5);
|
||||
$user->name = 'User 2';
|
||||
$user->save();
|
||||
|
||||
// 检查记录是否保存成功
|
||||
if ($user->saved()) { ... }
|
||||
|
||||
你也可以使用 [ORM::save_all] 方法来更新多条记录:
|
||||
|
||||
$user = ORM::factory('user');
|
||||
$user->name = 'Bob';
|
||||
|
||||
// 更新所有结果记录的名字为 'Bob'
|
||||
$user->where('active', '=', TRUE)->save_all();
|
||||
|
||||
#### 使用 `Updated` 和 `Created` 列
|
||||
|
||||
`_updated_column` 和 `_created_column` 变量是用于当模型更新或插入新纪录的时候自动更新设置的字段值。默认没有使用。如果你想使用:
|
||||
|
||||
// date_created 列用于储存创建的时间,使用 TRUE 保存的是时间戳(timestamp)
|
||||
protected $_created_column = array('date_created' => TRUE);
|
||||
|
||||
// date_modified 列用于储存最后修改时间。这里的时间设置为使用 date() 格式后的字符串
|
||||
protected $_updated_column = array('date_modified' => 'm/d/Y');
|
||||
|
||||
### 删除记录
|
||||
|
||||
删除记录可以使用 [ORM::delete] 和 [ORM::delet_all] 方法。这两个方法的使用和上面 存储记录 方法类似,但有一点不同的是 [ORM::delete] 方法带有一个删除记录 'id' 的可选参数。
|
||||
|
||||
### 关系
|
||||
|
||||
ORM 提供强大的关系模型。Ruby 有一篇介绍关系模型的文章: [http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html)
|
||||
|
||||
#### Belongs-To 和 Has-Many
|
||||
|
||||
假设我们在一所学校工作,当然学校有很多学生,而每个学生都只属于一个学校。这样的关系模型可以这样定义:
|
||||
|
||||
// school 模型文件
|
||||
protected $_has_many = array('students' => array());
|
||||
|
||||
// student 模型文件
|
||||
protected $_belongs_to = array('school' => array());
|
||||
|
||||
获取学生的学校:
|
||||
|
||||
$school = $student->school;
|
||||
|
||||
获取学校的学生:
|
||||
|
||||
// 注意在 studends 后必须调用 find_all 方法
|
||||
$students = $school->students->find_all();
|
||||
|
||||
// 缩小范围查询:
|
||||
$students = $school->students->where('active', '=', TRUE)->find_all();
|
||||
|
||||
默认情况下,在 student 表定义的模型文件中 ORM 会寻找 `school_id` 当作外键。这个可以通过 `foreign_key` 属性更改:
|
||||
|
||||
protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID'));
|
||||
|
||||
外键应该同时覆写 student 和 school 模型文件。
|
||||
|
||||
#### Has-One
|
||||
|
||||
Has-One 是 Has-Many 的一个特别情况,唯一不同的这是一对一关系。还以上面的例子说明就是,每个学校有且只有一个学生(当然这是一个很牵强呃例子)。
|
||||
|
||||
// school 模型文件
|
||||
protected $_has_one = array('student' => array());
|
||||
|
||||
类似于 Belongs-To,当你引用 Has-One 关系对象的时候无需调用 `find` 方法 - 它是自动完成的。
|
||||
|
||||
#### Has-Many "Through"
|
||||
|
||||
Has-Many "through" 关系(也可以称之为 Has-And-Belongs-To-Many) is used in the case of one object being related to multiple objects of another type, and visa-versa. For instance, a student may have multiple classes and a class may have multiple students. In this case, a third table and model known as a `pivot` is used. In this case, we will call the pivot object/model `enrollment`.
|
||||
|
||||
// student (学生)模型文件
|
||||
protected $_has_many = array('classes' => array('through' => 'enrollment'));
|
||||
|
||||
// class (班级)模型文件
|
||||
protected $_has_many = array('students' => array('through' => 'enrollment'));
|
||||
|
||||
其中 enrollment 表包含两个外键: `class_id` 和 `student_id`。在定义关系时,使用 `foreign_key` 和 `far_key` 覆写了默认值。例如:
|
||||
|
||||
// student (学生)模型文件() (the foreign key refers to this model [student], while the far key refers to the other model [class])
|
||||
protected $_has_many = array('classes' => array('through' => 'enrollment', 'foreign_key' => 'studentID', 'far_key' => 'classID'));
|
||||
|
||||
// class (班级)模型文件
|
||||
protected $_has_many = array('students' => array('through' => 'enrollment', 'foreign_key' => 'classID', 'far_key' => 'studentID'));
|
||||
|
||||
enrollment 模型文件应该这样定义:
|
||||
|
||||
// Enrollment 模型同时属于一个 student 和 class
|
||||
protected $_belongs_to = array('student' => array(), 'class' => array());
|
||||
|
||||
获取相关对象:
|
||||
|
||||
// 从 student 中获取 classes
|
||||
$student->classes->find_all();
|
||||
|
||||
// 从 class 中获取 students
|
||||
$class->students->find_all();
|
||||
|
||||
### 校验
|
||||
|
||||
ORM 和 [Validate] 类是紧密结合使用的。ORM 提供以下几种校验方式:
|
||||
|
||||
* _rules
|
||||
* _callbacks
|
||||
* _filters
|
||||
* _labels
|
||||
|
||||
#### `_rules`
|
||||
|
||||
protected $_rules = array
|
||||
(
|
||||
'username' => array('not_empty' => array()),
|
||||
'email' => array('not_empty' => array(), 'email' => array()),
|
||||
);
|
||||
|
||||
检测并确保 `username` 字段不为空。检测 `email` 字段不为空且是有效的 Email 地址格式。那些传递空值数组用于提供可选的额外参数到校验方法中使用。
|
||||
|
||||
#### `_callbacks`
|
||||
|
||||
protected $_callbacks = array
|
||||
(
|
||||
'username' => array('username_unique'),
|
||||
);
|
||||
|
||||
`username` 字段被传递到了 `username_unique` 回调函数。如果方法存在于当前模型它就会被调用,否则调用全局函数。下面有个小例子:
|
||||
|
||||
public function username_unique(Validate $data, $field)
|
||||
{
|
||||
// 确保 username 是唯一的
|
||||
...
|
||||
}
|
||||
|
||||
#### `_filters`
|
||||
|
||||
protected $_filters = array
|
||||
(
|
||||
TRUE => array('trim' => array()),
|
||||
'username' => array('stripslashes' => array()),
|
||||
);
|
||||
|
||||
`TRUE` 值代表 `trim` 过滤器应用到所有字段。而 `username` 字段则在校验前使用 `stripslashes` 过滤。那些传递空值数组用于提供可选的额外参数到校验方法中使用。
|
||||
|
||||
#### 检测对象是否通过校验
|
||||
|
||||
使用 [ORM::check] 检测当前对象是否通过校验:
|
||||
|
||||
// 设置完对象的值,接下来检测是否通过校验
|
||||
if ($user->values($_POST)->check())
|
||||
{
|
||||
$user->save();
|
||||
}
|
||||
|
||||
你也可是使用 `validate()` 方法直接访问模型的校验对象:
|
||||
|
||||
// 手动添加额外的过滤器
|
||||
$user->validate()->filter('username', 'trim');
|
@@ -0,0 +1,89 @@
|
||||
# 从 URL 移除 `index.php`
|
||||
|
||||
为了保持 URLs 的干净,你可能希望 URL 在访问的时候不包含 `/index.php/`。下面有两步可以实现:
|
||||
|
||||
1. 编辑 bootstrap 文件
|
||||
2. 设置重写规则
|
||||
|
||||
# 配置 Bootstrap
|
||||
|
||||
首先你需要在 [Kohana::init] 方法中更改 `index_file` 设置:
|
||||
|
||||
Kohana::init(array(
|
||||
'base_url' => '/myapp/',
|
||||
'index_file' => FALSE,
|
||||
));
|
||||
|
||||
现在所有使用 [URL::site],[URL::base] 和 [HTML::anchor] 生成的 URL均不会包含 "index.php" 了。
|
||||
|
||||
# URL 重写
|
||||
|
||||
开启重写配置的方法根据服务器的不同而不同,下面仅供参考:
|
||||
|
||||
## Apache
|
||||
|
||||
改名 `example.htaccess` 为 `.htaccess` 后修改下面的参数代码:
|
||||
|
||||
RewriteBase /kohana/
|
||||
|
||||
这里需要和 [Kohana::init] 方法中的 `base_url` 选项匹配:
|
||||
|
||||
RewriteBase /myapp/
|
||||
|
||||
完成了,就这点事!
|
||||
|
||||
### 失败了!
|
||||
|
||||
如果提示 "Internal Server Error" 或 "No input file specified" 错误,请尝试下面的修改:
|
||||
|
||||
RewriteRule ^(?:application|modules|system)\b - [F,L]
|
||||
|
||||
相反,我们可以尝试反斜杠:
|
||||
|
||||
RewriteRule ^(application|modules|system)/ - [F,L]
|
||||
|
||||
如果这样还不工作,再试着修改:
|
||||
|
||||
RewriteRule .* index.php/$0 [PT]
|
||||
|
||||
再简单点:
|
||||
|
||||
RewriteRule .* index.php [PT]
|
||||
|
||||
### 仍然失败!
|
||||
|
||||
如果还是提示失败的话,请确保你的服务器支持 URL 的 `mod_rewrite`。
|
||||
加入你可以修改 Apache 的配置,你可以复制下面的配置到 `httpd.conf`:
|
||||
|
||||
<Directory "/var/www/html/myapp">
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
|
||||
## NGINX
|
||||
|
||||
很难给出 nginx 的配置实例,但是修改其实非常简单:
|
||||
|
||||
location / {
|
||||
index index.php index.html index.htm;
|
||||
try_files $uri $uri/ index.php$uri?$args;
|
||||
}
|
||||
|
||||
location ~ ^(.+\.php)(.*)$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(.*)$;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
|
||||
include fastcgi.conf;
|
||||
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
}
|
||||
|
||||
两点需要注意的是使用 [try_files](http://wiki.nginx.org/NginxHttpCoreModule#try_files) 和 [fastcgi_split_path_info](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_split_path_info)。
|
||||
|
||||
[!!] 以上配置假定你的 PHP 是在端口为 9000 的 FastCGI 服务器,同时 nginx 在 v0.731 以上版本。
|
||||
|
||||
如果在运行中遇到的问题,请在 nginx 中启用 debug 级别的日志记录并检查 access 和 error 日志。
|
160
includes/kohana/modules/userguide/guide/zh-cn/tutorials.urls.md
Normal file
160
includes/kohana/modules/userguide/guide/zh-cn/tutorials.urls.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 路由,URLs 和链接
|
||||
|
||||
本节讲述了关于 Kohana 的请求路由, URL 生成以及链接的基本使用。
|
||||
|
||||
## 路由(Routing)
|
||||
|
||||
在上面提到的[请求流程](about.flow)一节中,一个请求通过 [Request] 类来寻找匹配 [Route] 并且加载对应的控制器以执行请求。本系统提供了更大的灵活性以及常规默认行为。
|
||||
|
||||
如果你查看了 `APPPATH/bootstrap.php` 的代码,你会发现会有包含下面的一段代码,它会在请求处理对在 [Request::instance] 关闭前立即执行。
|
||||
|
||||
Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'controller' => 'welcome',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
这是按照 `(<controller>(/<action>(/<id>)))` 的 uri 格式化的 ‘默认’ 路由设置。其中 *key* 使用 '<>' 括起来,而*可选*部分使用 '()' 括起来。既然是这样,上面的路由设置说明,所有的 uri 都是可选的,所以如果对于一个空的 uri 要匹配,它会去匹配默认的控制器和 action,也就是上面代码将会匹配并加载 `Controller_Welcome` 类,调用 `action_index` 方法以执行请求。
|
||||
|
||||
需要注意的是,任何的字符都是允许使用 `()<>` 括起来,对于 `/` 并没有特殊含义。在默认路由中 `/` 是被用来当作静态分隔符,但是如果正确的正则表达式是不会限制你如果格式化你的路由。
|
||||
|
||||
### 目录
|
||||
|
||||
对于某些原因你可能需要把一些控制器放置在子目录当作。比如这里有一个 amdin 子目录:
|
||||
|
||||
Route::set('admin', 'admin(/<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'directory' => 'admin',
|
||||
'controller' => 'home',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
该路由规定了 uri 中必须以 `admin` 开头去匹配,并且默认的,这个目录是静态被分配到 `admin`。如果现在有一个请求到 `admin/users/create` 那么它会加载 `Controller_Admin_Users` 类并调用 `action_create` 方法。
|
||||
|
||||
### 模式
|
||||
|
||||
Kohana 路由系统使用 perl 正则表达式来处理匹配。默认情况下 key(使用 `<>` 括起来的)只能根据 `[a-zA-Z0-9_]++` 来匹配,但是你可以为每个 key 以数组的形式自定义不同的模式分配到 [Route::set]。继续扩充上面的例子,如果你之前定义了一个 amdin 和 addiliate 段。其实可以使用路由分割或者下面的方式指定它们:
|
||||
|
||||
Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))',
|
||||
array(
|
||||
'directory' => '(admin|affiliate)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'home',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
上面的设置同时实现了两个段的路由映射,'admin' 和 'affiliate' 会映射到相对于的目录控制器里但是它会覆盖默认的路由设置。
|
||||
|
||||
### 更多路由样例
|
||||
|
||||
这里还有一些其他使用技巧,下面是一些样例:
|
||||
|
||||
/*
|
||||
* 验证的缩写
|
||||
*/
|
||||
Route::set('auth', '<action>',
|
||||
array(
|
||||
'action' => '(login|logout)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'auth'
|
||||
));
|
||||
|
||||
/*
|
||||
* 多样式 feeds
|
||||
* 452346/comments.rss
|
||||
* 5373.json
|
||||
*/
|
||||
Route::set('feeds', '<user_id>(/<action>).<format>',
|
||||
array(
|
||||
'user_id' => '\d+',
|
||||
'format' => '(rss|atom|json)',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'feeds',
|
||||
'action' => 'status',
|
||||
));
|
||||
|
||||
/*
|
||||
* 静态页面
|
||||
*/
|
||||
Route::set('static', '<path>.html',
|
||||
array(
|
||||
'path' => '[a-zA-Z0-9_/]+',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'static',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
/*
|
||||
* 你不喜欢斜线号?那我们使用冒号分隔。
|
||||
* EditGallery:bahamas
|
||||
* Watch:wakeboarding
|
||||
*/
|
||||
Route::set('gallery', '<action>(<controller>):<id>',
|
||||
array(
|
||||
'controller' => '[A-Z][a-z]++',
|
||||
'action' => '[A-Z][a-z]++',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Slideshow',
|
||||
));
|
||||
|
||||
/*
|
||||
* 快速搜索
|
||||
*/
|
||||
Route::set('search', ':<query>', array('query' => '.*'))
|
||||
->defaults(array(
|
||||
'controller' => 'search',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
路由的匹配是按照顺序指定的所以大家需要知道的是,如果你在加载模块之后设置路由,模块也可以指定路由程序相冲突的路由。如果是因为这个为什么默认路由会在最后设置,所以字段能够以路由的时候最好先做测试。
|
||||
|
||||
### 请求参数
|
||||
|
||||
目录,控制器和 action 都可以通过 [Request] 实例化后的两种方式访问:
|
||||
|
||||
$this->request->action;
|
||||
Request::instance()->action;
|
||||
|
||||
所有其他定义在路由中的键值可以从内控制器中访问:
|
||||
|
||||
$this->request->param('key_name');
|
||||
|
||||
[Request::param] 方法提供一个可选的第二参数,用于返回默认的没有找到路由设置键值的值。如果没有指定第二参数,返回包含所有键值的数组。
|
||||
|
||||
### 约定
|
||||
|
||||
约定适用于自定义的扩展的 `MODPATH/<module>/init.php` 文件或者 `APPPATH/bootstrap.php` 文件默认设置的路由。当然,你也可以采用外部加载,甚至是动态加载的方式。
|
||||
|
||||
## URLs
|
||||
|
||||
随着 Kohana 路由功能的不断强大,加入了一些生成路由 URI 的方法。通常你可能在调用 [URL::site] 方法时指定的字符串来创建完整的 URL:
|
||||
|
||||
URL::site('admin/edit/user/'.$user_id);
|
||||
|
||||
同时,Kohana 也提供另外一种从路由定义生成 URI 的方法。假如能够所以改变的路由的参数从而减轻代码的变更带来的烦恼,这是非常好的替代方法。下面提供一个使用 `feeds` 路由动态生成 URL 的例子:
|
||||
|
||||
Route::get('feeds')->uri(array(
|
||||
'user_id' => $user_id,
|
||||
'action' => 'comments',
|
||||
'format' => 'rss'
|
||||
));
|
||||
|
||||
比方说,你今后决定改变 `feeds/<user_id>(/<action>).<format>` 的路由定义作进一步的设计。
|
||||
Let's say you decided later to make that route definition more verbose by changing it to `feeds/<user_id>(/<action>).<format>`. If you wrote your code with the above uri generation method you wouldn't have to change a single line! When a part of the uri is enclosed in parentheses and specifies a key for which there in no value provided for uri generation and no default value specified in the route, then that part will be removed from the uri. An example of this is the `(/<id>)` part of the default route; this will not be included in the generated uri if an id is not provided.
|
||||
|
||||
[Request::uri] 可能会是你经常使用的方法,它除了上面说明的功能外还可以设定当前的路由,目录,控制器和 actions 的值。如果我们当前的默认路由是 `users/list`,我们可以生成这样的格式 `users/view/$id`:
|
||||
|
||||
$this->request->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
或者在视图中,可取的方法:
|
||||
|
||||
Request::instance()->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
## 链接
|
||||
|
||||
[!!] links stub
|
@@ -0,0 +1,95 @@
|
||||
# 类的加载
|
||||
|
||||
Kohana 需要使用 PHP 自身的[自动加载](http://php.net/manual/language.oop5.autoload.php)。这个消除了不用调用 [include](http://php.net/include) 和 [require](http://php.net/require) 之前就可以使用类文件。例如,让你想使用 [Cookie::set] 方法时,你只需要:
|
||||
|
||||
Cookie::set('mycookie', 'any string value');
|
||||
|
||||
或者要加载一个 [Encrypt] 的实例化,只需要调用 [Encrypt::instance]:
|
||||
|
||||
$encrypt = Encrypt::instance();
|
||||
|
||||
类也可以通过 [Kohana::auto_load] 方法加载,这使得从简单的类名称转换为文件名:
|
||||
|
||||
1. 类必须放置在[文件系统](start.filesystem)的 `classes/` 目录
|
||||
2. 任何下划线字符转换为斜线
|
||||
2. 文件名必须是小写的
|
||||
|
||||
当调用一个尚未加载类(比如,`Session_Cookie`),通过使用 [Kohana::find_file] 方法可以让 Kohana 搜索文件系统查找名为 `classes/session/cookie.php` 的文件。
|
||||
|
||||
## 自动加载器
|
||||
|
||||
在 `application/bootstrap.php` 配置文件默认使用 [spl_autoload_register](http://php.net/spl_autoload_register) 开启了自动加载器。
|
||||
|
||||
spl_autoload_register(array('Kohana', 'auto_load'));
|
||||
|
||||
在此类第一次使用的时候,这让 [Kohana::auto_load] 尝试去加载任意的不存在类。
|
||||
|
||||
# Transparent Class Extension {#class-extension}
|
||||
|
||||
The [cascading filesystem](about.filesystem) allows transparent class extension. For instance, the class [Cookie] is defined in `SYSPATH/classes/cookie.php` as:
|
||||
|
||||
class Cookie extends Kohana_Cookie {}
|
||||
|
||||
The default Kohana classes, and many extensions, use this definition so that almost all classes can be extended. You extend any class transparently, by defining your own class in `APPPATH/classes/cookie.php` to add your own methods.
|
||||
|
||||
[!!] You should **never** modify any of the files that are distributed with Kohana. Always make modifications to classes using extensions to prevent upgrade issues.
|
||||
|
||||
For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class:
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cookie extends Kohana_Cookie {
|
||||
|
||||
/**
|
||||
* @var mixed default encryption instance
|
||||
*/
|
||||
public static $encryption = 'default';
|
||||
|
||||
/**
|
||||
* Sets an encrypted cookie.
|
||||
*
|
||||
* @uses Cookie::set
|
||||
* @uses Encrypt::encode
|
||||
*/
|
||||
public static function encrypt($name, $value, $expiration = NULL)
|
||||
{
|
||||
$value = Encrypt::instance(Cookie::$encrpytion)->encode((string) $value);
|
||||
|
||||
parent::set($name, $value, $expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an encrypted cookie.
|
||||
*
|
||||
* @uses Cookie::get
|
||||
* @uses Encrypt::decode
|
||||
*/
|
||||
public static function decrypt($name, $default = NULL)
|
||||
{
|
||||
if ($value = parent::get($name, NULL))
|
||||
{
|
||||
$value = Encrypt::instance(Cookie::$encryption)->decode($value);
|
||||
}
|
||||
|
||||
return isset($value) ? $value : $default;
|
||||
}
|
||||
|
||||
} // End Cookie
|
||||
|
||||
Now calling `Cookie::encrypt('secret', $data)` will create an encrypted cookie which we can decrypt with `$data = Cookie::decrypt('secret')`.
|
||||
|
||||
## Multiple Levels of Extension {#multiple-extensions}
|
||||
|
||||
If you are extending a Kohana class in a module, you should maintain transparent extensions. Instead of making the [Cookie] extension extend Kohana, you can create `MODPATH/mymod/encrypted/cookie.php`:
|
||||
|
||||
class Encrypted_Cookie extends Kohana_Cookie {
|
||||
|
||||
// Use the same encrypt() and decrypt() methods as above
|
||||
|
||||
}
|
||||
|
||||
And create `MODPATH/mymod/cookie.php`:
|
||||
|
||||
class Cookie extends Encrypted_Cookie {}
|
||||
|
||||
This will still allow users to add their own extension to [Cookie] with your extensions intact. However, the next extension of [Cookie] will have to extend `Encrypted_Cookie` instead of `Kohana_Cookie`.
|
@@ -0,0 +1,57 @@
|
||||
# 通用配置
|
||||
|
||||
Kohana uses both static properties and files for configuration. Static properties are typically used for static classes, such as [Cookie], [Security], and [Upload]. Files are typically used for objects such as [Database], [Encrypt], and [Session].
|
||||
|
||||
Static properties can be set in `APPPATH/bootstrap.php` or by [class extension](using.autoloading#class-extension). The benefit of static properties is that no additional files need to be loaded. The problem with this method is that it causes the class to be loaded when the property is set, if you do not use an extension. However, using extensions will overload extensions made in modules. It is generally recommended to do static property configuration in the bootstrap.
|
||||
|
||||
[!!] When using opcode caching, such as [APC](http://php.net/apc) or [eAccelerator](http://eaccelerator.net/), class loading time is significantly reduced. It is highly recommended to use opcode caching with *any* production website, no matter the size.
|
||||
|
||||
## 加载配置
|
||||
|
||||
Every new Kohana installation will require changing [Kohana::init] settings in `APPPATH/bootstrap.php`. Any setting that is not set will use the default setting. These settings can be accessed and modified later by using the static property of the [Kohana] class. For instance, to get the current character set, read the [Kohana::$charset] property.
|
||||
|
||||
## 安全配置
|
||||
|
||||
There are several settings which need to be changed to make Kohana secure. The most important of these is [Cookie::$salt], which is used to create a "signature" on cookies that prevents them from being modified outside of Kohana.
|
||||
|
||||
If you plan to use the [Encrypt] class, you will also need to create an `encrypt` configuration file and set the encryption `key` value. The encryption key should include letters, numbers, and symbols for the best security.
|
||||
|
||||
[!!] **Do not use a hash for the encryption key!** Doing so will make the encryption key much easier to crack.
|
||||
|
||||
# 配置文件 {#config-files}
|
||||
|
||||
Configuration files are slightly different from other files within the [cascading filesystem](about.filesystem) in that they are **merged** rather than overloaded. This means that all configuration files with the same file path are combined to produce the final configuration. The end result is that you can overload *individual* settings rather than duplicating an entire file.
|
||||
|
||||
配置文件存放在 `config/` 目录的 PHP 文件,结构类似于:
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
'foo' => 'bar',
|
||||
),
|
||||
);
|
||||
|
||||
如果上面的配置文件名为 `myconf.php`,你可以通过下面代码调用:
|
||||
|
||||
$config = Kohana::config('myconf');
|
||||
$options = $config['options'];
|
||||
|
||||
[Kohana::config] 也提供了一钟使用“逗号格式”访问配置数组中的键:
|
||||
|
||||
获得 "options" 数组:
|
||||
|
||||
$options = Kohana::config('myconf.options');
|
||||
|
||||
从 "options" 数组获得 "foo" 键:
|
||||
|
||||
$foo = Kohana::config('myconf.options.foo');
|
||||
|
||||
配置数组也可以当作对象访问,如果你喜欢下面的方法:
|
||||
|
||||
$options = Kohana::config('myconf')->options;
|
||||
|
||||
请注意的是你只能使用键值型数组访问首个变量,其余的子键都必须使用标准数组方式访:
|
||||
|
||||
$foo = Kohana::config('myconf')->options['foo'];
|
@@ -0,0 +1,26 @@
|
||||
# 消息的基本使用
|
||||
|
||||
Kohana 消息(messages) 是一种友好化短小的词或短语的字符串,通常被叫做 "key"。消息通过 [Kohana::message] 方法调用访问并返回整个消息组或者单个消息。
|
||||
|
||||
举个简单的例子,当用户没有登录并试图访问一个需要验证的页面,通常会一个类似"你必须登录后才能访问此页面"的提示,而此消息可以保存在 auth 文件的 'must_login' 的键值中:
|
||||
|
||||
$message = Kohana::message('auth', 'must_login');
|
||||
|
||||
消息并不能直接翻译,如果想翻译一个消息,你需要配合使用[翻译函数](using.translation):
|
||||
|
||||
$translated = __(Kohana::message('auth', 'must_login'));
|
||||
|
||||
[!!] 在 Kohana v2 版本中,消息系统是可以翻译的,尽管如此,我们还是强烈推荐大家使用新的翻译系统代替消息,因为当翻译不存时它可以提供可读性文本。
|
||||
|
||||
## 消息文件
|
||||
|
||||
所有的消息文件都是保存在 `messages/` 目录下的纯 PHP 文件的配对数组:
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'must_login' => '你必须登录后才能访问此页面',
|
||||
'no_access' => '你没有访问此页面的权限',
|
||||
);
|
||||
|
||||
消息文件有些类似于[配置文件](using.configuration#config-files),它们都可以合并在一起。这意味着所有的消息都可以设置为一个数组并保存在 'auth' 文件之中。因此当你需要一个新的 'auth' 文件而没有必要创建多个重复文件。
|
223
includes/kohana/modules/userguide/guide/zh-cn/using.sessions.md
Normal file
223
includes/kohana/modules/userguide/guide/zh-cn/using.sessions.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# Using Sessions and Cookies
|
||||
|
||||
Kohana provides a couple of classes that make it easy to work with both cookies and session. At a high level both sessions and cookies provide the same function. They allow the developer to store temporary or persistent information about a specific client for later retrieval.
|
||||
|
||||
Cookies should be used for storing non-private data that is persistent for a long period of time. For example storing a user id or a language preference. Use the [Cookie] class for getting and setting cookies.
|
||||
|
||||
[!!] Kohana uses "signed" cookies. Every cookie that is stored is combined with a secure hash to prevent modification of the cookie. This hash is generated using [Cookie::salt], which uses the [Cookie::$salt] property. You should [change this setting](using.configuration) when your application is live.
|
||||
|
||||
Sessions should be used for storing temporary or private data. Very sensitive data should be stored using the [Session] class with the "database" or "native" adapters. When using the "cookie" adapter, the session should always be encrypted.
|
||||
|
||||
[!!] For more information on best practices with session variables see [the seven deadly sins of sessions](http://lists.nyphp.org/pipermail/talk/2006-December/020358.html).
|
||||
|
||||
# Storing, Retrieving, and Deleting Data
|
||||
|
||||
[Cookie] and [Session] provide a very similar API for storing data. The main difference between them is that sessions are accessed using an object, and cookies are accessed using a static class.
|
||||
|
||||
Accessing the session instance is done using the [Session::instance] method:
|
||||
|
||||
// Get the session instance
|
||||
$session = Session::instance();
|
||||
|
||||
When using sessions, you can also get all of the current session data using the [Session::as_array] method:
|
||||
|
||||
// Get all of the session data as an array
|
||||
$data = $session->as_array();
|
||||
|
||||
You can also use this to overload the `$_SESSION` global to get and set data in a way more similar to standard PHP:
|
||||
|
||||
// Overload $_SESSION with the session data
|
||||
$_SESSION =& $session->as_array();
|
||||
|
||||
// Set session data
|
||||
$_SESSION[$key] = $value;
|
||||
|
||||
## Storing Data {#setting}
|
||||
|
||||
Storing session or cookie data is done using the `set` method:
|
||||
|
||||
// Set session data
|
||||
$session->set($key, $value);
|
||||
|
||||
// Set cookie data
|
||||
Cookie::set($key, $value);
|
||||
|
||||
// Store a user id
|
||||
$session->set('user_id', 10);
|
||||
Cookie::set('user_id', 10);
|
||||
|
||||
## Retrieving Data {#getting}
|
||||
|
||||
Getting session or cookie data is done using the `get` method:
|
||||
|
||||
// Get session data
|
||||
$data = $session->get($key, $default_value);
|
||||
|
||||
// Get cookie data
|
||||
$data = Cookie::get($key, $default_value);
|
||||
|
||||
// Get the user id
|
||||
$user = $session->get('user_id');
|
||||
$user = Cookie::get('user_id');
|
||||
|
||||
## Deleting Data {#deleting}
|
||||
|
||||
Deleting session or cookie data is done using the `delete` method:
|
||||
|
||||
// Delete session data
|
||||
$session->delete($key);
|
||||
|
||||
// Delete cookie data
|
||||
Cookie::delete($key);
|
||||
|
||||
// Delete the user id
|
||||
$session->delete('user_id');
|
||||
Cookie::delete('user_id');
|
||||
|
||||
# Configuration {#configuration}
|
||||
|
||||
Both cookies and sessions have several configuration settings which affect how data is stored. Always check these settings before making your application live, as many of them will have a direct affect on the security of your application.
|
||||
|
||||
## Cookie Settings
|
||||
|
||||
All of the cookie settings are changed using static properties. You can either change these settings in `bootstrap.php` or by using a [class extension](using.autoloading#class-extension).
|
||||
|
||||
The most important setting is [Cookie::$salt], which is used for secure signing. This value should be changed and kept secret:
|
||||
|
||||
Cookie::$salt = 'your secret is safe with me';
|
||||
|
||||
[!!] Changing this value will render all cookies that have been set before invalid.
|
||||
|
||||
By default, cookies are stored until the browser is closed. To use a specific lifetime, change the [Cookie::$expiration] setting:
|
||||
|
||||
// Set cookies to expire after 1 week
|
||||
Cookie::$expiration = 604800;
|
||||
|
||||
// Alternative to using raw integers, for better clarity
|
||||
Cookie::$expiration = Date::WEEK;
|
||||
|
||||
The path that the cookie can be accessed from can be restricted using the [Cookie::$path] setting.
|
||||
|
||||
// Allow cookies only when going to /public/*
|
||||
Cookie::$path = '/public/';
|
||||
|
||||
The domain that the cookie can be accessed from can also be restricted, using the [Cookie::$domain] setting.
|
||||
|
||||
// Allow cookies only on the domain www.example.com
|
||||
Cookie::$domain = 'www.example.com';
|
||||
|
||||
If you want to make the cookie accessible on all subdomains, use a dot at the beginning of the domain.
|
||||
|
||||
// Allow cookies to be accessed on example.com and *.example.com
|
||||
Cookie::$domain = '.example.com';
|
||||
|
||||
To only allow the cookie to be accessed over a secure (HTTPS) connection, use the [Cookie::$secure] setting.
|
||||
|
||||
// Allow cookies to be accessed only on a secure connection
|
||||
Cookie::$secure = TRUE;
|
||||
|
||||
// Allow cookies to be accessed on any connection
|
||||
Cookie::$secure = FALSE;
|
||||
|
||||
To prevent cookies from being accessed using Javascript, you can change the [Cookie::$httponly] setting.
|
||||
|
||||
// Make cookies inaccessible to Javascript
|
||||
Cookie::$httponly = TRUE;
|
||||
|
||||
## Session Adapters {#adapters}
|
||||
|
||||
When creating or accessing an instance of the [Session] class you can decide which session adapter you wish to use. The session adapters that are available to you are:
|
||||
|
||||
Native
|
||||
: Stores session data in the default location for your web server. The storage location is defined by [session.save_path](http://php.net/manual/session.configuration.php#ini.session.save-path) in `php.ini` or defined by [ini_set](http://php.net/ini_set).
|
||||
|
||||
Database
|
||||
: Stores session data in a database table using the [Session_Database] class. Requires the [Database] module to be enabled.
|
||||
|
||||
Cookie
|
||||
: Stores session data in a cookie using the [Cookie] class. **Sessions will have a 4KB limit when using this adapter.**
|
||||
|
||||
The default datapter can be set by changing the value of [Session::$default]. The default adapter is "native".
|
||||
|
||||
[!!] As with cookies, a "lifetime" setting of "0" means that the session will expire when the browser is closed.
|
||||
|
||||
### Session Adapter Settings
|
||||
|
||||
You can apply configuration settings to each of the session adapters by creating a session config file at `APPPATH/config/session.php`. The following sample configuration file defines all the settings for each adapater:
|
||||
|
||||
return array(
|
||||
'native' => array(
|
||||
'name' => 'session_name',
|
||||
'lifetime' => 43200,
|
||||
),
|
||||
'cookie' => array(
|
||||
'name' => 'cookie_name',
|
||||
'encrypted' => TRUE,
|
||||
'lifetime' => 43200,
|
||||
),
|
||||
'database' => array(
|
||||
'name' => 'cookie_name',
|
||||
'encrypted' => TRUE,
|
||||
'lifetime' => 43200,
|
||||
'group' => 'default',
|
||||
'table' => 'table_name',
|
||||
'columns' => array(
|
||||
'session_id' => 'session_id',
|
||||
'last_active' => 'last_active',
|
||||
'contents' => 'contents'
|
||||
),
|
||||
'gc' => 500,
|
||||
),
|
||||
);
|
||||
|
||||
#### Native Adapter {#adapter-native}
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | name | name of the session | `"session"`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
#### Cookie Adapter {#adapter-cookie}
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | name | name of the cookie used to store the session data | `"session"`
|
||||
`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
#### Database Adapter {#adapter-database}
|
||||
|
||||
Type | Setting | Description | Default
|
||||
----------|-----------|---------------------------------------------------|-----------
|
||||
`string` | group | [Database::instance] group name | `"default"`
|
||||
`string` | table | table name to store sessions in | `"sessions"`
|
||||
`array` | columns | associative array of column aliases | `array`
|
||||
`integer` | gc | 1:x chance that garbage collection will be run | `500`
|
||||
`string` | name | name of the cookie used to store the session data | `"session"`
|
||||
`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE`
|
||||
`integer` | lifetime | number of seconds the session should live for | `0`
|
||||
|
||||
##### Table Schema
|
||||
|
||||
You will need to create the session storage table in the database. This is the default schema:
|
||||
|
||||
CREATE TABLE `sessions` (
|
||||
`session_id` VARCHAR(24) NOT NULL,
|
||||
`last_active` INT UNSIGNED NOT NULL,
|
||||
`contents` TEXT NOT NULL,
|
||||
PRIMARY KEY (`session_id`),
|
||||
INDEX (`last_active`)
|
||||
) ENGINE = MYISAM;
|
||||
|
||||
##### Table Columns
|
||||
|
||||
You can change the column names to match an existing database schema when connecting to a legacy session table. The default value is the same as the key value.
|
||||
|
||||
session_id
|
||||
: the name of the "id" column
|
||||
|
||||
last_active
|
||||
: UNIX timestamp of the last time the session was updated
|
||||
|
||||
contents
|
||||
: session data stored as a serialized string, and optionally encrypted
|
118
includes/kohana/modules/userguide/guide/zh-cn/using.views.md
Normal file
118
includes/kohana/modules/userguide/guide/zh-cn/using.views.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# 视图的使用
|
||||
|
||||
视图是包含输出显示信息内容的文件。通常大多数情况下是 HTML,CSS 和 Javascript 或者其他任何内容(包括调用 AJAX 的 XML 或 JSON 的输出)。其主要目的是为了从程序中分离逻辑以获得可复用性和整洁代码。
|
||||
|
||||
然而事实上,视图本身也能传递变量等代码并输出数据。比如,循环产品信息的数组并输出每个产品的信息。视图仍然是 PHP 文件因此你可以正常的写任何代码。
|
||||
|
||||
# 创建视图文件
|
||||
|
||||
视图文件存在[文件系统](about.filesystem)中的 `views` 目录。你也可以在 `views` 目录下面创建子目录组织你的文件。下面所有的例子都是合理的视图文件:
|
||||
|
||||
APPPATH/views/home.php
|
||||
APPPATH/views/pages/about.php
|
||||
APPPATH/views/products/details.php
|
||||
MODPATH/error/views/errors/404.php
|
||||
MODPATH/common/views/template.php
|
||||
|
||||
## 加载视图
|
||||
|
||||
[View] 对象通常在 [Controller] 内部通过使用 [View::factory] 方法创建。一般视图被赋值给 [Request::$response] 属性或其他视图。
|
||||
|
||||
public function action_about()
|
||||
{
|
||||
$this->request->response = View::factory('pages/about');
|
||||
}
|
||||
|
||||
当视图对象如同上面的例子赋值给 [Request::$response],必要时它会自动输出呈现。如果想获得视图输出的内容,你可以调用 [View::render] 方法或者强制转为字符串类型。当时视图输出呈现时,视图会被加载并生成 HTML 代码。
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$view = View::factory('pages/about');
|
||||
|
||||
// Render the view
|
||||
$about_page = $view->render();
|
||||
|
||||
// Or just type cast it to a string
|
||||
$about_page = (string) $view;
|
||||
|
||||
$this->request->response = $about_page;
|
||||
}
|
||||
|
||||
## 视图变量
|
||||
|
||||
一旦视图已经被加载,我们可以通过 [View::set] 和 [View::bind] 方法赋值变量。
|
||||
|
||||
public function action_roadtrip()
|
||||
{
|
||||
$view = View::factory('user/roadtrip')
|
||||
->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo'));
|
||||
->bind('user', $this->user);
|
||||
|
||||
// 视图拥有 $places 和 $user 变量
|
||||
$this->request->response = $view;
|
||||
}
|
||||
|
||||
[!!] `set()` 和 `bind()` 方法的区别在于 `bind()` 是引用赋值。如果你在变量定义之前使用 `bind()` 绑定了它。变量默认会被当作 `NULL` 创建。
|
||||
|
||||
### 全局变量
|
||||
|
||||
在程序中可能有多个视图文件而同时调用同样的变量。比如,在两个模板的 header 块中显示一个页面的相同标题而不同的内容。通过 [View::set_global] 和 [View::bind_global] 方法创建全局变量。
|
||||
|
||||
// 赋值 $page_title 到所有的视图
|
||||
View::bind_global('page_title', $page_title);
|
||||
|
||||
假如程序中首页有三个视图需要输出呈现:`template`,`template/sidebar` 和 `pages/home`。首先,创建一个抽象类控制器去初始化视图模板:
|
||||
|
||||
abstract class Controller_Website extends Controller_Template {
|
||||
|
||||
public $page_title;
|
||||
|
||||
public function before()
|
||||
{
|
||||
parent::before();
|
||||
|
||||
// 定义 $page_title 变量到所有视图中使用
|
||||
View::bind_global('page_title', $this->page_title);
|
||||
|
||||
// 加载视图为 $sidebar 变量到模板
|
||||
$this->template->sidebar = View::factory('template/sidebar');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
下一步,在 home 控制器继承 `Controller_Website`:
|
||||
|
||||
class Controller_Home extends Controller_Website {
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$this->page_title = 'Home';
|
||||
|
||||
$this->template->content = View::factory('pages/home');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
## 视图嵌套
|
||||
|
||||
如果你想在视图中加载另外一个视图,这里提供两个方案。通过调用 [View::factory] 你可以实现沙盒加载视图。这意味着你可以使用 [View::set] 或 [View::bind] 赋值:
|
||||
|
||||
// 只有 $user 变量可用在 "views/user/login.php" 视图文件
|
||||
<?php echo View::factory('user/login')->bind('user', $user) ?>
|
||||
|
||||
另外一种选择是直接加载视图,这会使得当前所有变量加载并在视图中使用:
|
||||
|
||||
// 所有定义在此视图中的变量都会加载到 "views/message.php" 文件
|
||||
<?php include Kohana::find_file('views', 'user/login') ?>
|
||||
|
||||
另外,你也可以在整个 [Request] 中加载一个视图中:
|
||||
|
||||
<?php echo Request::factory('user/login')->execute() ?>
|
||||
|
||||
这是一个 [HMVC](about.mvc) 的例子已确保它可以创建并从程序其他的 URL 调用。
|
||||
|
||||
# 升级 v2.x 版本
|
||||
|
||||
不同于 Kohana v2.x 版本,视图不在 [Controller] 环境中加载,因此你不能够把 `$this` 当作加载视图的控制器访问。传递控制器到视图必须这样实现:
|
||||
|
||||
$view->bind('controller', $this);
|
Reference in New Issue
Block a user