AbstractCommandFilter   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 65
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 95.65%

Importance

Changes 0
Metric Value
wmc 5
lcom 1
cbo 1
dl 0
loc 65
ccs 22
cts 23
cp 0.9565
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A filter() 0 41 4
1
<?php
2
3
/**
4
 * @file
5
 * Grafizzi\Graph\Filter\AbstractCommandFilter: a component of the Grafizzi library.
6
 *
7
 * (c) 2012 Frédéric G. MARAND <[email protected]>
8
 *
9
 * Grafizzi is free software: you can redistribute it and/or modify it under the
10
 * terms of the GNU Lesser General Public License as published by the Free
11
 * Software Foundation, either version 3 of the License, or (at your option) any
12
 * later version.
13
 *
14
 * Grafizzi is distributed in the hope that it will be useful, but WITHOUT ANY
15
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16
 * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
17
 * details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with Grafizzi, in the COPYING.LESSER.txt file.  If not, see
21
 * <http://www.gnu.org/licenses/>
22
 */
23
24
namespace Grafizzi\Graph\Filter;
25
26
/**
27
 * Filters implemented as an executable file.
28
 *
29
 * - nop -p <file>+ : check and optionally pretty-print graph files
30
 *   - p : just check, no output
31
 *   - concatenate them on stdout
32
 * - acyclic -n -v -o <outfile> <file>
33
 *   - -n : no output, just return value for acyclic or not
34
 *   - -v - pretty-print on stdout + 1 sentence on stderr saying whether the graph is acyclic
35
 *   - -o <file> : only output the acyclicity sentence on stderr
36
 * - gc -<many options> <file>+: count graph components: nodes, edges...
37
 * - gvpr : "awk" for GraphViz.
38
 * - renderers: dot, neato, twopi, circo, fdp, sfdp
39
 */
40
abstract class AbstractCommandFilter extends AbstractFilter {
41
42
  public static $commandName;
43
44
  /**
45
   * Options passed on the command line.
46
   *
47
   * @var array
48
   */
49
  public $commandOptions = [];
50
51
  /**
52
   * An array of options passed on the call line of the filter command.
53
   *
54
   * @param array $args
55
   */
56 7
  public function __construct(array $args = []) {
57 7
    $this->commandOptions = $args;
58 7
  }
59
60
  /**
61
   * {@inheritdoc}
62
   */
63 3
  public function filter($input) {
64 3
    $args = '';
65 3
    foreach ($this->commandOptions as $k => $v) {
66 1
      $args .= ' ' . escapeshellarg("${k}${v}");
67
    }
68
69 3
    $command = static::$commandName . $args;
70
71
    $descriptorSpec = [
72 3
      0 => ['pipe', 'r'],
73
      1 => ['pipe', 'w'],
74
      2 => ['pipe', 'w'],
75
    ];
76 3
    $pipes = [];
77
78
    // Option "bypass_shell" only works on Windows.
79 3
    $process = proc_open($command, $descriptorSpec, $pipes, NULL, NULL, ['bypass_shell' => true]);
80
81
    // Highly unlikely to happen outside Windows unless /bin/sh is missing.
82
    // Look for /bin/sh in this file (near line 810 in PHP 7.x):
83
    // https://github.com/php/php-src/blob/master/ext/standard/proc_open.c
84 3
    if (!is_resource($process)) {
85
      throw new \ErrorException('"$command" command could not be run (no resource).');
86
    }
87
88 3
    fwrite($pipes[0], $input);
89 3
    fclose($pipes[0]);
90
    $ret = [
91 3
      stream_get_contents($pipes[1]),
92 3
      stream_get_contents($pipes[2]),
93
    ];
94 3
    fclose($pipes[1]);
95 3
    fclose($pipes[2]);
96 3
    $status = proc_close($process);
97
    // http://tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF
98 3
    if ($status === 127) {
99 1
      throw new \ErrorException("''$command' command could not be run (exit 127)'.");
100
    }
101
102 2
    return $ret;
103
  }
104
}
105