Контент


Нестандартные ORM-модели в сессии

Условия:

1. Есть модель ORM, в конструкторе который Вы изменяете важные параметры, например $_table_name.
2. Объекты модели хранятся в сессии.

Ошибка

Как правило, Database_Exception — те самые важные параметры модели почему-то не переопределены. Хотя Вы их точно в конструкторе прописывали!

В чем дело?

Проблема возникнет, когда Kohana будет извлекать модель из сессии (точнее при создании объекта Session). Дело в том, что модель хранится в сериализованном виде, при десериализации (распаковывании) объекта ORM конструктор не вызывается. Так что все Ваши модификации будут пропущены (если говорить про параметр $_table_name, то модель будет обращаться к не той таблице БД).

Чтобы этого избегать, следует использовать protected-метод _initialize(). Он вызывается из конструктора, там по умолчанию происходят все вычисления дефолтовых значений для $_table_name, $_db, свойств связей и т.д. Как раз-таки с этого метода начинается десериализация модели ORM, так что все модификации складываем именно в _initialize(). Например, так:

protected function _initialize()
{
    if (empty($this->_table_name) AND ($table_name = Kohana::config('models')->table))
    {
        $this->_table_name = $table_name;
    }
 
    parent::_initialize();
}

Такое может возникнуть, когда свойства модели заполняются в зависимости от каких-либо условий (параметр Kohana::$environment или по настройкам конфигов). Раньше я всегда использовал конструктор, теперь вот есть смысл выносить все это в _initialize(). Да, случается нечасто (не так уж много случаев, когда объект ORM хранится в сессии целиком), но может стать причиной долгих поисков. В общем, я Вас предупредил :)

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

Опубликовано в Kohana3.

Теги: .


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

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

  1. stalker пишет:

    Ай-ай-ай .. не хорошо в водить в заблуждение новичков подобными постами.

    Десериализация объектов начинается с вызова функции __wakeup(), а ни как не _initialize(). Об этом сказано в оф. руководстве: http://php.net/manual/en/language.oop5.magic.php

    А вот __construct() и __wakeup() уже действительно вызывают _initialize() для инициализации объекта модели.

  2. biakaveron пишет:

    Ну, собственно говоря, речь как раз о том, что при десериализации пропускается непосредственный вызов конструктора, поэтому стоит использовать _initialize(). Возможно, некорректно выразился…

  3. stalker пишет:

    Ага, все верно. Я первый раз тоже сильно удивился когда в десериализованной модели идентификатор сервиса потерял. Потом долго «курил маны» и в исходниках Kohana ковырялся. :)

  4. janson пишет:

    Хм.

    У меня также обнаружился баг с сессиями (или с куками):

    В определенный момент (не выяснил пока условия возникновения) просто перестает отзываться сайт. Любые страницы выдают ошибку Undefined primary key (или как-то так) и обработчик исключений ругается на строку в ORM::pk()

    return $this->_object[$this->_primary_key];

    Методом научного тыка выяснил, что возникает этот в момент вызова сессии.

    Почистил куки — всё опять заработало. О_о

  5. biakaveron пишет:

    @janson
    Ну, это давняя тема, на форуме не раз обсуждалось. У меня подобное возникало после Fatal Error (скорее всего сессия корректно не дозаписывалась). На самом деле ничего страшного, просто метод pk() должен проверять наличие ключа $this->_primary_key.

  6. schokk пишет:

    @biakaveron

    А почему этот баг с сессиями никак не пофиксят, он уже не раз всплывал, вроде. Непонятно.

  7. biakaveron пишет:

    Ну, если фиксировать на уровне ORM (проверять модель на loaded и т.д.), то это не решит проблему потери сессионных данных. Возможно, в ветке 3.1 изменится что-то в работе собственно ядра — не знаю, не смотрел еще, что там творится.



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

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