Completed
Push — 4-psr3 ( 959fa0...cce1de )
by Frédéric G.
03:27
created

Renderer   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 74.36%

Importance

Changes 0
Metric Value
wmc 11
lcom 0
cbo 2
dl 0
loc 107
ccs 29
cts 39
cp 0.7436
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B getFormats() 0 37 6
A __construct() 0 3 1
A __call() 0 17 4
1
<?php
2
/**
3
 * @file
4
 * Grafizzi\Graph\Renderer: a component of the Grafizzi library.
5
 *
6
 * (c) 2012 Frédéric G. MARAND <[email protected]>
7
 *
8
 * Grafizzi is free software: you can redistribute it and/or modify it under the
9
 * terms of the GNU Lesser General Public License as published by the Free
10
 * Software Foundation, either version 3 of the License, or (at your option) any
11
 * later version.
12
 *
13
 * Grafizzi is distributed in the hope that it will be useful, but WITHOUT ANY
14
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
 * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
16
 * details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with Grafizzi, in the COPYING.LESSER.txt file.  If not, see
20
 * <http://www.gnu.org/licenses/>
21
 */
22
23
namespace Grafizzi\Graph;
24
25
use Grafizzi\Graph\Filter\AbstractFilter;
26
use Pimple\Container;
27
28
/**
29
 * A Renderer builds a rendering pipeline by instantiating Filters and providing
30
 * a pipe to chain invokations of their filter() methods.
31
 *
32
 * @method dot()
33
 * @method string()
34
 * @method sink()
35
 */
36
class Renderer {
37
38
  /**
39
   * The dependency injection container.
40
   *
41
   * @var \Pimple\Container
42
   */
43
  public $dic;
44
45
  /**
46
   * The channel between filters.
47
   *
48
   * @var string
49
   */
50
  public $pipe = null;
51
52
  /**
53
   * Helper to enumerate GraphViz format filters on the current system.
54
   *
55
   * @throws \ErrorException
56
   *
57
   * @param \Pimple\container $dic
58
   *
59
   * @return string[]
60
   *   An array of format names or false if dot cannot be run.
61
   */
62 5
  public static function getFormats(Container $dic) {
63 5
    $dotCommand = 'dot -Tinvalid';
64 5
    $useExceptions = !empty($dic['use_exceptions']);
65
    $descriptorSpec = array(
66 5
        0 => array('pipe', 'r'),
67 5
        1 => array('pipe', 'w'),
68 5
        2 => array('pipe', 'w'),
69 5
    );
70
71 5
    $process = proc_open($dotCommand, $descriptorSpec, $pipes, NULL, NULL);
72 5
    if (!is_resource($process)) {
73
      if ($useExceptions) {
74
        throw new \ErrorException('GraphViz "dot" command could not be run.');
75
      }
76
      // No need to define $formats otherwise: it is always defined further down.
77
    }
78
79 5
    fclose($pipes[0]);
80 5
    fclose($pipes[1]);
81 5
    $stderr = stream_get_contents($pipes[2]);
82 5
    proc_close($process);
83
84 5
    $sts = preg_match('/(.+):( .* )*/', $stderr, $matches);
85 5
    if (!$sts || count($matches) != 3) {
86
      if ($useExceptions) {
87
        throw new \ErrorException('GraphViz did not return a usable formats list.');
88
      }
89
      else {
90
        $formats = array();
91
      }
92
    }
93
    else {
94 5
      $formats = explode(' ', trim($matches[2]));
95
    }
96
97 5
    return $formats;
98
  }
99
100
  /**
101
   * Constructor.
102
   *
103
   * @param \Pimple\Container $dic
104
   */
105 4
  public function __construct(Container $dic) {
106 4
    $this->dic = $dic;
107 4
  }
108
109
  /**
110
   * Magic method: apply filter methods by simple name.
111
   *
112
   * @see Grafizzi\Graph\Filter\AbstractFilter::create()
113
   *
114
   * @param string $name
115
   *   The simple name for a filter. Will be converted to an actual class name.
116
   * @param array $args
117
   *   An array of arguments to pass to the filter method.
118
   *
119
   * @throws \DomainException
120
   *   Throws exception if the filter name does not convert to a usable filter
121
   *   class.
122
   *
123
   * @return $this
124
   */
125 3
  public function __call($name, $args) {
126
127 3
    $filter = isset($args[0])
128 3
      ? AbstractFilter::create($name, $args[0])
129 3
      : AbstractFilter::create($name);
130
131 2
    if ($filter) {
132 2
      list($this->pipe, $err) = $filter->filter($this->pipe);
133 2
      if (!empty($err)) {
134
        $this->dic['logger']->debug($err);
135
      }
136 2
    }
137
    else {
138
      throw new \DomainException('Filter not found: ' . $name);
139
    }
140 2
    return $this;
141
  }
142
}
143