Условия:
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 хранится в сессии целиком), но может стать причиной долгих поисков. В общем, я Вас предупредил
Ай-ай-ай .. не хорошо в водить в заблуждение новичков подобными постами.
Десериализация объектов начинается с вызова функции __wakeup(), а ни как не _initialize(). Об этом сказано в оф. руководстве: http://php.net/manual/en/language.oop5.magic.php
А вот __construct() и __wakeup() уже действительно вызывают _initialize() для инициализации объекта модели.
Ну, собственно говоря, речь как раз о том, что при десериализации пропускается непосредственный вызов конструктора, поэтому стоит использовать _initialize(). Возможно, некорректно выразился…
Ага, все верно. Я первый раз тоже сильно удивился когда в десериализованной модели идентификатор сервиса потерял. Потом долго «курил маны» и в исходниках Kohana ковырялся.
Хм.
У меня также обнаружился баг с сессиями (или с куками):
В определенный момент (не выяснил пока условия возникновения) просто перестает отзываться сайт. Любые страницы выдают ошибку Undefined primary key (или как-то так) и обработчик исключений ругается на строку в ORM::pk()
return $this->_object[$this->_primary_key];
Методом научного тыка выяснил, что возникает этот в момент вызова сессии.
Почистил куки — всё опять заработало. О_о
@janson
Ну, это давняя тема, на форуме не раз обсуждалось. У меня подобное возникало после Fatal Error (скорее всего сессия корректно не дозаписывалась). На самом деле ничего страшного, просто метод pk() должен проверять наличие ключа $this->_primary_key.
@biakaveron
А почему этот баг с сессиями никак не пофиксят, он уже не раз всплывал, вроде. Непонятно.
Ну, если фиксировать на уровне ORM (проверять модель на loaded и т.д.), то это не решит проблему потери сессионных данных. Возможно, в ветке 3.1 изменится что-то в работе собственно ядра — не знаю, не смотрел еще, что там творится.