Контент


F.A.Q.

Решил записывать сюда всякие интересности и особенности поведения Kohana, с которыми периодически сталкиваюсь. В первую очередь для себя, но возможно и вам будет интересно. Попутно здесь же буду приводить полезные приемы.

Общая информация

  • У вас есть базовый контроллер (Base_Controller к примеру), и он не должен быть доступен через URL (http://localhost/base/)? Сделайте его абстрактным (abstract class)!
  • Иногда бывает необходимо создать public-метод в контроллере для внутренних целей (например, чтобы вызвать его из хука или хэлпера), однако он не должен быть виден пользователю, в частности чтобы в него нельзя было попасть через URL. Для этого перед названием метода просто добавляем знак подчеркивания.

Маршрутизация

  • Чтобы избавиться от index.php в URL достаточно откорректировать параметр $config['index_page'] в файле config/config.php. Не забудьте подготовить файл .htaccess, иначе ничего не получится.

    Вроде бы мелочь, но я сам из-за отсутствия пояснений в документации бросался переписывать системный хэлпер, да и на форуме сталкивался с такими же вопрошающими, так что в FAQ’е должно быть на 100%.

  • Как выяснилось на форуме, если в URL присутствует имя фронт-контроллера (проще говоря index.php), то итоговый Router::$current_uri будет вычислен неверно. Например, http://localhost/any/directory/index.php/test будет обработан как http://localhost/index.php/test. Все это независимо от значения параметра $config['index_page'].

Database

  • Экранирование (метод Database::escape()) требуется только для выполнения plain-запросов (через метод Database::query()), методы Query Builder‘а и ORM автоматически вызывают escape().
  • Если необходимо вызвать какую-нибудь специфическую функцию СУБД в Query Builder‘е, используйте в методах параметр $quote, который определяет, заключать ли передаваемые имена полей в кавычки. Например:
    $this->db->where('date_created >', 'NOW()', TRUE);

ORM

  • Одна из наиболее распространенных ошибок, вызванных не совсем корректной официальной документацией — добавление связи «много-ко-многим» с объектом после сохранения исходного объекта. Приведу строчку, хорошо знакомую поклонникам модуля Auth:

    if ($user->save() AND $user->add(ORM::factory('role', 'login'))) {

    В этом случае роль ‘login‘ данному пользователю не добавится! Необходимо все манипуляции с объектом производить до сохранения:

    if ($user->add(ORM::factory('role', 'login')) AND $user->save()) {

  • Если вы указываете при создании ORM-объекта значение ключа (например, ORM::factory(‘user’, 1)), помните, что объект создается немедленно. Поэтому, если далее необходимо еще проделывать с ним какие-либо манипуляции (в частности, объединение с другими таблицами посредством метода with()), то сперва создайте пустой ORM-объект, примените with() и только потом делайте выборку по ключу.

    // НЕПРАВИЛЬНО! будет выполнено два запроса, условие article_id=1 потеряется
    $article = ORM::factory('article', 1)->with('user')->find();
    // ПРАВИЛЬНО! всего один запрос
    $article = ORM::factory('article')->with('user')->find(1);

  • Если в моделях используется наследование — помните, что связи и прочие свойства родительской модели могут быть случайно затерты данными новой модели. Пример:

    class Parent_Model extends ORM {
          $protected $ignored_columns = array('ignored1', 'ignored2');
    }
     
    class Child_Model extends Parent_Model {
         $protected $ignored_columns = array('ignored3');
    }
    // теперь свойства Child_Model::$ignored1 и Child_Model::$ignored2 будут обрабатываться как существующие в базе поля

Validation

  • Использование правила matches[] (обычно для подтверждения пароля или e-mail) позволяет не указывать правило required для этого поля, достаточно это правило указать для поля, с которым будем сравнивать.
  • Если необходимо «собрать» поле из нескольких (дата, время или еще что-то), то лучше всего использовать add_callback(), в котором нужное поле и будет вычислено. Если это происходит в модели ORM, не забываем указать исходные компоненты поля как ignored_columns. Обсуждение на оф. форуме.

Views

  • Наверняка у вас будут переменные, которые могут пригодиться в любом шаблоне приложения (к примеру, имя и id текущего пользователя). Поэтому я обычно в одном из базовых контроллеров устанавливаю глобальные переменные (метод set_global()) для представления $this->template — теперь они видны из всех включаемых в шаблон представлений.

Хуки

  • Если вы создаете хуки как классы (другой вариант — написание отдельных функций и вызов Event::add()), не забудьте в конструкторе привязать методы к соответствующим событиям, а после описания класса создать экземпляр хука (new Some_Hook), т.к. система самостоятельно описанные классы не создает (происходит обычный include).
  • Часто из метода хука требуется добраться до свойств или методов контроллера. Для этого можно использовать свойство Kohana::$instance, в котором и хранится текущий контроллер. Если контроллер еще не был создан, то можно его создать вручную (например, если хук отработал по 404й ошибке, то конструируем страницу Not Found).

Cache

  • Если Вы в контроллере пытаетесь загрузить сохраненный в кэше ORM-объект, можете обнаружить (например, через Profiler), что запрос к БД все же производится. Чтобы этого не происходило, надо в модели добавить строчку:

    protected $reload_on_wakeup = FALSE;


    В этом случае при сериализации/десериализации объекта (что собственно и происходит при каждой загрузке ORM-объекта из кэша) не будет происходить запрос к БД. Впрочем, если объект загружается не из кэша (к примеру, из сессии), то таким образом можно пропустить произошедшие изменения в БД и объект будет устаревшим.

Auth

  • В модуле Auth предоставлена модель User, унаследованная от Auth_User. Если вы захотите изменить в ней валидацию родительской модели (обычно меняют перечень полей и правила), то в конце метода validate() вызывайте не родительский метод (parent::validate()), а ORM::validate(), иначе получите ошибку.
  • Если вы используете метод validate() с сохранением объекта (параметр $save установлен в TRUE), помните, что в объект автоматически подставляются только те поля, которые упомянуты в правилах валидации. Таким образом, при существовании непроверяемых полей необходимо их добавить вручную. С другой стороны, возможно это повод заполнять подобные поля в отдельной форме (что-то типа «анкеты»), а в таблице БД сделать их поддерживаемыми NULL. Также не забудьте про связи с другими объектами — их необходимо установить до вызова validate(), иначе они пропадут (ведь метод save() вы уже вызывать не будете).
  • Вводите правильный пароль, но войти не можете? А не меняли ли Вы параметр ‘salt_pattern‘ в файле config/auth.php? Помните, что после его изменения войти под имеющимися учетными записями уже не получится. Подробнее можете почитать тут.

Конфигурация

  • Иногда удобно группировать файлы в тематические директории. Так можно поступить и с конфигами, например так:
    echo Kohana::config('somedir/somefile.paramname');
    

Router3

  • Подключая модуль router3 к приложению на Kohana v2.3.x, будьте готовы к тому, что теперь знак подчеркивания в имени контроллера будет заменяться слэшем и в итоге контроллер будет ожидаться в поддиректории папки controllers. Это может быть как плюсом (реализация админки в отдельной папке с помощью префиксов), так и минусом (работавшие ранее контроллеры будут приводить к странице 404).

Просто полезные ссылки

  • Очень интересная панель - Kohana Debug Toolbar, демо-страничку можно посмотреть тут.

Список будет расширяться, если есть какие-либо предложения - пишите :)

Google Bookmarks Digg Reddit del.icio.us Ma.gnolia Technorati Slashdot Yahoo My Web News2.ru БобрДобр.ru RUmarkz Ваау! Memori.ru rucity.com МоёМесто.ru Mister Wong

Комментарии (8)

Будьте в курсе обсуждения, подпишитесь на RSS ленту комментариев к этой записи.

  1. Евгений пишет:

    А как отключить обработку 404 ошибки? Чтобы ее мод реврайт обработал?

  2. BIakaVeron пишет:

    Вы не указали версию Kohana, поэтому вот примерное решение для Ko3:

    // в bootstrap.php
     try {
    Request::instance()
    	->execute()
    } catch (Exception $e) {
    	// пишем в лог и т.д.
    }
    // отправляем заголовки ответа и собственно вывод
    echo Request::instance()->send_headers()
    	->response;

    По умолчанию все ошибки обрабатывает внутренний обработчик Kohana, поэтому надо "обернуть" вызовы в try ... catch. В результате header с кодом 404 (или любой другой, например 403) пройдет наружу.

  3. Евгений пишет:

    Версия 2.3.1. Как для нее сделать?

  4. BIakaVeron пишет:

    Не помню насчет 2.3.1, а в 2.3.4 срабатывает событие ‘system.404′, по умолчанию оно обрабатывается системой, заголовки нормально генерируются.

  5. Евгений пишет:

    Как отменить это умолчание? Чтобы кохана просто пропускала это событие. Если уж нельзя, то как тогда править то представление, которое выдается пользователю при этой ошибке?

  6. BIakaVeron пишет:

    Event::clear(‘system.404′);

  7. Евгений пишет:

    Написал это в главном index.php, не работает.

  8. BIakaVeron пишет:

    Навешивание стандартного обработчика происходит внутри файла bootstrap.php, так что имеет смысл прописывать данную строчку в базовом контроллере или каком-нибудь хуке.



Можно включить подсветку кода: <code><pre lang="">...</pre></code>
Разрешены некоторые HTML теги

или используйте trackback.