ZF-9704: Undefined offset in Zend_Db_Table_Row_Abstract::findDependentRowset()

Description

Create tables like in http://framework.zend.com/manual/en/… . Execute Example #1.

How to reproduce. 1. Add to class BugsProducts properties $_cols and $_primary. 2. Execute Example #1.

Problem: Undefined offset in Zend_Db_Table_Row_Abstract on line 902.

Reason. When $_cols and $_primary defined in class, metadata of table is not filled out and $dependentInfo[Zend_Db_Table_Abstract::METADATA] contains empty array (in Zend_Db_Table_Row_Abstract on line 902).

Comments

There is same problem (undefined index) for find() function Zend_Db_Table_Abstract on line 1265

Can you please provide a bit more information on how your modified class looks like? I am not able to reproduce this error.

Hi, Could you please take a look to code below?



<?php

/*

CREATE TABLE `test`.`accounts` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 5 ) NOT NULL
) ENGINE = MYISAM ;

INSERT INTO `test`.`accounts` (
`id` ,
`name`
)
VALUES (
'1234', 'test'
);


CREATE TABLE `test`.`bugs` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`reported_by` INT NOT NULL
) ENGINE = MYISAM ;

INSERT INTO `test`.`bugs` (
`id` ,
`reported_by`
)
VALUES (
'1', '1234'
);

*/

require_once 'Zend/Db/Table/Abstract.php';

$db_config = array(
    'adapter'         => 'PDO_MYSQL',
    'params' => array (
        'dbname' => 'test',
        'host'   => 'localhost',
        'username' => 'root',
        'password' => '',
    ),
);

$db = Zend_Db::factory($db_config['adapter'], $db_config['params']);

$db->setFetchMode(Zend_Db::FETCH_ASSOC);
Zend_Db_Table_Abstract::setDefaultAdapter($db);

class Accounts extends Zend_Db_Table_Abstract
{
    protected $_name            = 'accounts';
    protected $_dependentTables = array('Bugs');
    
    protected $_cols = array('id', 'name');
    protected $_primary = 'id';
}


class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name            = 'bugs';
    protected $_referenceMap    = array(
        'Reporter' => array(
            'columns'           => 'reported_by',
            'refTableClass'     => 'Accounts',
            'refColumns'        => 'id'
        ),
    );
    protected $_cols = array('id', 'reported_by');
    protected $_primary = 'id'; 
}


$accountsTable = new Accounts();
$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();
$bugsReportedByUser = $user1234->findDependentRowset('Bugs');

var_dump($bugsReportedByUser->toArray());

and run it

{quote} D:>php testbug.php PHP Notice: Undefined index: id in \Zend\Db\Table\Abstract.php on line 1265 PHP Stack trace: PHP 1. main D:\testbug.php:0 PHP 2. Zend_Db_Table_Abstract->find(1234) D:\testbug.php:78

Notice: Undefined index: id in \Zend\Db\Table\Abstract.php on line 1265

Call Stack: 0.0005 332816 1. main D:\testbug.php:0 0.0247 1792376 2. Zend_Db_Table_Abstract->find(1234) D:\testbug.php:78

PHP Notice: Undefined index: reported_by in \Zend\Db\Table\Row\Abstract.php on line 902 PHP Stack trace: PHP 1. main D:\testbug.php:0 PHP 2. Zend_Db_Table_Row_Abstract->findDependentRowset($dependentTable = 'Bugs', $ruleKey = uninitialized, $select = uninitialized) D:\testbug.php:80

Notice: Undefined index: reported_by in \Zend\Db\Table\Row\Abstract.php on line 902

Call Stack: 0.0005 332816 1. main D:\testbug.php:0 0.0440 2217512 2. Zend_Db_Table_Row_Abstract->findDependentRowset('Bugs', ???, ???) D:\testbug.php:80

array(1) [0]=> array(2) ["id"]=> string(1) "1" ["reported_by"]=> string(4) "1234"

{quote}

Thanks, now I am able to reproduce this error.

Your tables are a bit different than these in the manual.

This could be a possible fix but I need to verify to not break backward compatibility and/or any unittest.

Index: library/Zend/Db/Table/Abstract.php
===================================================================
--- library/Zend/Db/Table/Abstract.php  (revision 22190)
+++ library/Zend/Db/Table/Abstract.php  (working copy)
@@ -844,6 +844,8 @@
         if (null === $this->_cols) {
             $this->_setupMetadata();
             $this->_cols = array_keys($this->_metadata);
+        } elseif (empty($this->_metadata)) {
+            $this->_setupMetadata();
         }
         return $this->_cols;
     }

I add $_cols and $_primary to prevent "DESCRIBE table" request which called from _setupMetadata(). But you want to change this behavior. Is it possible to fix the bug without calling _setupMetadata()?

Thanks.