diff --git a/xpdo/om/xpdoobject.class.php b/xpdo/om/xpdoobject.class.php index 3480910e..d90c0424 100644 --- a/xpdo/om/xpdoobject.class.php +++ b/xpdo/om/xpdoobject.class.php @@ -1275,9 +1275,12 @@ public function addOne(& $obj, $alias= '') { * to this instance via the intersection class. * @param string $alias An optional alias, required only for instances where * you have more than one relation defined to the same class. + * @param boolean $graph For object graph use only. If true, the existing object + * with the same value of the primary key will not be overwritten and + * will be used to overwrite the given instance. * @return boolean Indicates if the addMany was successful. */ - public function addMany(& $obj, $alias= '') { + public function addMany(& $obj, $alias= '', $graph= false) { $added= false; if (!is_array($obj)) { if (is_object($obj)) { @@ -1301,9 +1304,20 @@ public function addMany(& $obj, $alias= '') { $objpk= implode('-', $objpk); } } - $this->_relatedObjects[$alias][$objpk]= $obj; - if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Added related object with alias: ' . $alias . ' and pk: ' . $objpk . "\n" . print_r($obj->toArray('', true), true)); - $added= true; + if ($graph) { + if (isset($this->_relatedObjects[$alias][$objpk])) { + if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Skipped already existing graph node object with alias: ' . $alias . ' and pk: ' . $objpk . "\n" . print_r($obj->toArray('', true), true)); + $obj= $this->_relatedObjects[$alias][$objpk]; + } else { + if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Binded graph node object with alias: ' . $alias . ' and pk: ' . $objpk . "\n" . print_r($obj->toArray('', true), true)); + $this->_relatedObjects[$alias][$objpk] = $obj; + $added= true; + } + } else { + $this->_relatedObjects[$alias][$objpk]= $obj; + if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Added related object with alias: ' . $alias . ' and pk: ' . $objpk . "\n" . print_r($obj->toArray('', true), true)); + $added= true; + } } } } diff --git a/xpdo/om/xpdoquery.class.php b/xpdo/om/xpdoquery.class.php index 17f3e7a5..b708e0a3 100644 --- a/xpdo/om/xpdoquery.class.php +++ b/xpdo/om/xpdoquery.class.php @@ -509,33 +509,31 @@ public function bindGraphNode($parentClass, $parentAlias, $classAlias, $relation $foreign= $fkMeta['foreign']; $this->select($this->xpdo->getSelectColumns($class, $classAlias, $classAlias . '_')); $expression= $this->xpdo->escape($parentAlias) . '.' . $this->xpdo->escape($local) . ' = ' . $this->xpdo->escape($classAlias) . '.' . $this->xpdo->escape($foreign); - if (isset($fkMeta['criteria']['local'])) { - $localCriteria = array(); - if (is_array($fkMeta['criteria']['local'])) { - foreach ($fkMeta['criteria']['local'] as $critKey => $critVal) { - if (is_numeric($critKey)) { - $localCriteria[] = $critVal; - } else { - $localCriteria["{$classAlias}.{$critKey}"] = $critVal; - } + $localCriteria = array(); + if (isset($fkMeta['criteria']['local']) && is_array($fkMeta['criteria']['local'])) { + foreach ($fkMeta['criteria']['local'] as $critKey => $critVal) { + if (is_numeric($critKey)) { + $localCriteria[] = $critVal; + } else { + $localCriteria["{$parentAlias}.{$critKey}"] = $critVal; } } - if (!empty($localCriteria)) { - $expression = array($localCriteria, $expression); - } - $foreignCriteria = array(); - if (is_array($fkMeta['criteria']['foreign'])) { - foreach ($fkMeta['criteria']['foreign'] as $critKey => $critVal) { - if (is_numeric($critKey)) { - $foreignCriteria[] = $critVal; - } else { - $foreignCriteria["{$parentAlias}.{$critKey}"] = $critVal; - } + } + if (!empty($localCriteria)) { + $expression = array($localCriteria, $expression); + } + $foreignCriteria = array(); + if (isset($fkMeta['criteria']['foreign']) && is_array($fkMeta['criteria']['foreign'])) { + foreach ($fkMeta['criteria']['foreign'] as $critKey => $critVal) { + if (is_numeric($critKey)) { + $foreignCriteria[] = $critVal; + } else { + $foreignCriteria["{$classAlias}.{$critKey}"] = $critVal; } } - if (!empty($foreignCriteria)) { - $expression = array($foreignCriteria, $expression); - } + } + if (!empty($foreignCriteria)) { + $expression = array($foreignCriteria, $expression); } $this->leftJoin($class, $classAlias, $expression); if (!empty ($relations)) { @@ -609,23 +607,24 @@ public function hydrateGraphParent(& $instances, $row) { public function hydrateGraphNode(& $row, & $instance, $alias, $relations) { $relObj= null; if ($relationMeta= $instance->getFKDefinition($alias)) { + $cardinality = strtolower($relationMeta['cardinality']); if ($row[$alias.'_'.$relationMeta['foreign']] != null) { - $relObj = $this->xpdo->call($relationMeta['class'], '_loadInstance', array(& $this->xpdo, $relationMeta['class'], $alias, $row)); - if ($relObj) { - if (strtolower($relationMeta['cardinality']) == 'many') { - $instance->addMany($relObj, $alias); - } else { - $instance->addOne($relObj, $alias); - } + if ($cardinality === 'many' || empty($instance->_relatedObjects[$alias])) { + $relObj = $this->xpdo->call($relationMeta['class'], '_loadInstance', array(& $this->xpdo, $relationMeta['class'], $alias, $row)); + } else { + $relObj = $instance->_relatedObjects[$alias]; + } + if ($cardinality === 'many') { + $instance->addMany($relObj, $alias, true); + } else { + $instance->addOne($relObj, $alias); } } } if (!empty ($relations) && is_object($relObj)) { while (list($relationAlias, $subRelations)= each($relations)) { if (is_array($subRelations) && !empty($subRelations)) { - foreach ($subRelations as $subRelation) { - $this->hydrateGraphNode($row, $relObj, $relationAlias, $subRelation); - } + $this->hydrateGraphNode($row, $relObj, $relationAlias, $subRelations); } else { $this->hydrateGraphNode($row, $relObj, $relationAlias, null); }