Example #1
0
 /**
  * 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);
     }
 }
Example #2
0
 /**
  * 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);
         }
     }
 }
 /**
  * Callback function for comparing sequence blocks.
  * The applied, ranked criteria for comparison are:
  * 1. "academic level"
  *      Numeric sort, ascending.
  * 2. "start date"
  *      Numeric sort on timestamps, ascending. NULL values will be treated as unix timestamp 0.
  * 3. "title"
  *    Alphabetical sort.
  * 4. "sequence block id"
  *    A last resort. Numeric sort, ascending.
  *
  * @param CurriculumInventorySequenceBlockInterface $a
  * @param CurriculumInventorySequenceBlockInterface $b
  * @return int One of -1, 0, 1.
  */
 public static function compareSequenceBlocksWithDefaultStrategy(CurriculumInventorySequenceBlockInterface $a, CurriculumInventorySequenceBlockInterface $b)
 {
     // 1. academic level id
     if ($a->getAcademicLevel()->getLevel() > $b->getAcademicLevel()->getLevel()) {
         return 1;
     } elseif ($a->getAcademicLevel()->getLevel() < $b->getAcademicLevel()->getLevel()) {
         return -1;
     }
     // 2. start date
     $startDateA = $a->getStartDate() ? $a->getStartDate()->getTimestamp() : 0;
     $startDateB = $b->getStartDate() ? $b->getStartDate()->getTimestamp() : 0;
     if ($startDateA > $startDateB) {
         return 1;
     } elseif ($startDateA < $startDateB) {
         return -1;
     }
     // 3. title comparison
     $n = strcasecmp($a->getTitle(), $b->getTitle());
     if ($n) {
         return $n > 0 ? 1 : -1;
     }
     // 4. sequence block id comparison
     if ($a->getId() > $b->getId()) {
         return 1;
     } elseif ($a->getId() < $b->getId()) {
         return -1;
     }
     return 0;
 }