Graphviz::getFormat()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/*
4
 * This file is part of the doctrineviz package
5
 *
6
 * Copyright (c) 2017 Pierre Hennequart
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * Feel free to edit as you please, and have fun.
12
 *
13
 * @author Pierre Hennequart <[email protected]>
14
 */
15
16
declare(strict_types=1);
17
18
namespace Janalis\Doctrineviz\Graphviz;
19
20
use Symfony\Component\Process\Process;
21
22
/**
23
 * Graphviz.
24
 *
25
 * This class handles actions relating to graphviz dot binary.
26
 * Most of its code was stolen from https://github.com/graphp/graphviz distributed under MIT licence whose copyright notice is:
27
 * Copyright (c) 2012+ Christian Lück (Maintainer)
28
 * Copyright (c) 2012+ Fhaculty Core Team and our awesome contributors <https://github.com/clue/graph/graphs/contributors>
29
 */
30
class Graphviz
31
{
32
    /** @var string */
33
    protected $format;
34
35
    /** @var string */
36
    protected $binary;
37
38
    /**
39
     * Graphviz constructor.
40
     *
41
     * @param string $format
42
     * @param string $binary
43
     */
44
    public function __construct(string $format = 'png', string $binary = null)
45
    {
46
        $this->format = $format;
47
        $this->binary = $binary ?: 'dot'.(0 === stripos(PHP_OS, 'WIN') ? '.exe' : '');
48
    }
49
50
    /**
51
     * Create image file.
52
     *
53
     * @param GraphInterface $graph to display
54
     *
55
     * @throws \RuntimeException on error
56
     *
57
     * @return string filename
58
     */
59
    public function createImageFile(GraphInterface $graph): string
60
    {
61
        // @codeCoverageIgnoreStart
62
        if (false === $tmp = tempnam(sys_get_temp_dir(), 'doctrineviz')) {
63
            throw new \RuntimeException('Unable to get temporary file name for graphviz script');
64
        }
65
        if (false === file_put_contents($tmp, (string) $graph, LOCK_EX)) {
66
            throw new \RuntimeException('Unable to write graphviz script to temporary file');
67
        }
68
        $path = "$tmp.{$this->format}";
69
        $this->execute(
70
            '%s -T %s %s -o %s',
71
            $this->binary,
72
            $this->format,
73
            $tmp,
74
            $path
75
        );
76
        // @codeCoverageIgnoreEnd
77
78
        return $path;
79
    }
80
81
    /**
82
     * Display.
83
     *
84
     * @param GraphInterface $graph to display
85
     */
86
    public function display(GraphInterface $graph): void
87
    {
88
        // @codeCoverageIgnoreStart
89
        switch (true) {
90
            case 0 === stripos(PHP_OS, 'WIN'):
91
                $binary = 'start';
92
93
                break;
94
            case 'DARWIN' === strtoupper(PHP_OS):
95
                $binary = 'open';
96
97
                break;
98
            default:
99
                $binary = 'xdg-open';
100
        }
101
        $path = $this->createImageFile($graph);
102
        $this->execute(
103
            '%s %s',
104
            $binary,
105
            $path
106
        );
107
        // @codeCoverageIgnoreEnd
108
    }
109
110
    /**
111
     * Create image data.
112
     *
113
     * @param GraphInterface $graph to display
114
     *
115
     * @return string
116
     */
117
    public function createImageData(GraphInterface $graph): string
118
    {
119
        if ('dot' === $this->format) {
120
            return (string) $graph;
121
        }
122
        $path = $this->createImageFile($graph);
123
        $data = file_get_contents($path);
124
        unlink($path);
125
126
        return $data;
127
    }
128
129
    /**
130
     * Create image src.
131
     *
132
     * @param GraphInterface $graph to display
133
     *
134
     * @return string
135
     */
136
    public function createImageSrc(GraphInterface $graph): string
137
    {
138
        $format = ('svg' === $this->format || 'svgz' === $this->format) ? 'svg+xml' : $this->format;
139
140
        return 'data:image/'.$format.';base64,'.base64_encode($this->createImageData($graph));
141
    }
142
143
    /**
144
     * Create image html.
145
     *
146
     * @param GraphInterface $graph to display
147
     *
148
     * @return string
149
     */
150
    public function createImageHtml(GraphInterface $graph): string
151
    {
152
        if ('svg' === $this->format || 'svgz' === $this->format) {
153
            return '<object type="image/svg+xml" data="'.$this->createImageSrc($graph).'"></object>';
154
        }
155
156
        return '<img src="'.$this->createImageSrc($graph).'" />';
157
    }
158
159
    /**
160
     * Executes a command.
161
     *
162
     * @param string $format  of the command
163
     * @param array  ...$args to escape for shell
164
     *
165
     * @return Process
166
     */
167
    protected function execute(string $format, ...$args): Process
168
    {
169
        $process = new Process(sprintf($format, ...array_map(function ($arg, $index) use ($format) {
170
            return 0 === $index && 0 === strpos('%s', $format) ? escapeshellcmd($arg) : escapeshellarg($arg);
171
        }, $args, array_keys($args))));
172
        $process->mustRun();
173
174
        return $process;
175
    }
176
177
    /**
178
     * Get format.
179
     *
180
     * @return string
181
     */
182
    public function getFormat(): string
183
    {
184
        return $this->format;
185
    }
186
187
    /**
188
     * Set format.
189
     *
190
     * @param string $format
191
     */
192
    public function setFormat(string $format): void
193
    {
194
        $this->format = $format;
195
    }
196
197
    /**
198
     * Get binary.
199
     *
200
     * @return string
201
     */
202
    public function getBinary(): string
203
    {
204
        return $this->binary;
205
    }
206
207
    /**
208
     * Set binary.
209
     *
210
     * @param string $binary
211
     */
212
    public function setBinary($binary): void
213
    {
214
        $this->binary = $binary;
215
    }
216
}
217