/** * Saves relationship data to a link table containing the id's of both objects. * * This method inserts / updates the foreign objects. * Missing foreign objects will be removed from the link table, but not deleted. * * @param DataObjectInterface[] $objects * @param string $className Class name of foreign objects to load * @param string $linkTable Table that links two objects together * @param string $foreignObjectGetter Name of getter to retrieve foreign objects * @param string $idColumn Column on link table = the id on this object * @param string $foreignIdColumn Column on link table = the id on the foreign object table */ public function saveManyToMany(array $objects, $className, $linkTable, $foreignObjectGetter = null, $idColumn = null, $foreignIdColumn = null) { if (empty($objects)) { return; } if (!$foreignObjectGetter) { $foreignObjectGetter = 'get' . $this->inflector->methodNameFromClass($className, true); } $foreignObjectsToSave = []; foreach ($objects as $object) { if (!method_exists($object, $foreignObjectGetter)) { throw new MethodNotImplementedException("{$foreignObjectGetter} must be defined on {$object->getClassName()} to save relationship"); } /** @var DataObjectInterface[] $foreignObjects */ $foreignObjects = $object->{$foreignObjectGetter}(); if (!empty($foreignObjects)) { if (!is_array($foreignObjects)) { throw new MethodNotImplementedException("{$foreignObjectGetter} on {$object->getClassName()} must return an array to save relationship"); } foreach ($foreignObjects as $foreignObject) { $foreignObjectsToSave[] = $foreignObject; } } } $this->objectMapper->unitOfWork()->executeTransaction(function () use($foreignObjectsToSave, $objects, $className, $linkTable, $foreignObjectGetter, $idColumn, $foreignIdColumn) { $this->objectMapper->saveAll($foreignObjectsToSave); $this->saveManyToManyLinks($objects, $className, $linkTable, $foreignObjectGetter, $idColumn, $foreignIdColumn); }); }
/** * Loads a foreign relationship where a column on another object references the id for the supplied objects. * * Used to load the "many" side of a one-to-many relationship. * * @param DataObjectInterface[] $objects * @param string $className Class name of foreign objects to load * @param string $foreignColumn Property on foreign object that relates to this object id * @return DataObjectInterface[] Loaded objects keyed by id */ public function loadMany(array $objects, $className, $foreignColumn) { if (empty($objects)) { return []; } $ids = DataObject::getIds($objects); $where = [$foreignColumn => $ids]; $dbColumns = $this->objectMapper->getQueryHelper()->getDbColumns($className::getTableName()); if (isset($dbColumns['isDeleted'])) { $where['isDeleted'] = 0; } $foreignObjects = $this->objectMapper->findBy($className, $where); $foreignObjectsById = []; $getter = 'get' . ucfirst($foreignColumn); foreach ($foreignObjects as $foreignObject) { if (method_exists($foreignObject, $getter)) { $id = $foreignObject->{$getter}(); $foreignObjectsById[$id][] = $foreignObject; } else { throw new MethodNotImplementedException("{$getter} must be defined on {$className} to load one-to-many relationship with {$foreignObject->getClassName()}"); } } $setter = 'set' . $this->inflector->methodNameFromClass($className, true); foreach ($objects as $object) { if (method_exists($object, $setter)) { if (isset($foreignObjectsById[$object->getId()])) { $object->{$setter}($foreignObjectsById[$object->getId()]); } } else { throw new MethodNotImplementedException("{$setter} must be defined on {$object->getClassName()} to load one-to-many relationship with {$className}"); } } $flattenedForeignObjects = []; foreach ($foreignObjectsById as $array) { /** @var DataObjectInterface $object */ foreach ($array as $object) { $flattenedForeignObjects[$object->getId()] = $object; } } return $flattenedForeignObjects; }