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/ru-ru/about.upgrading.md
2011-05-03 09:49:01 +10:00

17 KiB
Raw Blame History

Переход с 2.3.x

Многое в Kohana v3 работает совсем по другому, нежели в Kohana 2.3, вот список самых популярных советов для обновляющихся.

Правила именования

Ветка 2.x выделяет различные 'типы' классов (т.е. контроллер, модель и т.д.), используя для этого суффиксы. Директории внутри папок model / controller не влияют на имя класса.

В 3.0 от данного подхода отказались в пользу файловых соглашений Zend framework , в котором имя класса является путем к файлу, разделенному знаками подчеркивания вместо слэщей (т.е. /some/class/file.php становится Some_Class_File)

Смотри описание соглашений для получения подробной информации.

Библиотека 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 было то, что если Вы попытаетесь обратиться к значению одного из суперглобальных массивов и оно не задано, библиотека 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

Произошло немало серьезных изменений в ORM после версии 2.3, вот список наиболее известных проблем после обновления.

Свойства

Все свойства модели теперь начинаются со знака подчеркивания (_) и больше не доступны через метод __get(). Вместо этого Вы должны вызвать метод с именем свойства, но без подчеркивания.

Например, свойство, бывшее в 2.3 loaded, теперь называется _loaded и извне класса доступно через $model->loaded().

Связи

В 2.3, если Вы хотели пройтись по связанным с моделью объектам, надо было использовать:

foreach($model->{relation_name} as $relation)

Однако в новой системе это не будет работать. В версии 2.3 любой запрос с использованием библиотеки Database, был сгенерирован глобально, т.е. у Вас не получится создать одновременно два запроса. Вот пример:

TODO: Нужен достойный пример!!!!

Этот запрос приведет к ошибке, т.к. второй запрос будет 'наследовать' условия первого, тем самым вызывая чертовщину. В v3.0 это было исправлено выделением каждого запроса в свою собственную 'песочницу', это приводит к тому, что некоторые вещи работают не так, как ожидается. Пример:

foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post)
{
	echo $post->title;
}

[!!] (Смотри описание нового синтаксиса запросов в руководстве по Database)

В 2.3 данный запрос вернет объект-итератор всех записей пользователя с id=3, где поле post_date лежит в диапазоне последних 24 часов. Однако новая версия применит условия where к пользовательской модели и вернет объединенную через join модель Model_Post.

Для достижения нужного эффекта необходимо перераспределить порядок вызовов:

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();

Связи много-ко-многим

В 2.3 Вы можете указать has_and_belongs_to_many тип связи. В 3.0 эта функциональность была переработана в связь сквозное has_many.

В моделях определяется связь has_many с другой моделью, но добавляется атрибут 'through' => 'table' , где 'table' - имя промежуточной таблицы. Например (в контексте области записи<>категории):

$_has_many = array
(
	'categories' => 	array
						(
							'model' 	=> 'category', // внешняя модель
							'through'	=> 'post_categories' // промежуточная модель
						),
);

Если Вы настроили kohana с использованием табличных префиксов, то не стоит беспокоиться о явном указании префиксов в модели.

Внешние ключи

Если Вы хотели переопределить внешний ключ в ORM ветки 2.x, надо было указать в принадлежащей (слабой) модели свойство $foreign_keys со значением имени внешнего ключа.

В 3.0 Вы определяется ключ foreign_key в самом объявлении связи, вот так:

Class Model_Post extends ORM
{
	$_belongs_to = 	array
					(
						'author' => array
									(
										'model' 		=> 'user',
										'foreign_key' 	=> 'user_id',
									),
					);
}

В данном примере мы настроили поле user_id для таблицы записей.

В связях has_many атрибут far_key (дальний ключ) является полем в промежуточной таблице, которое связано с внешней (для текущей) таблицей, а внешний ключ является полем в промежуточной таблице, которое связано с "этой" таблицей.

Следуя вышесказанному, "posts" связаны много-ко-многим с "categories" через 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',
													),
								);
	}

Очевидно, что настройки псевдонимов выглядят несколько неадекватными, но это хороший пример того, как работает схема внешний/дальний ключ.

ORM Iterator

Стоит также отметить, что от класса ORM_Iterator отказались в пользу Database_Result.

Если надо получить массив объектов ORM с ключами из первичных ключей, надо вызвать [Database_Result::as_array], вот так:

	$objects = ORM::factory('user')->find_all()->as_array('id');

Здесь id является первичным ключом таблицы.

Библиотека Router

В версии 2 была библиотека Router, которая обрабатывала основной запрос приложения. Она позволяла определить базовые маршруты в файле config/routes.php и использовать собственные регулярные выражения для них, однако этого было недостаточно для описания чего-нибудь нестандартного.

Маршруты

Система маршрутизации (теперь логичнее называть ее системой запросов) в версии 3.0 стала намного более гибкой. Маршруты объявляются в загрузочном файле (application/bootstrap.php) и скриптах init.php модулей (modules/module/init.php). (Стоит также отметить, что маршруты рассматриваются в том же порядке, в каком были определены).

Вместо объявления массива маршрутов теперь необходимо создавать новый объект [Route] на каждый маршрут. В отличие от ветки 2.x нет необходимости отделять один URI от другого. Вместо этого Вы определяете шаблон с использованием переменных для обозначения секций (таких как контроллер, метод, id).

К примеру, в предыдущей системе данное выражение:

$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'));

[!!] Каждому маршруту назначается уникальное имя (в данном случае он называется reversed), причины описаны в учебнике по URL.

Угловые скобки являются признаком динамических секций, которые будут сохранены в виде переменных. Круглые скобки обозначают необязательные участки. Если Вы хотите обрабатывать только адреса, начинающиеся с admin, используйте:

Rouse::set('admin', 'admin(/<controller>(/<id>(/<action>)))');

А если надо заставить пользователя указать контроллер:

Route::set('admin', 'admin/<controller>(/<id>(/<action>))');

Также Kohana не устанавливает сама значений по умолчанию. Если Вы хотите, чтобы Kohana установила метод 'index' как дефолтный, необходимо указать это в явном виде! Сделайте это с помощью [Route::defaults]. Когда надо указать регулярное выражение для отдельных сегментов uri, добавьте параметр - массив вида segment => regex. Например:

Route::set('reversed', '(<controller>(/<id>(/<action>)))', array('id' => '[a-z_]+'))
		->defaults(array('controller' => 'posts', 'action' => 'index'))

Значение сегмента id теперь должно состоять только из маленьких латинских букв и знака подчеркивания.

Экшены

Еще один момент, который необходимо отметить - методы контроллера, которые должны быть доступны через url теперь называются "экшены" ("actions"), и начинаются с префикса 'action_'. В вышеуказанном примере, если пользователь введет admin/posts/1/edit, то экшен будет называться edit, но вызываемый метод контроллера получится action_edit. Подробности в учебнике url.

Сессии

Больше нет методов Session::set_flash(), Session::keep_flash() и Session::expire_flash(), вместо них используйте [Session::get_once].

Хэлпер 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

Сделано несколько незначительных изменений, которые стоит отметить.

В 2.3 представления формировались в зоне видимости контроллера, что позволяло в представлении использовать $this как ссылку на контроллер, и в 3.0 теперь по-другому. Представления теперь генерируются в пустом окружении. Если необходимо использовать $this в шаблоне, создайте ссылку с помощью [View::bind]: $view->bind('this', $this).

Тем не менее, стоит отметить, что это очень плохая привычка, т.к. повышает сцепление представления с контроллером и усложняет повторное использование. Рекомендуется подключать необходимые переменные таким образом:

$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].

<?php

Class Controller_Hello extends Controller_Template
{
	function after()
	{
		$this->template->menu = '...';
		
		return parent::after();
	}
}