использование zend test dbadapter с абстрактной таблицей zend db

Кто-нибудь смог использовать Zend_Test_DbAdapter с Zend_Db_Table_Abstract?

Я пытаюсь протестировать созданную мной модель, которая расширяет Zend_Db_Table_Abstract, и я получаю исключение относительно того, что первичный ключ не установлен, если я использую Zend_Test_DbAdapter (другие адаптеры, такие как mysql или sqlite), работают нормально.


class Model_Category extends Zend_Db_Table_Abstract
{
    protected $_name = 'categories';

    protected $_dependentTables = array('Model_Video');

    public function getMap()
    {
        $map = array();
        $rows = $this->fetchAll();
        foreach($rows as $row)
        {
            $map[$row->id] = $row->name;
        }

        return $map;
    }
}

Фрагмент из тестового класса PHPUnit:

protected function setUp()
{
    $adapter = new Zend_Test_DbAdapter();
    $stmt = Zend_Test_DbStatement::createSelectStatement(array(
        array('id' => 1, 'name' => 'pranks'),
        array('id' => 2, 'name' => 'physical_feats'),
        array('id' => 3, 'name' => 'art'),
        array('id' => 4, 'name' => 'cute'),
        array('id' => 5, 'name' => 'philanthropy')
    ));
    $adapter->appendStatementToStack($stmt);

    $this->fixture = new Model_Category($adapter);
}

Исключения генерируются при выполнении методов модели:

public function testGetMap()
{
    $expected = array(
        '1' => 'pranks',
        '2' => 'physical_feats',
        '3' => 'art',
        '4' => 'cute',
        '5' => 'philanthropy'
    );
    $actual = $this->fixture->getMap();
    $this->assertEquals($expected, $actual);
}

Результат:

Model_CategoryTest::testGetMap()
Zend_Db_Table_Exception: A table must have a primary key, but none was found
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:876
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:969
ZendFramework-1.10.6/library/Zend/Db/Table/Select.php:100
ZendFramework-1.10.6/library/Zend/Db/Table/Select.php:78
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:1005
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:1303
application/models/Category.php:35
tests/unit/application/models/CategoryTest.php:90

Принудительное использование первичного ключа также не работает:

protected function setUp()
{
    $adapter = new Zend_Test_DbAdapter();
    $stmt = Zend_Test_DbStatement::createSelectStatement(array(
        array('id' => 1, 'name' => 'pranks'),
        array('id' => 2, 'name' => 'physical_feats'),
        array('id' => 3, 'name' => 'art'),
        array('id' => 4, 'name' => 'cute'),
        array('id' => 5, 'name' => 'philanthropy')
    ));
    $adapter->appendStatementToStack($stmt);

    $this->fixture = new Model_Category(array(
        'db' => $adapter,
        'primary' => 'id'
    ));
}

Выполнение того же модульного теста, приведенного выше, приводит к:

Model_CategoryTest::testGetMap()
Zend_Db_Table_Exception: Primary key column(s) (id) are not columns in this table ()
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:888
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:969
ZendFramework-1.10.6/library/Zend/Db/Table/Select.php:100
ZendFramework-1.10.6/library/Zend/Db/Table/Select.php:78
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:1005
ZendFramework-1.10.6/library/Zend/Db/Table/Abstract.php:1303
application/models/Category.php:35
tests/unit/application/models/CategoryTest.php:93

person Nick    schedule 14.10.2012    source источник
comment
Можете ли вы опубликовать код для своей модели и какова трассировка стека исключения?   -  person drew010    schedule 15.10.2012
comment
Я добавил код и трассировки к своему исходному сообщению. Я надеюсь, что это поможет. Я должен упомянуть, что номера строк, указанные для Category.php и CategoryTest.php в трассировках, неверны, потому что я сжал исходный код для этого поста.   -  person Nick    schedule 17.10.2012
comment
В обоих случаях трассировка ссылается на $rows = $this-›fetchAll() в Category.php и $actual = $this-›fixture-›getMap(); в CategoryTest.php.   -  person Nick    schedule 17.10.2012


Ответы (2)


Вы можете определить первичный ключ, выполнив следующие действия в своем экземпляре Zend_Test_DbAdapter:

$adapter = new Zend_Test_DbAdapter();
$adapter->setDescribeTable('table_name', array('column_name' =>
    array(
        'SCHEMA_NAME' => 'schema_name',
        'TABLE_NAME'  => 'table_name'
        'COLUMN_NAME' => 'column_name',     
        'PRIMARY'     => true
    )
));

А затем транспонирование table_name, column_name и schema_name со значениями из вашей реализации. Вам нужно будет сделать это для каждой таблицы, с которой вы взаимодействуете в тестируемом классе.

person Thys Swart    schedule 05.11.2012
comment
Это решило часть проблемы, но выявило новую связанную проблему. Когда вызывается метод Zend_Db_Adapter_Abstract fetchPairs(), $row[0] и $row[1] не существуют. Это потому, что $stmt-›fetch(Zend_Db::FETCH_NUM) каким-то образом по-прежнему возвращает ассоциативный массив, а не числовой массив. - person Nick; 14.11.2012

Причина, по которой вы получаете исключение Zend_Db_Table_Exception: A table must have a primary key, but none was found, заключается в том, что все таблицы, использующие Zend_Db_Table, должны иметь определенный первичный ключ. Когда вы переходите к использованию таблицы, поскольку первичный ключ не был определен в вашем классе DbTable, Zend_Db пытается определить первичный ключ таблицы, изучая свойства таблицы из информационной схемы. Он видит, что ваша таблица не имеет первичного ключа и терпит неудачу.

Из руководства :

Если вы не укажете первичный ключ, Zend_Db_Table_Abstract попытается обнаружить первичный ключ на основе информации, предоставленной методом describeTable().

Примечание. Каждый класс таблиц должен знать, какие столбцы можно использовать для уникальной адресации строк. Если столбцы первичного ключа не указаны в определении класса таблицы или аргументах конструктора таблицы или не обнаружены в метаданных таблицы, предоставленных **describeTable(), тогда таблицу нельзя использовать с Zend_Db_Table.

Попытка принудительно использовать первичный ключ не работает, потому что похоже, что в вашей таблице нет столбца с именем id, который вы указываете в качестве первичного ключа.

Решением будет добавление первичного ключа к таблице, которую вы пытаетесь использовать.

В вашем классе модели, который расширяет Zend_Db_Table_Abstract, вы можете указать первичный ключ, который не является идентификатором, используя protected $_primary = 'primary_column';

person drew010    schedule 17.10.2012
comment
Спасибо за ответ! Проблема в том, что я пытаюсь использовать Zend_Test_DbAdapter для тестирования. Этот адаптер не подключается к реальной базе данных и, следовательно, не имеет представления о метаданных таблицы (насколько мне известно). - person Nick; 22.10.2012
comment
Это правда, но она распространяется от Zend_Db_Table_Abstract, который выполняет эту проверку очень рано в построении, поэтому вы получаете ошибку. Это тестирование, вам все равно нужно установить первичный ключ, который вам все равно придется делать в производстве. Добавление определения для первичного ключа должно устранить ошибку. - person drew010; 22.10.2012
comment
Как я уже говорил, Zend_Test_DbAdapter не имеет концепции метаданных, поэтому ни один столбец не может быть установлен в качестве первичного ключа. В конце концов, я думаю, вы ответили на мой вопрос: поскольку для Zend_Db_Table_Abstract требуется первичный ключ, Zend_Test_DbAdapter использовать нельзя. Это стыд... - person Nick; 24.10.2012
comment
Просто кажется, что если вы добавили фиктивный protected $_primary = 'id'; в свою модель категории, ошибка должна исчезнуть. - person drew010; 24.10.2012