Completed
Push — 7.x-1.x ( 2f9e3c...1070be )
by Frédéric G.
01:36
created

qa.module::qa_autoload_psr4()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 27
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @file
5
 * OSInet Quality Assurance module for Drupal
6
 *
7
 * @copyright Copyright (C) 2005-2018 Frederic G. MARAND for Ouest Systèmes Informatiques (OSInet)
8
 *
9
 * @since DRUPAL-4-6
10
 *
11
 * @license Licensed under the disjunction of the CeCILL, version 2 and General Public License version 2 and later
12
 *
13
 * License note: QA is distributed by OSInet to its customers under the
14
 * CeCILL 2.0 license. OSInet support services only apply to the module
15
 * when distributed by OSInet, not by any third-party further down the
16
 * distribution chain.
17
 *
18
 * If you obtained QA from drupal.org, that site received it under the
19
 * GPLv2 license and can therefore distribute it under the GPLv2, and
20
 * so can you and just anyone down the chain as long as the GPLv2 terms
21
 * are abided by, the module distributor in that case being the
22
 * drupal.org organization or the downstream distributor, not OSInet.
23
 */
24
25
use Drupal\qa\Exportable;
26
use Drupal\qa\Plugin\Qa\Control\BaseControl;
27
use Drupal\qa\Plugin\Qa\Control\BasePackage;
28
use Drupal\qa\Plugin\Qa\Control\Variable\Variable;
29
30
/**
31
 * Implements hook_init().
32
 *
33
 * - add module CSS.
34
 *
35
 * TODO probabaly remove the CSS from here.
36
 */
37
function qa_init() {
38
  drupal_add_css(drupal_get_path('module', 'qa') .'/qa.css');
39
}
40
41
/**
42
 * Implements hook_boot().
43
 *
44
 * Menu loaders may need objects before hook_init().
45
 *
46
 * - register custom autoloader.
47
 */
48
function qa_boot() {
49
  spl_autoload_register(qa_autoload_psr4::class);
50
}
51
52
/**
53
 * Legacy Dedicated autoloader for QA.
54
 *
55
 * Only load symbols in the Drupal\qa namespace.
56
 *
57
 * @param string $name
58
 *
59
 * @deprecated
60
 */
61
function qa_autoload($name) {
62
  // Adjust verbosity if needed.
63
  $verbose = FALSE;
64
65
  $verbose && watchdog('qa/autoload', 'Loading %name', array('%name' => $name), WATCHDOG_DEBUG);
66
  if (strpos($name, 'Drupal\qa\\') !== 0) {
67
    return;
68
  }
69
70
  $module_path = drupal_get_path('module', 'qa');
71
  $path_array = explode('\\', $name);
72
  $filename = array_pop($path_array);
73
  array_splice($path_array, 0, 2, [$module_path, 'src/Plugin/Qa/Control']);
74
  $path = implode('/', $path_array);
75
  if (!is_dir($path) || !is_readable($path)) {
76
    $args = array('%path' => $path);
77
    drupal_set_message(t("Cannot read plugins directory %path.", $args), 'warning');
78
    watchdog('qa', "Cannot read plugins directory %path", $args, WATCHDOG_WARNING);
79
  }
80
  $path_array[] = "{$filename}.php";
81
  $path = implode('/', $path_array);
82
  $sts = include_once $path;
83
  $verbose && drupal_set_message(t('QA Autoloaded %path: @result', array(
84
    '%path' => $path,
85
    '@result' => $sts ? t('Success'): t('Failure'),
86
  )));
87
}
88
89
function qa_autoload_psr4($class) {
90
  // project-specific namespace prefix
91
  $prefix = 'Drupal\\qa\\';
92
93
  // base directory for the namespace prefix
94
  $base_dir = drupal_get_path('module', 'qa') . '/src/';
95
96
  // does the class use the namespace prefix?
97
  $len = strlen($prefix);
98
  if (strncmp($prefix, $class, $len) !== 0) {
99
    // no, move to the next registered autoloader
100
    return;
101
  }
102
103
  // get the relative class name
104
  $relative_class = substr($class, $len);
105
106
  // replace the namespace prefix with the base directory, replace namespace
107
  // separators with directory separators in the relative class name, append
108
  // with .php
109
  $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
110
111
  // if the file exists, require it
112
  if (file_exists($file)) {
113
    require $file;
114
  }
115
}
116
117
/**
118
 * Implements hook_menu().
119
 */
120
function qa_menu() {
121
  $items = array();
122
  $items['admin/reports/qa'] = array(
123
    'title'            => 'Quality Assurance',
124
    'description'      => 'Assisted auditing tools by OSInet',
125
    'page callback'    => 'drupal_get_form',
126
    'page arguments'   => array('qa_report_form'),
127
    'access arguments' => array('access site reports'),
128
  );
129
  $items['admin/reports/qa/projects'] = array(
130
    'title'           => 'Projects',
131
    'type'             => MENU_LOCAL_TASK,
132
    'page callback'    => 'qa_report_projects',
133
    'access arguments' => array('access site reports'),
134
    'file'             => 'qa_projects.inc',
135
  );
136
  $items['admin/reports/qa/variable'] = array(
137
    'title'           => 'Variables',
138
    'type'             => MENU_LOCAL_TASK,
139
    'page callback'    => 'qa_report_variables',
140
    'access arguments' => array('access site reports'),
141
    'file'             => 'qa_variables.inc',
142
  );
143
  $items['admin/reports/qa/variable/%qa_variable'] = array(
144
    'title'           => 'Variables',
145
    'type'             => MENU_CALLBACK,
146
    'page callback'    => 'qa_report_variable',
147
    'page arguments'   => array(4),
148
    'access arguments' => array('access site reports'),
149
    'file'             => 'qa_variables.inc',
150
  );
151
152
  $items['admin/reports/qa/results'] = array(
153
    'title'            => 'Quality Assurance results',
154
    'page callback'    => 'qa_report_results',
155
    'page arguments'   => array(),
156
    'access arguments' => array('access site reports'),
157
    'type'             => MENU_CALLBACK,
158
  );
159
  $items['admin/reports/qa/list'] = array(
160
    'title'            => 'QA Tests',
161
    'type'             => MENU_DEFAULT_LOCAL_TASK,
162
  );
163
  $items['admin/reports/qa/dependencies'] = array(
164
    'title'            => 'Dependencies',
165
    'type'             => MENU_LOCAL_TASK,
166
    'page callback'    => 'qa_page_dependencies',
167
    'access arguments' => array('access site reports'),
168
    'file'             => 'qa_dependencies.inc',
169
    'weight'           => 1,
170
  );
171
  return $items;
172
}
173
174
/**
175
 * Page callback for qa/dependencies
176
 *
177
 * TODO convert to native Image_GraphViz to remove dependency on graphviz_filter
178
 * XXX convert to Grafizzi to remove dependency on Image_GraphViz
179
 *
180
 * @return string
181
 */
182
function qa_page_dependencies() {
183
  $G = qa_dependencies();
184
  // passed by reference: cannot pass a function return
185
  return graphviz_filter_render($G);
186
}
187
188
/**
189
 * Batch conclusion callback.
190
 *
191
 * @param boolean $success
192
 * @param array $results
193
 * @param array $operations
194
 */
195
function qa_report_finished($success, $results, $operations) {
0 ignored issues
show
Unused Code introduced by
The parameter $operations is not used and could be removed.

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

Loading history...
196
  unset($results['#message']);
197
  if ($success) {
198
    $message = format_plural(count($results), 'One control pass ran.', '@count control passes ran.');
199
  }
200
  else {
201
    $message = t('Finished with an error.');
202
  }
203
  drupal_set_message($message);
204
  $_SESSION['qa_results'] = $results;
205
  drupal_goto('admin/reports/qa/results');
206
}
207
208
/**
209
 * Results page for QA Controls batch.
210
 *
211
 * @link http://www.php.net/manual/fr/function.unserialize.php @endlink
212
 */
213
function qa_report_results() {
214
  if (empty($_SESSION['qa_results'])) {
215
    drupal_goto('admin/reports/qa');
216
  }
217
  // Work around incomplete classes
218
  $results = unserialize(serialize($_SESSION['qa_results']));
219
220
  $header = array(
221
    t('Control'),
222
    t('Status'),
223
    t('Results'),
224
  );
225
  $data = array();
226
  foreach ($results as $pass) {
227
    $control = $pass->control;
228
    $data[] = array(
229
      $control->title,
230
      $pass->status
231
        ? theme('image', array(
232
          'path' => 'misc/watchdog-ok.png',
233
          'alt' => t('OK'),
234
          ))
235
        : theme('image', array(
236
          'path' => 'misc/watchdog-error.png',
237
          'alt' => t('Error'),
238
          )),
239
      $pass->result,
240
    );
241
  }
242
  $ret = theme('table', array(
243
    'header' => $header,
244
    'rows' => $data,
245
    'attributes' => array(
246
      'id' => 'qa-results',
247
    )));
248
  // unset($_SESSION['qa_results']);
249
  return $ret;
250
}
251
252
/**
253
 * Form builder for QA packages/controls selection form.
254
 *
255
 * @return array
256
 */
257
function qa_report_form($form, $form_state) {
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $form_state is not used and could be removed.

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

Loading history...
258
  $form = array();
259
  $base = drupal_get_path('module', 'qa');
260
  $packages = Exportable::getClasses($base, BasePackage::class);
261
  ksort($packages);
262
  foreach ($packages as $package_name => $package) {
263
    $collapsed = TRUE;
264
    $form[$package_name] = array(
265
      '#type' => 'fieldset',
266
      '#title' => filter_xss_admin($package->title),
267
      '#description' => filter_xss_admin($package->description),
268
      '#collapsible' => TRUE,
269
    );
270
    $controls = $package->getClasses($package->dir, BaseControl::class);
271
272
    foreach ($controls as $control_name => $control) {
273
      $default_value = isset($_SESSION[$control_name])
274
        ? $_SESSION[$control_name]
275
        : NULL;
276
      if ($default_value) {
277
        $collapsed = FALSE;
278
      }
279
280
      $deps = array();
281
      $met = TRUE;
282
      foreach ($control->getDependencies() as $dep_name) {
283
        if (module_exists($dep_name)) {
284
          $deps[] = t('@module (<span class="admin-enabled">available</span>)', array('@module' => $dep_name));
285
        }
286
        else {
287
          $deps[] = t('@module (<span class="admin-disabled">unavailable</span>)', array('@module' => $dep_name));
288
          $met = FALSE;
289
        }
290
      }
291
      $form[$package_name][$control_name] = array(
292
        '#type'          => 'checkbox',
293
        '#default_value' => $met ? $default_value : 0,
294
        '#title'         => filter_xss_admin($control->title),
295
        '#description'   => filter_xss_admin($control->description),
296
        '#disabled'      => !$met,
297
      );
298
      $form[$package_name][$control_name .'-dependencies'] = array(
299
        '#value' => t('Depends on: !dependencies', array(
300
          '!dependencies' => implode(', ', $deps),
301
          )),
302
        '#prefix' => '<div class="admin-dependencies">',
303
        '#suffix' => '</div>',
304
      );
305
    }
306
    $form[$package_name]['#collapsed'] = $collapsed;
307
  }
308
309
  $form['submit'] = array(
310
    '#type'  => 'submit',
311
    '#value' => t('Run controls'),
312
  );
313
314
  return $form;
315
}
316
317
/**
318
 * Submit handler for QA packages/controls selection form
319
 *
320
 * @param array $form
321
 * @param array $form_state
322
 */
323
function qa_report_form_submit($form, &$form_state) {
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

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

Loading history...
324
  $controls = array();
325
  foreach ($form_state['values'] as $item => $value) {
326
    if (class_exists($item) && is_subclass_of($item, BaseControl::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Drupal\qa\Plugin\Qa\Control\BaseControl::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
327
      if ($value) {
328
        $controls[$item] = $value;
329
      }
330
      $_SESSION[$item] = $value;
331
    }
332
    elseif ($value == 1) {
333
      $args = array(
334
        '%control' => $item,
335
      );
336
      drupal_set_message(t('Requested invalid control %control', $args), 'error');
337
      watchdog('qa', 'Requested invalid control %control', $args, WATCHDOG_ERROR);
338
    }
339
  }
340
341
  drupal_set_message(t('Prepare to run these controls: @controls', array(
342
    '@controls' => implode(', ', array_keys($controls)))), 'status');
343
  $batch = array(
344
    'operations'       => array(),
345
    'title'            => t('QA Controls running'),
346
    'init_message'     => t('QA Controls initializing'),
347
    // 'progress_message' => t('current: @current, Remaining: @remaining, Total: @total'),
348
    'error_message'    => t('Error in QA Control'),
349
    'finished'         => 'qa_report_finished',
350
    // 'file'             => '', // only if outside module file
351
  );
352
353
  foreach ($controls as $item => $value) {
354
    $batch['operations'][] = array('qa_report_run_pass', array($item));
355
  }
356
  batch_set($batch);
357
}
358
359
/**
360
 * Batch progress step.
361
 *
362
 * @return void
363
 */
364
function qa_report_run_pass($class_name, &$context) {
365
  $name_arg = array('@class' => $class_name);
366
367
  $control = new $class_name();
368
  if (!is_object($control)) {
369
    drupal_set_message(t('Cannot obtain an instance for @class', $name_arg), 'error');
370
    $context['results']['#message'] = t('Control @class failed to run.', $name_arg);
371
    $context['message'] = t('Control @class failed to run.', $name_arg);
372
    $context['results'][$class_name] = 'wow';
373
  }
374
  else {
375
    drupal_set_message(t('Running a control instance for @class', $name_arg), 'status');
376
    $pass = $control->run();
377
    if (!$pass->status) {
378
      $context['success'] = FALSE;
379
    }
380
    $context['results']['#message'][] = t('Control @class ran', $name_arg);
381
    $context['message'] = theme('item_list', $context['results']['#message']);
382
    $context['results'][$class_name] = $pass;
383
  }
384
}
385
386
function qa_variable_load($name) {
387
  $variable = new Variable($name);
388
  if (!$variable->is_set) {
389
    return FALSE;
390
  }
391
392
  return $variable;
393
}
394