You are here

class AddUpdateForm in Optimizely 8

Same name and namespace in other branches
  1. 8.0 src/AddUpdateForm.php \Drupal\optimizely\AddUpdateForm

Implements the form for the Add Projects page.

Hierarchy

Expanded class hierarchy of AddUpdateForm

1 string reference to 'AddUpdateForm'
optimizely.routing.yml in ./optimizely.routing.yml
optimizely.routing.yml

File

src/AddUpdateForm.php, line 13

Namespace

Drupal\optimizely
View source
class AddUpdateForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormID() {
    return 'optimizely-add-update';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $target_oid = NULL) {
    $addupdate_form = [];
    $addupdate_form['#theme'] = 'optimizely_add_update_form';
    $form['#attached']['library'][] = 'optimizely/optimizely.forms';
    if ($target_oid == NULL) {
      $form_action = 'Add';
      $intro_message = '';
      $addupdate_form['optimizely_oid'] = [
        '#type' => 'value',
        '#value' => NULL,
      ];

      // Enable form element defaults - blank, unselected.
      $enabled = FALSE;
      $project_code = '';
    }
    else {
      $form_action = 'Update';
      $query = \Drupal::database()
        ->select('optimizely', 'o', [
        'target' => 'slave',
      ])
        ->fields('o')
        ->condition('o.oid', $target_oid, '=');
      $record = $query
        ->execute()
        ->fetchObject();
      $addupdate_form['optimizely_oid'] = [
        '#type' => 'value',
        '#value' => $target_oid,
      ];
      $addupdate_form['optimizely_original_path'] = [
        '#type' => 'value',
        '#value' => implode("\n", unserialize($record->path)),
      ];
      $enabled = $record->enabled;
      $project_code = $record->project_code == 0 ? 'Undefined' : $record->project_code;
    }

    // If we are updating the default record,
    // make the form element inaccessible.
    $addupdate_form['optimizely_project_title'] = [
      '#type' => 'textfield',
      '#disabled' => $target_oid == 1 ? TRUE : FALSE,
      '#title' => $this
        ->t('Project Title'),
      '#default_value' => $target_oid ? $record->project_title : '',
      '#description' => $target_oid == 1 ? $this
        ->t('Default project, this field can not be changed.') : $this
        ->t('Descriptive name for the project entry.'),
      '#size' => 60,
      '#maxlength' => 256,
      '#required' => TRUE,
      '#weight' => 10,
    ];
    $account_id = AccountId::getId();
    $addupdate_form['optimizely_project_code'] = [
      '#type' => 'textfield',
      '#disabled' => $target_oid == 1 ? TRUE : FALSE,
      '#title' => $this
        ->t('Optimizely Project Code'),
      '#default_value' => $project_code,
      '#description' => $account_id == 0 ? $this
        ->t('The Optimizely account value has not been set in the
           <a href="@url">Account Info</a> settings form.
           The Optimizely account value is used as
           the project ID for this "default" project entry.', [
        '@url' => Url::fromRoute('optimizely.settings')
          ->toString(),
      ]) : $this
        ->t('The Optimizely javascript file name used in the snippet
           as provided by the Optimizely website for the project.'),
      '#size' => 30,
      '#maxlength' => 100,
      '#required' => TRUE,
      '#weight' => 20,
    ];
    $addupdate_form['optimizely_path'] = [
      '#type' => 'textarea',
      '#title' => $this
        ->t('Set Path Where Optimizely Code Snippet Appears'),
      '#default_value' => $target_oid ? implode("\n", unserialize($record->path)) : '',
      '#description' => $this
        ->t('Enter the path where you want to insert the Optimizely
         Snippet. For Example: "/clubs/*" causes the snippet to appear on all pages
         below "/clubs" in the URL but not on the actual "/clubs" page itself.'),
      '#cols' => 100,
      '#rows' => 6,
      '#resizable' => FALSE,
      '#required' => FALSE,
      '#weight' => 40,
    ];
    $addupdate_form['optimizely_enabled'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('Enable/Disable Project'),
      '#default_value' => $target_oid ? $record->enabled : 0,
      '#options' => [
        1 => 'Enable project',
        0 => 'Disable project',
      ],
      '#weight' => 25,
      '#attributes' => $enabled ? [
        'class' => [
          'enabled',
        ],
      ] : [
        'class' => [
          'disabled',
        ],
      ],
    ];
    $addupdate_form['submit'] = [
      '#type' => 'submit',
      '#value' => $form_action,
      '#weight' => 100,
    ];
    $addupdate_form['cancel'] = [
      '#markup' => Link::fromTextAndUrl(t('Cancel'), new Url('optimizely.settings'))
        ->toString(),
      '#weight' => 101,
    ];
    return $addupdate_form;
  }

  /**
   * {@inheritdoc}
   *
   * Check to make sure the project code is unique except for the default
   * entry which uses the account ID but should support an additional entry
   * to allow for custom settings.
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $proj_code = $form_state
      ->getValue('optimizely_project_code');
    $op = $form_state
      ->getValue('op');

    // Watch for "Undefined" value in Project Code, Account ID needed
    // in Settings page.
    if ($proj_code == "Undefined") {
      $form_state
        ->setErrorByName('optimizely_project_code', $this
        ->t('The Optimizely Account ID must be set in the
                   <a href="@url">Account Info</a> page.
                   The account ID is used as the default Optimizely Project Code.', [
        '@url' => Url::fromRoute('optimizely.settings')
          ->toString(),
      ]));
    }
    elseif (!ctype_digit($proj_code)) {
      $form_state
        ->setErrorByName('optimizely_project_code', $this
        ->t("The project code %code must only contain digits.", [
        '%code' => $proj_code,
      ]));
    }
    elseif ($op == 'Add') {

      // Confirm project_code is unique or the entered project code
      // is also the account ID.
      // SELECT the project title in prep for related form error message.
      $query = \Drupal::database()
        ->query('SELECT project_title FROM {optimizely}
        WHERE project_code = :project_code ORDER BY oid DESC', [
        ':project_code' => $proj_code,
      ]);

      // Fetch an indexed array of the project titles, if any.
      $results = $query
        ->fetchCol(0);
      $query_count = count($results);

      // Flag submission if existing entry is found with the same project
      // code value AND it's not a SINGLE entry to replace the "default" entry.
      if ($query_count > 0 || $proj_code != AccountId::getId() && $query_count >= 2) {

        // Get the title of the project that already had the project code.
        $found_entry_title = $results[0];

        // Flag the project code form field.
        $form_state
          ->setErrorByName('optimizely_project_code', $this
          ->t('The project code (%project_code) already has an entry
                     in the "%found_entry_title" project.', [
          '%project_code' => $proj_code,
          '%found_entry_title' => $found_entry_title,
        ]));
      }
    }

    // Skip if disabled entry.
    $enabled = $form_state
      ->getValue('optimizely_enabled');
    $paths = $form_state
      ->getValue('optimizely_path');
    $oid = $form_state
      ->getValue('optimizely_oid');
    if ($enabled) {

      // Confirm that the project paths point to valid site URLs.
      $target_paths = preg_split('/[\\r\\n]+/', $paths, -1, PREG_SPLIT_NO_EMPTY);

      // For uniformity and ease of string matching, ensure each path
      // starts with a slash / except for the site-wide wildcard * or
      // special aliases such as <front>.
      self::checkPaths($target_paths);
      $valid_path = PathChecker::validatePaths($target_paths);
      if (!is_bool($valid_path)) {
        $form_state
          ->setErrorByName('optimizely_path', t('The project path "%project_path" could not be resolved as a valid URL for the site,
             or it contains a wildcard * that cannot be handled by this module.', [
          '%project_path' => $valid_path,
        ]));
      }

      // There must be only one Optimizely javascript call on a page.
      // Check paths to ensure there are no duplicates.
      list($error_title, $error_path) = PathChecker::uniquePaths($target_paths, $oid);
      if (!is_bool($error_title)) {
        $form_state
          ->setErrorByName('optimizely_path', t('The path "%error_path" will result in a duplicate entry based on
             the other project path settings. Optimizely does not allow more
             than one project to be run on a page.', [
          '%error_path' => $error_path,
        ]));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    // Catch form submitted values and prep for processing.
    $oid = $form_state
      ->getValue('optimizely_oid');
    $project_title = $form_state
      ->getValue('optimizely_project_title');
    $project_code = $form_state
      ->getValue('optimizely_project_code');
    $path_array = preg_split('/[\\r\\n]+/', $form_state
      ->getValue('optimizely_path'), -1, PREG_SPLIT_NO_EMPTY);

    // For uniformity and ease of string matching, ensure each path starts
    // with a slash / except for the site-wide wildcard * or special aliases
    // such as <front>.
    self::checkPaths($path_array);
    $enabled = $form_state
      ->getValue('optimizely_enabled');

    // Process the submission to add or edit.
    // If no ID value is included in submission then add new entry.
    if (!isset($oid)) {
      \Drupal::database()
        ->insert('optimizely')
        ->fields([
        'project_title' => $project_title,
        'path' => serialize($path_array),
        'project_code' => $project_code,
        'enabled' => $enabled,
      ])
        ->execute();
      drupal_set_message(t('The project entry has been created.'), 'status');

      // Rebuild the provided paths to ensure Optimizely javascript
      // is now included on paths.
      if ($enabled) {
        CacheRefresher::doRefresh($path_array);
      }
    }
    else {
      \Drupal::database()
        ->update('optimizely')
        ->fields([
        'project_title' => $project_title,
        'path' => serialize($path_array),
        'project_code' => $project_code,
        'enabled' => $enabled,
      ])
        ->condition('oid', $oid)
        ->execute();
      drupal_set_message(t('The project entry has been updated.'), 'status');

      // Path originally set for project - to be compared to the updated value
      // to determine what cache paths needs to be refreshed.
      $original_path_array = preg_split('/[\\r\\n]+/', $form_state
        ->getValue('optimizely_original_path'), -1, PREG_SPLIT_NO_EMPTY);
      CacheRefresher::doRefresh($path_array, $original_path_array);
    }

    // Return to project listing page.
    $form_state
      ->setRedirect('optimizely.listing');
  }

  /**
   * Ensure that for an array of paths, each path starts with a slash.
   */
  private static function checkPaths(&$path_array) {
    foreach ($path_array as &$path) {
      $path = self::checkPathLeadingSlash($path);
    }
  }

  /**
   * Ensure that the path starts with a slash.
   *
   * @param string $path
   *   Path to be checked for having a leading slash. If leading slash
   *   is missing, prefix one. If the path already starts with a special char
   *   such as * or < leave it alone.
   *
   * @return string
   *   The path with a leading slash added, or the original path unchanged.
   */
  private static function checkPathLeadingSlash($path) {
    return ctype_alnum($path[0]) ? '/' . $path : $path;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AddUpdateForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
AddUpdateForm::checkPathLeadingSlash private static function Ensure that the path starts with a slash.
AddUpdateForm::checkPaths private static function Ensure that for an array of paths, each path starts with a slash.
AddUpdateForm::getFormID public function
AddUpdateForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
AddUpdateForm::validateForm public function Check to make sure the project code is unique except for the default entry which uses the account ID but should support an additional entry to allow for custom settings. Overrides FormBase::validateForm
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FormBase::$configFactory protected property The config factory. 1
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 1
FormBase::container private function Returns the service container.
FormBase::create public static function Instantiates a new instance of this class. Overrides ContainerInjectionInterface::create 87
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
FormInterface::getFormId public function Returns a unique string identifying the form. 236
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.