code: public function selectAdaptiveNextItem()
      {
          $lastItemId = $this->getCurrentCatItemId();
          $lastOutput = $this->getLastCatItemOutput();
          $catSession = $this->getCatSession();
  
          $preSelection = $catSession->getTestMap();
  
          try {
              if (!$this->syncingMode) {
                  $selection = $catSession->getTestMap(array_values($lastOutput));
  
                  if (!$this->saveAdaptiveResults($catSession)) {
                      \common_Logger::w('Unable to save CatService results.');
                  }
                  $isShadowItem = false;
              } else {
                  $selection = $catSession->getTestMap();
                  $isShadowItem = true;
              }
          } catch (CatEngineException $e) {
              \common_Logger::e('Error during CatEngine processing. ' . $e->getMessage());
              $selection = $catSession->getTestMap();
              $isShadowItem = true;
          }
  
          $event = new SelectAdaptiveNextItemEvent($this->getTestSession(), $lastItemId, $preSelection, $selection, $isShadowItem);
          $this->getServiceManager()->get(EventManager::SERVICE_ID)->trigger($event);
  
          $this->persistCatSession($catSession);
          if (is_array($selection) && count($selection) > 0) {
              \common_Logger::d("New CAT item selection is '" . implode(', ', $selection) . "'.");
              return $selection[0];
          } else {
              \common_Logger::d('No new CAT item selection.');
              return null;
          }
      }
docs: Select the next Adaptive Item and store the retrieved results from CAT engine
  
  Ask the CAT Engine for the Next Item to be presented to the candidate, depending on the last
  CAT Item ID and last CAT Item Output currently stored.
  
  This method returns a CAT Item ID in case of the CAT Engine returned one. Otherwise, it returns
  null meaning that there is no CAT Item to be presented.
  
  @return mixed|null
  @throws \common_Exception