Completed
Push — 7.x-1.x ( 32ffa2...019f08 )
by Frédéric G.
01:31
created

qa.module (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @file
5
 * OSInet Quality Assurance module for Drupal
6
 *
7
 * @copyright Copyright (C) 2005-2012 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
use OSInet\DrupalQA\Variable\Variable;
25
26
/**
27
 * Implements hook_init().
28
 *
29
 * - add module CSS.
30
 * - register custom autoloader.
31
 *
32
 * TODO probabaly remove the CSS from here.
33
 */
34
function qa_init() {
35
  drupal_add_css(drupal_get_path('module', 'qa') .'/qa.css');
36
}
37
38
/**
39
 * Implements hook_boot().
40
 *
41
 * Menu loaders may need objects before hook_init().
42
 */
43
function qa_boot() {
44
  spl_autoload_register('qa_autoload');
45
}
46
47
/**
48
 * Dedicated autoloader for QA.
49
 *
50
 * Only load symbols in the OSInet\DrupalQA namespace.
51
 *
52
 * @param string $name
53
 */
54
function qa_autoload($name) {
55
  // Adjust verbosity if needed.
56
  $verbose = FALSE;
57
58
  $verbose && watchdog('qa/autoload', 'Loading %name', array('%name' => $name), WATCHDOG_DEBUG);
59
  if (strpos($name, 'OSInet\DrupalQA\\') !== 0) {
60
    return;
61
  }
62
63
  $module_path = drupal_get_path('module', 'qa');
64
  $path_array = explode('\\', $name);
65
  $filename = array_pop($path_array);
66
  array_unshift($path_array, $module_path);
67
  $path = implode('/', $path_array);
68
  if (!is_dir($path) || !is_readable($path)) {
69
    $args = array('%path' => $path);
70
    drupal_set_message(t("Cannot read plugins directory %path.", $args), 'warning');
71
    watchdog('qa', "Cannot read plugins directory %path", $args, WATCHDOG_WARNING);
72
  }
73
  $path_array[] = "{$filename}.php";
74
  $path = implode('/', $path_array);
75
  $sts = include_once $path;
76
  $verbose && drupal_set_message(t('QA Autoloaded %path: @result', array(
77
    '%path' => $path,
78
    '@result' => $sts ? t('Success'): t('Failure'),
79
  )));
80
}
81
82
/**
83
 * Implements hook_menu().
84
 */
85
function qa_menu() {
86
  $items = array();
87
  $items['admin/reports/qa'] = array(
88
    'title'            => 'Quality Assurance',
89
    'page callback'    => 'drupal_get_form',
90
    'page arguments'   => array('qa_report_form'),
91
    'access arguments' => array('access site reports'),
92
  );
93
  $items['admin/reports/qa/projects'] = array(
94
    'title'           => 'Projects',
95
    'type'             => MENU_LOCAL_TASK,
96
    'page callback'    => 'qa_report_projects',
97
    'access arguments' => array('access site reports'),
98
    'file'             => 'qa_projects.inc',
99
  );
100
  $items['admin/reports/qa/variable'] = array(
101
    'title'           => 'Variables',
102
    'type'             => MENU_LOCAL_TASK,
103
    'page callback'    => 'qa_report_variables',
104
    'access arguments' => array('access site reports'),
105
    'file'             => 'qa_variables.inc',
106
  );
107
  $items['admin/reports/qa/variable/%qa_variable'] = array(
108
    'title'           => 'Variables',
109
    'type'             => MENU_CALLBACK,
110
    'page callback'    => 'qa_report_variable',
111
    'page arguments'   => array(4),
112
    'access arguments' => array('access site reports'),
113
    'file'             => 'qa_variables.inc',
114
  );
115
116
  $items['admin/reports/qa/results'] = array(
117
    'title'            => 'Quality Assurance results',
118
    'page callback'    => 'qa_report_results',
119
    'page arguments'   => array(),
120
    'access arguments' => array('access site reports'),
121
    'type'             => MENU_CALLBACK,
122
  );
123
  $items['admin/reports/qa/list'] = array(
124
    'title'            => 'QA Tests',
125
    'type'             => MENU_DEFAULT_LOCAL_TASK,
126
  );
127
  $items['admin/reports/qa/dependencies'] = array(
128
    'title'            => 'Dependencies',
129
    'type'             => MENU_LOCAL_TASK,
130
    'page callback'    => 'qa_page_dependencies',
131
    'access arguments' => array('access site reports'),
132
    'file'             => 'qa_dependencies.inc',
133
    'weight'           => 1,
134
  );
135
  return $items;
136
}
137
138
/**
139
 * Page callback for qa/dependencies
140
 *
141
 * TODO convert to native Image_GraphViz to remove dependency on graphviz_filter
142
 * XXX convert to Grafizzi to remove dependency on Image_GraphViz
143
 *
144
 * @return string
145
 */
146
function qa_page_dependencies() {
147
  $G = qa_dependencies();
148
  // passed by reference: cannot pass a function return
149
  return graphviz_filter_render($G);
150
}
151
152
/**
153
 * Batch conclusion callback.
154
 *
155
 * @param boolean $success
156
 * @param array $results
157
 * @param array $operations
158
 */
159
function qa_report_finished($success, $results, $operations) {
0 ignored issues
show
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...
160
  unset($results['#message']);
161
  if ($success) {
162
    $message = format_plural(count($results), 'One control pass ran.', '@count control passes ran.');
163
  }
164
  else {
165
    $message = t('Finished with an error.');
166
  }
167
  drupal_set_message($message);
168
  $_SESSION['qa_results'] = $results;
169
  drupal_goto('admin/reports/qa/results');
170
}
171
172
/**
173
 * Results page for QA Controls batch.
174
 *
175
 * @link http://www.php.net/manual/fr/function.unserialize.php @endlink
176
 */
177
function qa_report_results() {
178
  if (empty($_SESSION['qa_results'])) {
179
    drupal_goto('admin/reports/qa');
180
  }
181
  // Work around incomplete classes
182
  $results = unserialize(serialize($_SESSION['qa_results']));
183
184
  $header = array(
185
    t('Control'),
186
    t('Status'),
187
    t('Results'),
188
  );
189
  $data = array();
190
  foreach ($results as $pass) {
191
    $control = $pass->control;
192
    $data[] = array(
193
      $control->title,
194
      $pass->status
195
        ? theme('image', array(
196
          'path' => 'misc/watchdog-ok.png',
197
          'alt' => t('OK'),
198
          ))
199
        : theme('image', array(
200
          'path' => 'misc/watchdog-error.png',
201
          'alt' => t('Error'),
202
          )),
203
      $pass->result,
204
    );
205
  }
206
  $ret = theme('table', array(
207
    'header' => $header,
208
    'rows' => $data,
209
    'attributes' => array(
210
      'id' => 'qa-results',
211
    )));
212
  // unset($_SESSION['qa_results']);
213
  return $ret;
214
}
215
216
/**
217
 * Form builder for QA packages/controls selection form.
218
 *
219
 * @return array
220
 */
221
function qa_report_form($form, $form_state) {
0 ignored issues
show
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...
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...
222
  $form = array();
223
  $base = drupal_get_path('module', 'qa');
224
  $packages = OSInet\DrupalQA\Exportable::getClasses($base, 'OSInet\DrupalQA\BasePackage');
225
  ksort($packages);
226
  foreach ($packages as $package_name => $package) {
227
    $collapsed = TRUE;
228
    $form[$package_name] = array(
229
      '#type' => 'fieldset',
230
      '#title' => filter_xss_admin($package->title),
231
      '#description' => filter_xss_admin($package->description),
232
      '#collapsible' => TRUE,
233
    );
234
    $controls = $package->getClasses($package->dir, 'OSInet\DrupalQA\BaseControl');
235
236
    foreach ($controls as $control_name => $control) {
237
      $default_value = isset($_SESSION[$control_name])
238
        ? $_SESSION[$control_name]
239
        : NULL;
240
      if ($default_value) {
241
        $collapsed = FALSE;
242
      }
243
244
      $deps = array();
245
      $met = TRUE;
246
      foreach ($control->getDependencies() as $dep_name) {
247
        if (module_exists($dep_name)) {
248
          $deps[] = t('@module (<span class="admin-enabled">available</span>)', array('@module' => $dep_name));
249
        }
250
        else {
251
          $deps[] = t('@module (<span class="admin-disabled">unavailable</span>)', array('@module' => $dep_name));
252
          $met = FALSE;
253
        }
254
      }
255
      $form[$package_name][$control_name] = array(
256
        '#type'          => 'checkbox',
257
        '#default_value' => $met ? $default_value : 0,
258
        '#title'         => filter_xss_admin($control->title),
259
        '#description'   => filter_xss_admin($control->description),
260
        '#disabled'      => !$met,
261
      );
262
      $form[$package_name][$control_name .'-dependencies'] = array(
263
        '#value' => t('Depends on: !dependencies', array(
264
          '!dependencies' => implode(', ', $deps),
265
          )),
266
        '#prefix' => '<div class="admin-dependencies">',
267
        '#suffix' => '</div>',
268
      );
269
    }
270
    $form[$package_name]['#collapsed'] = $collapsed;
271
  }
272
273
  $form['submit'] = array(
274
    '#type'  => 'submit',
275
    '#value' => t('Run controls'),
276
  );
277
278
  return $form;
279
}
280
281
/**
282
 * Submit handler for QA packages/controls selection form
283
 *
284
 * @param array $form
285
 * @param array $form_state
286
 */
287
function qa_report_form_submit($form, &$form_state) {
0 ignored issues
show
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...
288
  $controls = array();
289
  foreach ($form_state['values'] as $item => $value) {
290
    if (class_exists($item) && is_subclass_of($item, '\OSInet\DrupalQA\BaseControl')) {
0 ignored issues
show
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
291
      if ($value) {
292
        $controls[$item] = $value;
293
      }
294
      $_SESSION[$item] = $value;
295
    }
296
    elseif ($value == 1) {
297
      $args = array(
298
        '%control' => $item,
299
      );
300
      drupal_set_message(t('Requested invalid control %control', $args), 'error');
301
      watchdog('qa', 'Requested invalid control %control', $args, WATCHDOG_ERROR);
302
    }
303
  }
304
305
  drupal_set_message(t('Prepare to run these controls: @controls', array(
306
    '@controls' => implode(', ', array_keys($controls)))), 'status');
307
  $batch = array(
308
    'operations'       => array(),
309
    'title'            => t('QA Controls running'),
310
    'init_message'     => t('QA Controls initializing'),
311
    // 'progress_message' => t('current: @current, Remaining: @remaining, Total: @total'),
312
    'error_message'    => t('Error in QA Control'),
313
    'finished'         => 'qa_report_finished',
314
    // 'file'             => '', // only if outside module file
315
  );
316
317
  foreach ($controls as $item => $value) {
318
    $batch['operations'][] = array('qa_report_run_pass', array($item));
319
  }
320
  batch_set($batch);
321
}
322
323
/**
324
 * Batch progress step.
325
 *
326
 * @return void
327
 */
328
function qa_report_run_pass($class_name, &$context) {
329
  $name_arg = array('@class' => $class_name);
330
331
  $control = new $class_name();
332
  if (!is_object($control)) {
333
    drupal_set_message(t('Cannot obtain an instance for @class', $name_arg), 'error');
334
    $context['results']['#message'] = t('Control @class failed to run.', $name_arg);
335
    $context['message'] = t('Control @class failed to run.', $name_arg);
336
    $context['results'][$class_name] = 'wow';
337
  }
338
  else {
339
    drupal_set_message(t('Running a control instance for @class', $name_arg), 'status');
340
    $pass = $control->run();
341
    if (!$pass->status) {
342
      $context['success'] = FALSE;
343
    }
344
    $context['results']['#message'][] = t('Control @class ran', $name_arg);
345
    $context['message'] = theme('item_list', $context['results']['#message']);
346
    $context['results'][$class_name] = $pass;
347
  }
348
}
349
350
function qa_variable_load($name) {
351
  $variable = new Variable($name);
352
  if (!$variable->is_set) {
353
    return FALSE;
354
  }
355
356
  return $variable;
357
}
358