diff --git a/lib/classes/JsonApi/Routes/Courseware/ContainersCopy.php b/lib/classes/JsonApi/Routes/Courseware/ContainersCopy.php index 087483994292b40fb291e8c01261fcf6c544309a..cbef54c762e239b10d792d567390e1fcc3481427 100644 --- a/lib/classes/JsonApi/Routes/Courseware/ContainersCopy.php +++ b/lib/classes/JsonApi/Routes/Courseware/ContainersCopy.php @@ -45,7 +45,7 @@ class ContainersCopy extends NonJsonApiController private function copyContainer(\User $user, \Courseware\Container $remote_container, \Courseware\StructuralElement $element) { - $container = $remote_container->copy($user, $element); + list($container, $blockMapObjs) = $remote_container->copy($user, $element); return $container; } diff --git a/lib/models/Courseware/Container.php b/lib/models/Courseware/Container.php index 1f621e5c88343efef56dbc2a2c5dd5ce91e649b8..088f53959c44dd5a05d24b5714f80ac83d2e580d 100644 --- a/lib/models/Courseware/Container.php +++ b/lib/models/Courseware/Container.php @@ -104,9 +104,9 @@ class Container extends \SimpleORMap * @param User $user the owner and editor of the new copy of this block * @param StructuralElement $element the structural element this block will be copied into * - * @return Container the copy of this Container + * @return array an array containing the container object and the block maps */ - public function copy(User $user, StructuralElement $element): Container + public function copy(User $user, StructuralElement $element): array { $container = self::build([ 'structural_element_id' => $element->id, @@ -120,24 +120,26 @@ class Container extends \SimpleORMap $container->store(); - $blockMap = $this->copyBlocks($user, $container); + list($blockMapIds, $blockMapObjs) = $this->copyBlocks($user, $container); - $container['payload'] = $container->type->copyPayload($blockMap); + $container['payload'] = $container->type->copyPayload($blockMapIds); $container->store(); - return $container; + return [$container, $blockMapObjs]; } private function copyBlocks(User $user, Container $newContainer): array { $blockMap = []; + $newBlockList = []; foreach ($this->blocks as $block) { $newBlock = $block->copy($user, $newContainer); $blockMap[$block->id] = $newBlock->id; + $newBlockList[$block->id] = $newBlock; } - return $blockMap; + return [$blockMap, $newBlockList]; } } diff --git a/lib/models/Courseware/StructuralElement.php b/lib/models/Courseware/StructuralElement.php index ca5a7b7f281c4f9379c285558a7809f972e09ad2..3cfca284999316e289bf8353bfb02d81a53f8b8f 100644 --- a/lib/models/Courseware/StructuralElement.php +++ b/lib/models/Courseware/StructuralElement.php @@ -809,16 +809,19 @@ SQL; * * @param User $user this user will be the owner of the copy * @param StructuralElement $parent the target where to copy this instance + * @param string $purpose the purpose of copying this instance + * @param string $recursiveId the optional mapping id for copying child structural elements upon recursive call to this function * * @return StructuralElement the copy of this instance */ - public function copy(User $user, StructuralElement $parent, string $purpose = ''): StructuralElement + public function copy(User $user, StructuralElement $parent, string $purpose = '', string $recursiveId = ''): StructuralElement { $ancestorIds = array_column($parent->findAncestors(), 'id'); $ancestorIds[] = $parent->id; if (in_array($this->id, $ancestorIds)) { throw new \InvalidArgumentException('Cannot copy into descendants.'); } + static $mapping = []; $file_ref_id = $this->copyImage($user, $parent); @@ -840,9 +843,26 @@ SQL; $element->store(); - $this->copyContainers($user, $element); + list($containerMap, $blockMap) = $this->copyContainers($user, $element); - $this->copyChildren($user, $element, $purpose); + $mappingId = $recursiveId === '' ? $this->id . '_' . $element->id : $recursiveId; + if (!isset($mapping[$mappingId])) { + $mapping[$mappingId] = [ + 'elements' => [], + 'containers' => [], + 'blocks' => [], + ]; + } + $mapping[$mappingId]['elements'][$this->id] = $element->id; + $mapping[$mappingId]['containers'] = $mapping[$mappingId]['containers'] + $containerMap; + $mapping[$mappingId]['blocks'] = $mapping[$mappingId]['blocks'] + $blockMap; + + $this->copyChildren($user, $element, $purpose, $mappingId); + + if ($recursiveId === '') { + $this->performMapping($mapping[$mappingId]); + unset($mapping[$mappingId]); + } return $element; } @@ -914,17 +934,22 @@ SQL; return $this; } - private function copyContainers(User $user, StructuralElement $newElement): void + private function copyContainers(User $user, StructuralElement $newElement): array { + $containerMap = []; + $blockMap = []; foreach ($this->containers as $container) { - $container->copy($user, $newElement); + list($newContainer, $blockMapsObjs) = $container->copy($user, $newElement); + $containerMap[$container->id] = $newContainer->id; + $blockMap = $blockMap + $blockMapsObjs; } + return [$containerMap, $blockMap]; } - private function copyChildren(User $user, StructuralElement $newElement, string $purpose = ''): void + private function copyChildren(User $user, StructuralElement $newElement, string $purpose = '', string $recursiveId = ''): void { foreach ($this->children as $child) { - $child->copy($user, $newElement, $purpose); + $child->copy($user, $newElement, $purpose, $recursiveId); } } @@ -1046,4 +1071,23 @@ SQL; return $this->parent->findParentTask(); } + + private function performMapping($mapping) + { + // Blocks mapping. + foreach ($mapping['blocks'] as $oldBlockId => $newBlockObj) { + if ($newBlockObj->type->getType() === \Courseware\BlockTypes\Link::getType()) { + $payload = $newBlockObj->type->getPayload(); + if ($payload['type'] === 'internal' && '' != $payload['target']) { + if (in_array($payload['target'], array_keys($mapping['elements']))) { + $payload['target'] = $mapping['elements'][intval($payload['target'])]; + } else { + $payload['target'] = ''; + } + $newBlockObj->type->setPayload($payload); + $newBlockObj->store(); + } + } + } + } }