modules/custom/d_update/src/UpdateChecklist.php
public function saveProgress(array $values) {
    $user = \Drupal::currentUser();

    $time = time();
    $num_changed_items = 0;
    $progress = [
      '#changed' => $time,
      '#changed_by' => $user->id(),
      '#completed_items' => 0,
      '#items' => [],
    ];
    $status = [
      'positive' => [],
      'negative' => [],
    ];

    $drooplerUpdateConfig = $this->configFactory->getEditable('checklistapi.progress.d_update');
    $savedProgress = $drooplerUpdateConfig->get(ChecklistapiChecklist::PROGRESS_CONFIG_KEY);

    foreach ($values as $group_key => $group) {
      foreach ($group as $item_key => $item) {
        $old_item = (!empty($savedProgress['#items'][$item_key])) ? $savedProgress['#items'][$item_key] : 0;
        if ($item) {
          // Item is checked.
          $status['positive'][] = $item_key;
          $progress['#completed_items']++;
          if ($old_item) {
            // Item was previously checked. Use saved value.
            $new_item = $old_item;
          }
          else {
            // Item is newly checked. Set new value.
            $new_item = [
              '#completed' => $time,
              '#uid' => $user->id(),
            ];
            $num_changed_items++;
          }
          $progress['#items'][$item_key] = $new_item;
        }
        else {
          // Item is unchecked.
          $status['negative'][] = $item_key;
          if ($old_item) {
            // Item was previously checked.
            $num_changed_items++;
          }
        }
      }
    }

    $this->setSuccessfulByHook($status['positive'], TRUE);
    $this->setSuccessfulByHook($status['negative'], FALSE);

    ksort($progress);

    $drooplerUpdateConfig->set(ChecklistapiChecklist::PROGRESS_CONFIG_KEY, $progress)->save();
    drupal_set_message(\Drupal::translation()->formatPlural(
      $num_changed_items,
      '%title progress has been saved. 1 item changed.',
      '%title progress has been saved. @count items changed.',
      ['%title' => $this->updateChecklist->title]
    ));
  }
public function saveProgress(array $values) {
    $user = \Drupal::currentUser();

    $time = time();
    $num_changed_items = 0;
    $progress = [
      '#changed' => $time,
      '#changed_by' => $user->id(),
      '#completed_items' => 0,
      '#items' => [],
    ];
    $status = [
      'positive' => [],
      'negative' => [],
    ];

    $drooplerUpdateConfig = $this->configFactory->getEditable('checklistapi.progress.d_update');
    $savedProgress = $drooplerUpdateConfig->get(ChecklistapiChecklist::PROGRESS_CONFIG_KEY);

    foreach ($values as $group_key => $group) {
      foreach ($group as $item_key => $item) {
        $old_item = (!empty($savedProgress['#items'][$item_key])) ? $savedProgress['#items'][$item_key] : 0;
        if ($item) {
          // Item is checked.
          $status['positive'][] = $item_key;
          $progress['#completed_items']++;
          if ($old_item) {
            // Item was previously checked. Use saved value.
            $new_item = $old_item;
          }
          else {
            // Item is newly checked. Set new value.
            $new_item = [
              '#completed' => $time,
              '#uid' => $user->id(),
            ];
            $num_changed_items++;
          }
          $progress['#items'][$item_key] = $new_item;
        }
        else {
          // Item is unchecked.
          $status['negative'][] = $item_key;
          if ($old_item) {
            // Item was previously checked.
            $num_changed_items++;
          }
        }
      }
    }

    $this->setSuccessfulByHook($status['positive'], TRUE);
    $this->setSuccessfulByHook($status['negative'], FALSE);

    ksort($progress);

    $drooplerUpdateConfig->set(ChecklistapiChecklist::PROGRESS_CONFIG_KEY, $progress)->save();
    drupal_set_message(\Drupal::translation()->formatPlural(
      $num_changed_items,
      '%title progress has been saved. 1 item changed.',
      '%title progress has been saved. @count items changed.',
      ['%title' => $this->updateChecklist->title]
    ));
  }
Updates and saves progress of the update checklist.

@param array $values
Two dimensional array with structure "version_key" => ["checkbox_id" => TRUE|FALSE]

@throws \Drupal\Core\Entity\EntityStorageException