/** * {@inheritDoc} */ public function save($entity, array $options = []) { $query = $this->queryBuilder->save($this->entityMetadata, $options)->entity($entity); try { $saveResult = $this->doQuery($query, ["output" => "raw"]); } catch (\PDOException $e) { $pkMetadata = $this->entityMetadata->getPrimaryKeyMetadata(); // if this entity has an auto incrementing PK, or the error is not about PK conflicts, re-throw the error if ($pkMetadata[EntityMetadata::METADATA_FIELD_AUTO_INCREMENTING] == true || $e->errorInfo[0] != self::ANSI_DUPLICATE_KEY_ERROR_CODE) { throw $e; } // this is a duplicate key on a collection with a PK that does not auto increment. // force the save to be an update $query->setOption("saveType", "update"); $saveResult = $this->doQuery($query, ["output" => "raw"]); } // get the primary key value, if there is one, and save it on the entity if (isset($saveResult[StorageInterface::NEW_INSERT_ID_RETURN_FIELD])) { $pkValue = $saveResult[StorageInterface::NEW_INSERT_ID_RETURN_FIELD]; $this->entityMetadata->setEntityValue($entity, $this->entityMetadata->getPrimaryKey(), $pkValue); } else { $pkValue = null; } // save "* to many" relationships foreach ($this->entityMetadata->getRelationships() as $alias => $relationship) { $type = $relationship[EntityMetadata::METADATA_RELATIONSHIP_TYPE]; $property = $relationship[EntityMetadata::METADATA_RELATIONSHIP_PROPERTY]; $childValue = $this->entityMetadata->getEntityValue($entity, $property); if ($type == EntityMetadata::RELATIONSHIP_TYPE_ONE_TO_ONE) { // This covers "many to one" as well if (!empty($this->relationshipCascade[$alias])) { /** @var RepositoryInterface $childRepo */ $childRepo = $this->relationshipCascade[$alias]; $childRepo->save($childValue); } // nothing more to do for One to One / Many to One continue; } /* We need to know the following: * Which child entities have been added and removed * The field names used on both sides of the relationship * The corresponding values for both the parent and child entities */ if (!$childValue instanceof Collection) { // if this isn't a collection object we can't process this relationship continue; } // get the field used on the child entity $childMetadata = $this->metadataProvider->getEntityMetadata($relationship[EntityMetadata::METADATA_ENTITY]); $theirField = !empty($relationship[EntityMetadata::METADATA_RELATIONSHIP_THEIR_FIELD]) ? $relationship[EntityMetadata::METADATA_RELATIONSHIP_THEIR_FIELD] : $childMetadata->getPrimaryKey(); // get the field and value used on the parent entity $ourValue = null; $ourField = null; // if we haven't specified a field for the parent, use the primary key if (empty($relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD])) { // using the PK if ($pkValue !== null) { // This was a new record and we already have the value for the parent PK, so set it now $ourValue = $pkValue; } $ourField = $this->entityMetadata->getPrimaryKey(); } else { $ourField = $relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD]; } // get the parent value if it isn't set already if ($ourValue === null) { $ourValue = $this->entityMetadata->getEntityValue($entity, $ourField); } // update the relationship if ($type == EntityMetadata::RELATIONSHIP_TYPE_ONE_TO_MANY) { $this->saveOneToMany($alias, $childValue, $childMetadata, $ourValue, $theirField); } elseif ($type == EntityMetadata::RELATIONSHIP_TYPE_MANY_TO_MANY) { $this->saveManyToMany($relationship, $alias, $childValue, $childMetadata, $ourValue, $ourField, $theirField); } } return $saveResult; }