You are here

class ScannerForm in Search and Replace Scanner 8

Form for performing searching.

Hierarchy

Expanded class hierarchy of ScannerForm

1 string reference to 'ScannerForm'
scanner.routing.yml in ./scanner.routing.yml
scanner.routing.yml

File

src/Form/ScannerForm.php, line 16

Namespace

Drupal\scanner\Form
View source
class ScannerForm extends FormBase {
  use StringTranslationTrait;

  /**
   * The private temporary storage factory.
   *
   * @var \Drupal\Core\TempStore\PrivateTempStoreFactory
   */
  protected $tempStore;

  /**
   * The scanner plugin manager.
   *
   * @var Drupal\scanner\Plugin\ScannerPluginManager
   */
  protected $scannerManager;

  /**
   * {@inheritdoc}
   */
  public function __construct(PrivateTempStoreFactory $tempStore, ScannerPluginManager $scannerManager) {
    $this->tempStore = $tempStore;
    $this->scannerManager = $scannerManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('tempstore.private'), $container
      ->get('plugin.manager.scanner'));
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'scanner_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = \Drupal::config('scanner.admin_settings');
    $mode = $form_state
      ->getValue('scanner_mode') ? $form_state
      ->getValue('scanner_mode') : $config
      ->get('scanner_mode');
    $wholeword = $form_state
      ->getValue('scanner_wholeword') ? $form_state
      ->getValue('scanner_wholeword') : $config
      ->get('scanner_wholeword');
    $regex = $form_state
      ->getValue('scanner_regex') ? $form_state
      ->getValue('scanner_regex') : $config
      ->get('scanner_regex');
    $published = $form_state
      ->getValue('scanner_published') ? $form_state
      ->getValue('scanner_published') : $config
      ->get('scanner_published');
    $language = $form_state
      ->getValue('scanner_language') ? $form_state
      ->getValue('scanner_language') : $config
      ->get('scanner_language');
    $form['settings_link'] = [
      '#prefix' => '<p>',
      '#suffix' => '</p>',
    ];
    $form['search'] = [
      '#type' => 'textfield',
      '#default_value' => '',
      '#title' => $this
        ->t('Step 1: Search for'),
      '#maxlength' => 256,
    ];
    $form['submit_search'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Search'),
    ];
    $form['replace'] = [
      '#type' => 'textfield',
      '#default_value' => '',
      '#title' => $this
        ->t('Step 2: Replace with'),
      '#maxlength' => 256,
      '#access' => \Drupal::currentUser()
        ->hasPermission('perform search and replace') ? TRUE : FALSE,
    ];
    $form['submit_replace'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Replace'),
      '#access' => \Drupal::currentUser()
        ->hasPermission('perform search and replace') ? TRUE : FALSE,
    ];
    $form['options'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Search Options'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    ];
    $form['options']['surrounding'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Surrounding Text'),
      '#collapsible' => FALSE,
      '#description' => $this
        ->t('You can limit matches by providing the text that should appear immediately before or after the search text. Remember to account for spaces.  Note: Case sensitivity and regular expression options will all apply here, too. Whole word is not recommended.'),
    ];
    $form['options']['surrounding']['preceded'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Preceded by'),
      '#default_value' => '',
      '#maxlength' => 256,
    ];
    $form['options']['surrounding']['followed'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Followed by'),
      '#default_value' => '',
      '#maxlength' => 256,
    ];
    $form['options']['message'] = [
      '#type' => 'markup',
      '#markup' => $this
        ->t('The below settings override the values configured in the <a href="@url" target="_blank">admin settings page</a>.', [
        '@url' => '/admin/config/content/scanner',
      ]),
    ];
    $form['options']['mode'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Case sensitive search'),
      '#default_value' => $mode,
      '#description' => $this
        ->t('Check this if the search should only return results that exactly match the capitalization of your search terms.'),
    ];
    $form['options']['wholeword'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Match whole word'),
      '#default_value' => $wholeword,
      '#description' => $this
        ->t("Check this if you don't want the search to match any partial words. For instance, if you search for 'run', a whole word search will <em>not</em> match 'running'."),
    ];
    $form['options']['regex'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Use regular expressions in search'),
      '#default_value' => $regex,
      '#description' => $this
        ->t('Check this if you want to use regular expressions in your search terms.'),
    ];
    $form['options']['published'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Published nodes only'),
      '#default_value' => $published,
      '#description' => $this
        ->t('Check this if you only want your search and replace to affect fields in nodes that are published.'),
    ];
    $form['options']['language'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Content language'),
      '#default_value' => $language,
      '#options' => $this
        ->getLanguages(),
      '#description' => $this
        ->t('The language of the content you would like to search through.'),
    ];
    $scannerStore = $this->tempStore
      ->get('scanner');

    // Empty the results on initial load, otherwise results from previous query
    // will be displayed.
    if (empty($form_state
      ->getValues())) {
      $scannerStore
        ->set('results', '');
    }
    else {
      $renderable = $scannerStore
        ->get('results');
      $markup = \Drupal::service('renderer')
        ->render($renderable);
      $form['results'] = [
        '#type' => 'markup',
        '#markup' => $markup,
      ];
    }
    return $form;
  }

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

    // Validation logic here.
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_state
      ->cleanValues();
    $scannerStore = $this->tempStore
      ->get('scanner');
    $op = $form_state
      ->getUserInput()['op'];

    // Save the $form_state values into the user tempstore for later.
    foreach ($form_state
      ->getValues() as $key => $value) {
      $scannerStore
        ->set($key, $form_state
        ->getValue($key));
    }
    $scannerStore
      ->set('op', $op);
    if ($op == $this
      ->t('Search')) {
      $fields = \Drupal::config('scanner.admin_settings')
        ->get('fields_of_selected_content_type');

      // Build an array of batch operation jobs.
      // Batch job will need the field and the $form_state values.
      $operations = [];
      foreach ($fields as $key => $field) {
        $operations[] = [
          '\\Drupal\\scanner\\Form\\ScannerForm::batchSearch',
          [
            $field,
            $form_state
              ->getValues(),
          ],
        ];
      }
      $batch = [
        'title' => $this
          ->t('Scanner Search Batch'),
        'operations' => $operations,
        'finished' => '\\Drupal\\scanner\\Form\\ScannerForm::batchFinished',
        'progress_message' => $this
          ->t('Processed @current out of @total'),
      ];
      batch_set($batch);
      $form_state
        ->setRebuild(TRUE);
    }
    elseif ($op == $this
      ->t('Replace')) {

      // Redirect to the confirmation form.
      $form_state
        ->setRedirect('scanner.admin_confirm');
    }
  }

  /**
   * Batch operation function.
   *
   * @param string $field
   *   The name of the field.
   * @param array $values
   *   The $form_state values.
   * @param array $context
   *   An array containin data that is persisted across batch jobs.
   *
   * @see https://api.drupal.org/api/drupal/core%21includes%21form.inc/group/batch/8.5.x
   */
  public static function batchSearch($field, array $values, array &$context) {
    $pluginManager = \Drupal::service('plugin.manager.scanner');
    list($entityType, $bundle, $fieldname) = explode(':', $field);

    // Attempt to load the plugin.
    try {
      $plugin = $pluginManager
        ->createInstance('scanner_entity');
    } catch (PluginException $e) {

      // The instance could not be found so fail gracefully and let the user
      // know.
      \Drupal::logger('scanner')
        ->error($e
        ->getMessage());
      \Drupal::messenger()
        ->addError($this
        ->t('An error occured @e:', [
        '@e' => $e
          ->getMessage(),
      ]));
    }
    $results = $plugin
      ->search($field, $values);
    if (!empty($results)) {
      $context['results'][$entityType][$bundle][$fieldname] = $results;

      // Number of entities with search term.
      $context['results']['count']['entities'] += count($results);
      foreach ($results as $data) {

        // Number of matches within each field of each entity.
        $context['results']['count']['matches'] += count($data['field']);
      }
      $context['message'] = 'Searching through field...';
    }
  }

  /**
   * The batch process has finished.
   *
   * @param bool $success
   *   Indicates whether the batch process finish successfully.
   * @param array $results
   *   Contains the output from the batch operations.
   * @param array $operations
   *   A list of operations that were processed.
   */
  public static function batchFinished($success, $results, $operations) {
    if ($success && isset($results['count'])) {
      $count = $results['count'];
      $count_for_theme = NULL;
      if (isset($results['count']['matches'])) {

        // Handle regex results.
        $count_for_theme = $results['count']['matches'];
      }
      elseif (isset($results['count']['entities'])) {

        // Handle other results.
        $count_for_theme = $results['count']['entities'];
      }
      else {

        // Handle other results.
        $count_for_theme = $results['count'];
      }

      // $count expected to be a numerical value.
      unset($results['count']);
      $renderable = [
        '#theme' => 'scanner_results',
        '#data' => [
          'values' => $results,
          'count' => $count_for_theme,
        ],
      ];
      $scannerStore = \Drupal::service('tempstore.private')
        ->get('scanner');

      // Persist the results to the tempstore.
      $scannerStore
        ->set('results', $renderable);
    }
    else {
      \Drupal::messenger()
        ->addMessage(t('There were some errors.'));
    }
    if (!isset($count['matches'])) {
      $count['matches'] = 0;
      $count['entities'] = 0;
    }
    \Drupal::messenger()
      ->addMessage(t('Found @matches matches in @entities entities.', [
      '@matches' => $count['matches'],
      '@entities' => $count['entities'],
    ]));
  }

  /**
   * Helper function to fetch languaged enabled on the site.
   *
   * @return array
   *   The languages keyed by langcode, with an option "all" for all languages.
   */
  public function getLanguages() {
    $languages = \Drupal::languageManager()
      ->getLanguages();
    foreach ($languages as $language) {
      $langs[$language
        ->getId()] = $language
        ->getName();
    }
    $langs['all'] = $this
      ->t('All languages');
    return $langs;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
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::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.
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.
ScannerForm::$scannerManager protected property The scanner plugin manager.
ScannerForm::$tempStore protected property The private temporary storage factory.
ScannerForm::batchFinished public static function The batch process has finished.
ScannerForm::batchSearch public static function Batch operation function.
ScannerForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
ScannerForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
ScannerForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
ScannerForm::getLanguages public function Helper function to fetch languaged enabled on the site.
ScannerForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
ScannerForm::validateForm public function Form validation handler. Overrides FormBase::validateForm
ScannerForm::__construct public function
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.