Issues

ZF-6232: findManyToManyRowset() returns columns from the intersection table

Description

Hello,

I've found that the method findManyToManyRowset() from the Zend_Db_Table_Row_Abstract returns all columns both from the matching and intersection tables in the resulting rowset. Is that safe? I mean what happens if the matching and intersection table have a same column name with different values? Would the results be valid? However the $select sets integrityCheck off and consequently the result rowset's readOnly flag off too.

I believe that the result rowset should not contain any values from the intersection table or optionaly some column collision checking should be done. At least, if the resulting rowset contains any values from the intersection table, it should be marked readOnly for sake.

Best regards, Ludek Stepan

Comments

Hi,

I believe this is linked to http://framework.zend.com/issues/browse/ZF-3709

Inside Zend_Db_Table_Row_Abstract line 1053 onwards we have

 $select->from(array('i' => $interName), Zend_Db_Select::SQL_WILDCARD, $interSchema)
               ->joinInner(array('m' => $matchName), $joinCond, Zend_Db_Select::SQL_WILDCARD, $matchSchema)
               ->setIntegrityCheck(false);

I believe the from column declaration is causing the issue and should be

 $select->from(array('i' => $interName), array(), $interSchema)
               ->joinInner(array('m' => $matchName), $joinCond, Zend_Db_Select::SQL_WILDCARD, $matchSchema)
               ->setIntegrityCheck(false);

to hide all the columns of the intersection table. This would then matchup with the documentation in http://framework.zend.com/manual/en/…

Comment converted to patch file.

Attached patch with fix and adjustment to a unit test to verify

Fixed in trunk 21100 and in release branch 1.10 in 21102

First, i believe this is a behaviour not suited to be changed in a minor version.

I have to agree that overlapping column names could invalidate the result set.

However i disagree with issue 3709 that any subsequent {{save()}} will fail with an exception as it would only fail if you explicitly {{set()}} a column of the intersection table, wich does not make any sense.

We would like to adapt these changes as they make our domain model code somewhat less complicated, but we are running into issues.

Previously we used to display a ManyToMany-Rowset using all columns [i.id_r, i.id_m, m.id, m.value]. Then manipulate it and then synchronize it to a Dependent-Rowset using only the columns that represent the intersection [i.id_r, i.id_m]. This is still possible by translating/fixing the column names from [m.id] to [i.id_r (given), i.id_m].

However we are facing an issue when we actually need a value from the intersection table, in other words when the relation contains some data. I have tried to give a Zend_Db_Table_Select statement to findManyToManyRowset(). bq. {{$this->select()->columns(array('i' => 'value'));}} This fails because the intersection Table has not been defined. bq. Zend_Db_Select(255): No table has been specified for the FROM clause

+Do we really have to findDependents and then findParents on this rowset to get the information we could retrieve just fine before?+

Another quick but possibly dirty solution would be to revert the behaviour of this fix by overloading findManyToManyRowset with


if( $select === null )
{
  if( is_string($intersectionTable) )
  {
    $intersectionTable = $this->_getTableFromString($intersectionTable);
  }
  $select = $intersectionTable->select(true);
}

before calling the parent method.

Anyway i'd like this bug to be reopened because of the issue: +It is not easily possible to include intersection values that are actually needed.+

I'm going to agree with Christoph here. This one came as a bit of a surprise in a minor release.

For what it is worth I just spent 4 hours trying to track down a problem which turns out to be due to this change. Working code dependent on the documented behaviour that the result set contains data from the intersection table. Docs say "This method returns a Zend_Db_Table_Rowset_Abstract containing rows from the table $table, satisfying the many-to-many relationship. The current Row object $row from the origin table is used to find rows in the intersection table, and that is joined to the destination table. " Not nice to break working code in a minor release.

I've extraced my solution to a Workaround: http://gist.github.com/554965

Commentary and workaround on this issue has been blogged about here: http://ralphschindler.com/2010/11/…

-ralph