Completed
Push — 7.x-1.x ( e29040...6f598e )
by Frédéric G.
02:24 queued 25s
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