Search code examples
phpmysqlormschemapropel

Propel - Joining the same table using multiple foreign keys


I am having an issue with Propel2 (version 2.0.0-dev).

I have three foreign keys pointing to the same table:

<foreign-key foreignTable="sites" phpName="Site" refPhpName="Timesheet">
  <reference local="siteID" foreign="siteID"/>
</foreign-key>
<foreign-key foreignTable="sites" phpName="FromSite">
  <reference local="from_siteID" foreign="siteID"/>
</foreign-key>
<foreign-key foreignTable="sites" phpName="ToSite">
  <reference local="to_siteID" foreign="siteID"/>
</foreign-key>

and despite different PhpNames, the Base Class generates default: $key incorrectly:

if (null !== $this->aToSite) {
        switch ($keyType) {
            case TableMap::TYPE_CAMELNAME:
                $key = 'site';
                break;
            case TableMap::TYPE_FIELDNAME:
                $key = 'sites';
                break;
            default:
                $key = 'Site';
        }
        $result[$key] = $this->aToSite->toArray($keyType, $includeLazyLoadColumns,  $alreadyDumpedObjects, true);
    }

default: $key should be ToSite, not Site. Similarly for FromSite. As a result, the Site table is only joined for Site, but not for FromSite and ToSite, which subsequently doesn't allow me to call objects using FromSite and ToSite.

The tables are joined in the following way:

$timesheets = TimesheetQuery::create()
  ->select(Timesheet::getTransferFieldsWithRelations())
  ...
  ->joinWith("Timesheet.FromSite FromSite", Criteria::LEFT_JOIN)
  ->joinWith("Timesheet.ToSite ToSite", Criteria::LEFT_JOIN)
  ->joinWith("Timesheet.Site Site", Criteria::LEFT_JOIN)
  ...

Is there a way around this?


Solution

  • We managed to fix the above issue. In Propel/Generator/Builder/Om/ObjectBuilder.php, change the following:

    if (\$includeForeignObjects) {";
            foreach ($fks as $fk) {
                $script .= "
            if (null !== \$this->" . $this->getFKVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getForeignTable(), false)}
                \$result[\$key] = \$this->" . $this->getFKVarName($fk) . "->toArray(\$keyType, \$includeLazyLoadColumns,  \$alreadyDumpedObjects, true);
            }";
            }
            foreach ($referrers as $fk) {
                if ($fk->isLocalPrimaryKey()) {
                    $script .= "
            if (null !== \$this->" . $this->getPKRefFKVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getTable(), false)}
                \$result[\$key] = \$this->" . $this->getPKRefFKVarName($fk) . "->toArray(\$keyType, \$includeLazyLoadColumns, \$alreadyDumpedObjects, true);
            }";
                } else {
                    $script .= "
            if (null !== \$this->" . $this->getRefFKCollVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getTable(), true)}
                \$result[\$key] = \$this->" . $this->getRefFKCollVarName($fk) . "->toArray(null, false, \$keyType, \$includeLazyLoadColumns, \$alreadyDumpedObjects);
            }";
                }
            }
            $script .= "
        }";
    

    to

    if (\$includeForeignObjects) {";
            foreach ($fks as $fk) {
                $script .= "
            if (null !== \$this->" . $this->getFKVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getPhpName(), $fk->getForeignTable(), false)}
                \$result[\$key] = \$this->" . $this->getFKVarName($fk) . "->toArray(\$keyType, \$includeLazyLoadColumns,  \$alreadyDumpedObjects, true);
            }";
            }
            foreach ($referrers as $fk) {
                if ($fk->isLocalPrimaryKey()) {
                    $script .= "
            if (null !== \$this->" . $this->getPKRefFKVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getRefPhpName(), $fk->getTable(), false)}
                \$result[\$key] = \$this->" . $this->getPKRefFKVarName($fk) . "->toArray(\$keyType, \$includeLazyLoadColumns, \$alreadyDumpedObjects, true);
            }";
                } else {
                    $script .= "
            if (null !== \$this->" . $this->getRefFKCollVarName($fk) . ") {
                {$this->addToArrayKeyLookUp($fk->getRefPhpName(), $fk->getTable(), true)}
                \$result[\$key] = \$this->" . $this->getRefFKCollVarName($fk) . "->toArray(null, false, \$keyType, \$includeLazyLoadColumns, \$alreadyDumpedObjects);
            }";
                }
            }
            $script .= "
        }";
    

    As well as this:

    protected function addToArrayKeyLookUp(Table $table, $plural)
    {
        $phpName = $table->getPhpName();
        $camelCaseName = $table->getCamelCaseName();
        $fieldName = $table->getName();
    

    to:

    protected function addToArrayKeyLookUp($phpName, Table $table, $plural)
    {
        if($phpName == "") {
            $phpName = $table->getPhpName();  
        }
    
        $camelCaseName = $table->getCamelCaseName();
        $fieldName = $table->getName();
    

    Now I can reference multiple FKs with PHPNames to the same table without any issues.

    Note that the file will change every time Propel is updated.