Passed
Pull Request — 8.x-1.x (#18)
by Frédéric G.
05:43
created

ReportForm   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 23
eloc 108
dl 0
loc 207
rs 10
c 1
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getFormId() 0 2 1
B buildForm() 0 61 7
A validateForm() 0 1 1
B submitForm() 0 37 7
A runPass() 0 24 3
A create() 0 4 1
A runFinished() 0 15 2
A __construct() 0 6 1
1
<?php
2
3
namespace Drupal\qa\Form;
4
5
use Drupal\Component\Utility\Xss;
6
use Drupal\Core\Extension\ModuleHandlerInterface;
7
use Drupal\Core\Form\FormBase;
8
use Drupal\Core\Form\FormStateInterface;
9
use Drupal\Core\StringTranslation\TranslationInterface;
10
use Drupal\Core\Url;
11
use Drupal\qa\BasePackage;
12
use Drupal\qa\Exportable;
13
use Drupal\qa\Plugin\Qa\Control\BaseControl;
14
use Symfony\Component\DependencyInjection\ContainerInterface;
15
use Symfony\Component\HttpFoundation\RedirectResponse;
16
use Symfony\Component\HttpFoundation\RequestStack;
17
18
/**
19
 * Provides a QA form.
20
 */
21
class ReportForm extends FormBase {
22
23
  /**
24
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
25
   */
26
  protected $moduleHandler;
27
28
  /**
29
   * @var \Drupal\Core\StringTranslation\TranslationInterface
30
   */
31
  protected $translation;
32
33
  public function __construct(
34
    ModuleHandlerInterface $mh,
35
    TranslationInterface $translation
36
  ) {
37
    $this->moduleHandler = $mh;
38
    $this->translation = $translation;
39
  }
40
41
  public static function create(ContainerInterface $container) {
42
    $mh = $container->get('module_handler');
43
    $translation = $container->get('string_translation');
44
    return new static($mh, $translation);
0 ignored issues
show
Bug introduced by
It seems like $translation can also be of type null; however, parameter $translation of Drupal\qa\Form\ReportForm::__construct() does only seem to accept Drupal\Core\StringTranslation\TranslationInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

44
    return new static($mh, /** @scrutinizer ignore-type */ $translation);
Loading history...
Bug introduced by
It seems like $mh can also be of type null; however, parameter $mh of Drupal\qa\Form\ReportForm::__construct() does only seem to accept Drupal\Core\Extension\ModuleHandlerInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

44
    return new static(/** @scrutinizer ignore-type */ $mh, $translation);
Loading history...
45
  }
46
47
  /**
48
   * {@inheritdoc}
49
   */
50
  public function getFormId() {
51
    return 'qa_report';
52
  }
53
54
  /**
55
   * {@inheritdoc}
56
   */
57
  public function buildForm(array $form, FormStateInterface $form_state) {
58
    $packages = Exportable::getClasses(__DIR__ . "/../..", BasePackage::class);
59
    ksort($packages);
60
61
    $session = $this->getRequest()->getSession();
62
    foreach ($packages as $package_name => $package) {
63
      $open = FALSE;
64
      $form[$package_name] = array(
65
        '#type' => 'details',
66
        '#title' => Xss::filterAdmin($package->title),
67
        '#description' => Xss::filterAdmin($package->description),
68
        '#collapsible' => TRUE,
69
      );
70
      $controls = $package->getClasses($package->dir, BaseControl::class);
71
      foreach ($controls as $control_name => $control) {
72
        $default_value = $session->get($control_name);
73
        if ($default_value) {
74
          $open = TRUE;
75
        }
76
        $deps = array();
77
        $met = TRUE;
78
        foreach ($control->getDependencies() as $dep_name) {
79
          if ($this->moduleHandler->moduleExists($dep_name)) {
80
            $deps[] = $this->t('@module (<span class="admin-enabled">available</span>)', [
81
              '@module' => $dep_name,
82
            ]);
83
          }
84
          else {
85
            $deps[] = $this->t('@module (<span class="admin-disabled">unavailable</span>)', [
86
              '@module' => $dep_name,
87
            ]);
88
            $met = FALSE;
89
          }
90
        }
91
        $form[$package_name][$control_name] = [
92
          '#type'          => 'checkbox',
93
          '#default_value' => $met ? $default_value : 0,
94
          '#title'         => Xss::filterAdmin($control->title),
95
          '#description'   => Xss::filterAdmin($control->description),
96
          '#disabled'      => !$met,
97
        ];
98
        $form[$package_name][$control_name .'-dependencies'] = [
99
          '#value' => $this->t('Depends on: !dependencies', [
100
            '!dependencies' => implode(', ', $deps),
101
          ]),
102
          '#prefix' => '<div class="admin-dependencies">',
103
          '#suffix' => '</div>',
104
        ];
105
      }
106
      $form[$package_name]['#open'] = $open;
107
    }
108
109
    $form['actions'] = [
110
      '#type' => 'actions',
111
    ];
112
    $form['actions']['submit'] = [
113
      '#type' => 'submit',
114
      '#value' => $this->t('Run checked controls'),
115
    ];
116
117
    return $form;
118
  }
119
120
  /**
121
   * {@inheritdoc}
122
   */
123
  public function validateForm(array &$form, FormStateInterface $form_state) {
124
//    if (mb_strlen($form_state->getValue('message')) < 10) {
125
//      $form_state->setErrorByName('name', $this->t('Message should be at least 10 characters.'));
126
//    }
127
  }
128
129
130
  /**
131
   * {@inheritdoc}
132
   */
133
  public function submitForm(array &$form, FormStateInterface $formState) {
134
    $controls = array();
135
    $session = $this->getRequest()->getSession();
136
    foreach ($formState->getValues() as $item => $value) {
137
      if (class_exists($item) && is_subclass_of($item, BaseControl::class)) {
138
        if ($value) {
139
          $controls[$item] = $value;
140
        }
141
        $session->set($item, $value);
142
      }
143
      elseif ($value === 1) {
144
        $args = ['%control' => $item];
145
        $this->messenger()
146
          ->addError($this->t('Requested invalid control %control', $args));
147
        $this->logger('qa')
148
          ->error('Requested invalid control %control', $args);
149
      }
150
    }
151
152
    $this->messenger()
153
      ->addStatus($this->t('Prepare to run these controls: @controls', [
154
        '@controls' => implode(', ', array_keys($controls)),
155
      ]));
156
    $batch = [
157
      'operations'       => [],
158
      'title'            => $this->t('QA Controls running'),
159
      'init_message'     => $this->t('QA Controls initializing'),
160
      'progress_message' => $this->t('current: @current, Remaining: @remaining, Total: @total'),
161
      'error_message'    => $this->t('Error in QA Control'),
162
      'finished'         => [ReportForm::class, 'runFinished'],
163
      // 'file'             => '', // only if outside module file
164
    ];
165
166
    foreach ($controls as $item => $value) {
167
      $batch['operations'][] = [[$this, 'runPass'], [$item]];
168
    }
169
    batch_set($batch);
170
  }
171
172
  /**
173
   * Batch conclusion callback.
174
   *
175
   * @param bool $success
176
   * @param array $results
177
   * @param array $operations
178
   *
179
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
180
   */
181
  public static function runFinished(bool $success, array $results, array $operations) {
0 ignored issues
show
Unused Code introduced by
The parameter $operations is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

181
  public static function runFinished(bool $success, array $results, /** @scrutinizer ignore-unused */ array $operations) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
182
    unset($results['#message']);
183
    if ($success) {
184
      $message = \Drupal::translation()->formatPlural(count($results),
185
        'One control pass ran.',
186
        '@count control passes ran.'
187
      );
188
    }
189
    else {
190
      $message = t('Finished with an error.');
191
    }
192
    \Drupal::messenger()->addMessage($message);
193
    $_SESSION['qa_results'] = $results;
194
    return new RedirectResponse(
195
      Url::fromRoute('qa.reports.results', [], ['absolute' => TRUE])->toString()
0 ignored issues
show
Bug introduced by
It seems like Drupal\Core\Url::fromRou...' => TRUE))->toString() can also be of type Drupal\Core\GeneratedUrl; however, parameter $url of Symfony\Component\HttpFo...Response::__construct() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
      /** @scrutinizer ignore-type */ Url::fromRoute('qa.reports.results', [], ['absolute' => TRUE])->toString()
Loading history...
196
    );
197
  }
198
199
  /**
200
   * Batch progress step.
201
   *
202
   * @return void
203
   */
204
  public function runPass(string $className, array &$context) {
205
    $nameArg = array('@class' => $className);
206
207
    $control = new $className();
208
    if (!is_object($control)) {
209
      $this->messenger()
210
        ->addError($this->t('Cannot obtain an instance for @class', $nameArg));
211
      $context['results']['#message'] = $this->t('Control @class failed to run.', $nameArg);
212
      $context['message'] = $this->t('Control @class failed to run.', $nameArg);
213
      $context['results'][$className] = 'wow';
214
    }
215
    else {
216
      $this->messenger()
217
        ->addStatus($this->t('Running a control instance for @class', $nameArg));
218
      $pass = $control->run();
219
      if (!$pass->status) {
220
        $context['success'] = FALSE;
221
      }
222
      $context['results']['#message'][] = $this->t('Control @class ran', $nameArg);
223
      $context['message'] = [
224
        '#theme' => 'item_list',
225
        '#items' => $context['results']['#message'],
226
      ];
227
      $context['results'][$className] = $pass;
228
    }
229
  }
230
231
}
232