Using boolean fields with Magento ORM

2019-05-11 04:50发布

问题:

I am working on a backend edit page for my custom entity. I have almost everything working, including saving a bunch of different text fields. I have a problem, though, when trying to set the value of a boolean field.

I have tried:

$landingPage->setEnabled(1);
$landingPage->setEnabled(TRUE);
$landingPage->setEnabled(0);
$landingPage->setEnabled(FALSE);

None seem to persist a change to my database.

How are you supposed to set a boolean field using magento ORM?

edit Looking at my database, mysql is storing the field as a tinyint(1), so magento may be seeing this as an int not a bool. Still can't get it to set though.

回答1:

Delete var/cache/* - your DB schema is cached by Magento even though the new column is already added to the MySQL table.



回答2:

This topic has bring curiosity to me. Although it has been answered, I'd like to share what I've found though I didn't do intense tracing.

It doesn't matter whether the cache is enabled / disabled, the table schema will be cached.

It will be cached during save process.

Mage_Core_Model_Abstract -> save()

Mage_Core_Model_Resource_Db_Abstract -> save(Mage_Core_Model_Abstract $object)


Mage_Core_Model_Resource_Db_Abstract

public function save(Mage_Core_Model_Abstract $object)
{
    ...
    //any conditional will eventually call for:
    $this->_prepareDataForSave($object);
    ...
}

protected function _prepareDataForSave(Mage_Core_Model_Abstract $object)
{
    return $this->_prepareDataForTable($object, $this->getMainTable());
}

Mage_Core_Model_Resource_Abstract

protected function _prepareDataForTable(Varien_Object $object, $table)
{
    $data = array();
    $fields = $this->_getWriteAdapter()->describeTable($table);
    foreach (array_keys($fields) as $field) {
        if ($object->hasData($field)) {
            $fieldValue = $object->getData($field);
            if ($fieldValue instanceof Zend_Db_Expr) {
                $data[$field] = $fieldValue;
            } else {
                if (null !== $fieldValue) {
                    $fieldValue   = $this->_prepareTableValueForSave($fieldValue, $fields[$field]['DATA_TYPE']);
                    $data[$field] = $this->_getWriteAdapter()->prepareColumnValue($fields[$field], $fieldValue);
                } else if (!empty($fields[$field]['NULLABLE'])) {
                    $data[$field] = null;
                }
            }
        }
    }
    return $data;
}

See the line: $fields = $this->_getWriteAdapter()->describeTable($table);

Varien_Db_Adapter_Pdo_Mysql

public function describeTable($tableName, $schemaName = null)
{
    $cacheKey = $this->_getTableName($tableName, $schemaName);
    $ddl = $this->loadDdlCache($cacheKey, self::DDL_DESCRIBE);
    if ($ddl === false) {
        $ddl = parent::describeTable($tableName, $schemaName);
        /**
         * Remove bug in some MySQL versions, when int-column without default value is described as:
         * having default empty string value
         */
        $affected = array('tinyint', 'smallint', 'mediumint', 'int', 'bigint');
        foreach ($ddl as $key => $columnData) {
            if (($columnData['DEFAULT'] === '') && (array_search($columnData['DATA_TYPE'], $affected) !== FALSE)) {
                $ddl[$key]['DEFAULT'] = null;
            }
        }
        $this->saveDdlCache($cacheKey, self::DDL_DESCRIBE, $ddl);
    }

    return $ddl;
}

As we can see:

$ddl = $this->loadDdlCache($cacheKey, self::DDL_DESCRIBE);

will try to load the schema from cache.

If the value is not exists: if ($ddl === false)

it will create one: $this->saveDdlCache($cacheKey, self::DDL_DESCRIBE, $ddl);

So the problem that occurred in this question will be happened if we ever save the model that is going to be altered (add column, etc).

Because it has ever been $model->save(), the schema will be cached. Later after he add new column and "do saving", it will load the schema from cache (which is not containing the new column) and resulting as: the data for new column is failed to be saved in database