Троичная логика (ternary logic) в Doctrine ORM

// Июль 7th, 2011 // Doctrine

В этой статье речь пойдет о третичной логике. Я не буду говорить об операциях в троичной логике, а коснусь лишь вопросов хранения данных в Doctrine.

Представим, что есть некоторый столбец в БД, данные которого могут принимать три возможных значения. Для хранения типа boolean (двоичная логика) Doctrine используется тип данных boolean в PHP, а при отражении в таблицу он проектируется в tinyint(1). Но как тогда кодировать третье значение? Мы будем использовать NULL. Т.е. область определения = {0,1,NULL}. Значит notnull => false. Но тогда возникает одна проблема.

$model = new SomeModel();
$model->ternary_field = NULL;
$model->save();

При этом срабатывает приведение типов, и в БД сохраняется 0, а не NULL. Приведение типов столбцов закодировано в файле Doctrine_Record::getPrepared():

 public function getPrepared(array $array = array())
 {
 $a = array();

 if (empty($array)) {
 $modifiedFields = $this->_modified;
 }

 foreach ($modifiedFields as $field) {
 $type = $this->_table->getTypeOf($field);

 if ($this->_data[$field] === self::$_null) {
 $a[$field] = null;
 continue;
 }

 switch ($type) {
 case 'array':
 case 'object':
 $a[$field] = serialize($this->_data[$field]);
 break;
 case 'gzip':
 $a[$field] = gzcompress($this->_data[$field],5);
 break;
 case 'boolean':
 $a[$field] = $this->getTable()->getConnection()->convertBooleans($this->_data[$field]);
 break;
 case 'set':
 if (is_array($this->_data[$field])) {
 $a[$field] = implode(',', $this->_data[$field]);
 } else {
 $a[$field] = $this->_data[$field];
 }
 break;
 default:
 if ($this->_data[$field] instanceof Doctrine_Record) {
 $a[$field] = $this->_data[$field]->getIncremented();
 if ($a[$field] !== null) {
 $this->_data[$field] = $a[$field];
 }
 } else {
 $a[$field] = $this->_data[$field];
 }
 /** TODO:
 if ($this->_data[$v] === null) {
 throw new Doctrine_Record_Exception('Unexpected null value.');
 }
 */
 }
 }

 return $a;
 }

А для типа boolean срабатывает вот этот case:

case 'boolean':
 $a[$field] = $this->getTable()->getConnection()->convertBooleans($this->_data[$field]);
 break;

Определение столбца выглядело следующим образом:

        $this->hasColumn('ternary_field', 'boolean', null,
         array(
            'default' => false
        ));

Не буду томить с решением проблемы, во общем всё портил параметр default. После его изменения на default=>NULL в базу стали сохраняться правильные значения.

Литература

http://stackoverflow.com/questions/1391777/how-do-i-insert-null-values-using-pdo
http://php.net/manual/en/pdostatement.bindparam.php

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


2 Responses to “Троичная логика (ternary logic) в Doctrine ORM”

  1. AmdY:

    по идее нужно использовать Expression, в первой ветке делалось так.
    $model->ternary_field = new Doctrine_Expression(‘NULL’);

Комментировать