This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
khosb/includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md
2011-05-03 09:49:01 +10:00

289 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 从 2.3.x 升级
Kohana v3 大部分功能都不同于 Kohana 2.3 版本,下面列出了一系列的升级建议:
## 命名约定
在 2.x 体系中不同的类的'类型'(比如 controllermodel 等)使用后缀来加以区分。文件夹在模型/控制器目录下没有任何类名的关系。
在 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 到另一个。相反的你使用标记段比如controllermethodid的变量来指定 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();
}
}