/** * Recursively creates and appends sequence block nodes to the XML document. * * @param \DomDocument $dom the document object * @param \DomElement $sequenceNode the sequence DOM node to append to * @param CurriculumInventorySequenceBlockInterface $block the current sequence block * @param array $eventReferences A reference map of sequence blocks to events. * @param array $competencyObjectReferences A reference map of sequence blocks to competency objects. * @param \DomElement|null $parentSequenceBlockNode the DOM node representing the parent sequence block. * @param int $order of this sequence block in relation to other nested sequence blocks. '0' if n/a. */ protected function createSequenceBlockNode(\DomDocument $dom, \DomElement $sequenceNode, CurriculumInventorySequenceBlockInterface $block, array $eventReferences, array $competencyObjectReferences, \DomElement $parentSequenceBlockNode = null, $order = 0) { $sequenceBlockNode = $dom->createElement('SequenceBlock'); $sequenceNode->appendChild($sequenceBlockNode); // append a reference to _this_ sequence block to the parent sequence block if (isset($parentSequenceBlockNode)) { $ref = "/CurriculumInventory/Sequence/SequenceBlock[@id='{$block->getId()}']"; $sequenceBlockReferenceNode = $dom->createElement('SequenceBlockReference', $ref); $parentSequenceBlockNode->appendChild($sequenceBlockReferenceNode); if ($order) { $sequenceBlockReferenceNode->setAttribute('order', $order); } } $sequenceBlockNode->setAttribute('id', $block->getId()); switch ($block->getRequired()) { case CurriculumInventorySequenceBlockInterface::OPTIONAL: $sequenceBlockNode->setAttribute('required', 'Optional'); break; case CurriculumInventorySequenceBlockInterface::REQUIRED: $sequenceBlockNode->setAttribute('required', 'Required'); break; case CurriculumInventorySequenceBlockInterface::REQUIRED_IN_TRACK: $sequenceBlockNode->setAttribute('required', 'Required In Track'); break; } switch ($block->getChildSequenceOrder()) { case CurriculumInventorySequenceBlockInterface::ORDERED: $sequenceBlockNode->setAttribute('order', 'Ordered'); break; case CurriculumInventorySequenceBlockInterface::UNORDERED: $sequenceBlockNode->setAttribute('order', 'Unordered'); break; case CurriculumInventorySequenceBlockInterface::PARALLEL: $sequenceBlockNode->setAttribute('order', 'Parallel'); break; } // // min/max are currently not supported. // //$sequenceBlockNode->setAttribute('minimum', $block->getMinimum()); //$sequenceBlockNode->setAttribute('maximum', $block->getMaximum()); if ($block->hasTrack()) { $sequenceBlockNode->setAttribute('track', 'true'); } else { $sequenceBlockNode->setAttribute('track', 'false'); } $titleNode = $dom->createElement('Title'); $sequenceBlockNode->appendChild($titleNode); $titleNode->appendChild($dom->createTextNode($block->getTitle())); if ('' !== trim($block->getDescription())) { $descriptionNode = $dom->createElement('Description'); $sequenceBlockNode->appendChild($descriptionNode); $descriptionNode->appendChild($dom->createTextNode($block->getDescription())); } // add duration and/or start+end date $timingNode = $dom->createElement('Timing'); $sequenceBlockNode->appendChild($timingNode); if ($block->getDuration()) { $durationNode = $dom->createElement('Duration'); $timingNode->appendChild($durationNode); $durationNode->appendChild($dom->createTextNode('P' . $block->getDuration() . 'D')); // duration in days. } if ($block->getStartDate()) { $datesNode = $dom->createElement('Dates'); $timingNode->appendChild($datesNode); $startDateNode = $dom->createElement('StartDate', $block->getStartDate()->format('Y-m-d')); $datesNode->appendChild($startDateNode); $endDateNode = $dom->createElement('EndDate', $block->getEndDate()->format('Y-m-d')); $datesNode->appendChild($endDateNode); } // academic level $levelNode = $dom->createElement('Level', "/CurriculumInventory/AcademicLevels/Level[@number='{$block->getAcademicLevel()->getLevel()}']"); $sequenceBlockNode->appendChild($levelNode); // clerkship type // map course clerkship type to "Clerkship Model" // @todo Refactor this out into utility method. [ST 2015/09/14] $course = $block->getCourse(); $clerkshipModel = false; if ($course) { $clerkshipType = $course->getClerkshipType() ? $course->getClerkshipType()->getId() : null; switch ($clerkshipType) { case CourseClerkshipTypeInterface::INTEGRATED: $clerkshipModel = 'integrated'; break; case CourseClerkshipTypeInterface::BLOCK: case CourseClerkshipTypeInterface::LONGITUDINAL: $clerkshipModel = 'rotation'; break; } } if ($clerkshipModel) { $clerkshipModelNode = $dom->createElement('ClerkshipModel', $clerkshipModel); $sequenceBlockNode->appendChild($clerkshipModelNode); } // link to competency objects if (array_key_exists($block->getId(), $competencyObjectReferences)) { $refs = $competencyObjectReferences[$block->getId()]; foreach ($refs['program_objectives'] as $id) { $uri = $this->createCompetencyObjectUri($id, 'program_objective'); $this->createCompetencyObjectReferenceNode($dom, $sequenceBlockNode, $uri); } foreach ($refs['course_objectives'] as $id) { $uri = $this->createCompetencyObjectUri($id, 'course_objective'); $this->createCompetencyObjectReferenceNode($dom, $sequenceBlockNode, $uri); } } // pre-conditions and post-conditions are n/a // link to events if (array_key_exists($block->getId(), $eventReferences)) { $refs = $eventReferences[$block->getId()]; foreach ($refs as $reference) { $sequenceBlockEventNode = $dom->createElement('SequenceBlockEvent'); $sequenceBlockNode->appendChild($sequenceBlockEventNode); if ($reference['required']) { $sequenceBlockEventNode->setAttribute('required', 'true'); } else { $sequenceBlockEventNode->setAttribute('required', 'false'); } $refUri = "/CurriculumInventory/Events/Event[@id='E{$reference['event_id']}']"; $eventReferenceNode = $dom->createElement('EventReference', $refUri); $sequenceBlockEventNode->appendChild($eventReferenceNode); // start/end-date // Not implemented at this point. // // Some food for thought: // This information may be retrieved from the date range values of offerings or independent learning // sessions associated with Ilios sessions. // E.g. // For a start date of this sequence block event reference, the earliest start date of any offerings // within a session may be assumed. // Likewise, the latest end date of any offerings within a session could be used for the end date of // event reference. // How accurate this will match the expected start/end date values here remains to be seen and will // require further discussion. // [ST 2013/08/08] } } // recursively generate XML for nested sequence blocks $children = $block->getChildrenAsSortedList(); if (!empty($children)) { $order = 0; $isOrdered = CurriculumInventorySequenceBlockInterface::ORDERED === $block->getChildSequenceOrder(); foreach ($children as $child) { // apply an incremental sort order for "ordered" sequence blocks if ($isOrdered) { $order++; } $this->createSequenceBlockNode($dom, $sequenceNode, $child, $eventReferences, $competencyObjectReferences, $sequenceBlockNode, $order); } } }
/** * Recursively copies nested sequence blocks for rollover. * * @param CurriculumInventorySequenceBlockInterface $block The block to copy. * @param CurriculumInventoryReportInterface $newReport The new report to roll over into. * @param CurriculumInventoryAcademicLevelInterface[] $newLevels A map of new academic levels, indexed by level. * @param CurriculumInventorySequenceBlockInterface|null $newParent The new parent block for this copy. */ protected function rolloverSequenceBlock(CurriculumInventorySequenceBlockInterface $block, CurriculumInventoryReportInterface $newReport, array $newLevels, CurriculumInventorySequenceBlockInterface $newParent = null) { /* @var CurriculumInventorySequenceBlockInterface $newBlock */ $newBlock = $this->sequenceBlockManager->create(); $newBlock->setReport($newReport); $newBlock->setAcademicLevel($newLevels[$block->getAcademicLevel()->getLevel()]); $newBlock->setDescription($block->getDescription()); $newBlock->setEndDate($block->getEndDate()); $newBlock->setStartDate($block->getStartDate()); $newBlock->setChildSequenceOrder($block->getChildSequenceOrder()); $newBlock->setDuration($block->getDuration()); $newBlock->setTitle($block->getTitle()); $newBlock->setOrderInSequence($block->getOrderInSequence()); $newBlock->setMinimum($block->getMinimum()); $newBlock->setMaximum($block->getMaximum()); $newBlock->setTrack($block->hasTrack()); $newBlock->setRequired($block->getRequired()); if ($newParent) { $newBlock->setParent($newParent); $newParent->addChild($newBlock); } $newReport->addSequenceBlock($newBlock); $this->sequenceBlockManager->update($newBlock, false, false); foreach ($block->getChildren() as $child) { $this->rolloverSequenceBlock($child, $newReport, $newLevels, $newBlock); } }