private function computeAssociationChanges($assoc, $value)
{
// Look through the entities, and in any of their associations, for transient (new)
// enities, recursively. ("Persistence by reachability")
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($value instanceof Proxy && !$value->__isInitialized__) {
return;
// Ignore uninitialized proxy objects
}
$value = array($value);
} else {
if ($value instanceof PersistentCollection) {
// Unwrap. Uninitialized collections will simply be empty.
$value = $value->unwrap();
}
}
foreach ($value as $entry) {
$targetClass = $this->dm->getClassMetadata($assoc['targetDocument'] ?: get_class($entry));
$state = $this->getDocumentState($entry);
$oid = spl_object_hash($entry);
if ($state == self::STATE_NEW) {
if (!($assoc['cascade'] & ClassMetadata::CASCADE_PERSIST)) {
throw new \InvalidArgumentException("A new document was found through a relationship that was not" . " configured to cascade persist operations: " . self::objToStr($entry) . "." . " Explicitly persist the new document or configure cascading persist operations" . " on the relationship.");
}
$this->persistNew($targetClass, $entry);
$this->computeChangeSet($targetClass, $entry);
} else {
if ($state == self::STATE_REMOVED) {
return new \InvalidArgumentException("Removed document detected during flush: " . self::objToStr($entry) . ". Remove deleted documents from associations.");
} else {
if ($state == self::STATE_DETACHED) {
// Can actually not happen right now as we assume STATE_NEW,
// so the exception will be raised from the DBAL layer (constraint violation).
throw new \InvalidArgumentException("A detached document was found through a " . "relationship during cascading a persist operation.");
}
}
}
// MANAGED associated entities are already taken into account
// during changeset calculation anyway, since they are in the identity map.
}
}