Passed
Push — master ( 01dce1...1829db )
by Marc
02:13
created

FbpDumper   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 73.32%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 2
dl 0
loc 189
ccs 66
cts 90
cp 0.7332
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A toJson() 0 4 1
A toYaml() 0 4 1
A toFbp() 0 4 1
F createFbp() 0 49 11
A examineConnectionTouple() 0 10 1
B examineProcess() 0 24 3
A hasElement() 0 12 3
A connectPorts() 0 10 1
A throwDumperException() 0 16 4
1
<?php
2
/*
3
 * This file is part of the phpflo\phpflo-fbp package.
4
 *
5
 * (c) Marc Aschmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace PhpFlo\Fbp;
12
13
use PhpFlo\Common\FbpDefinitionsInterface;
14
use PhpFlo\Exception\DumperException;
15
use Symfony\Component\Yaml\Yaml;
16
17
/**
18
 * Class FbpDumper
19
 *
20
 * @package PhpFlo\Fbp
21
 * @author Marc Aschmann <[email protected]>
22
 */
23
final class FbpDumper implements FbpDefinitionsInterface
24
{
25
    /**
26
     * @var array
27
     */
28
    private static $processes;
29
30
    /**
31
     * @param array $definition
32
     * @return string json
33
     */
34 2
    public static function toJson(array $definition)
35
    {
36 2
        return json_encode($definition, JSON_PRETTY_PRINT);
37
    }
38
39
    /**
40
     * @param array $definition
41
     * @param int $inline level until inlining starts
42
     * @return string yaml
43
     */
44 2
    public static function toYaml(array $definition, $inline = 3)
45
    {
46 2
        return Yaml::dump($definition, $inline);
47
    }
48
49
    /**
50
     * @param array $definition
51
     * @return string
52
     */
53 1
    public static function toFbp(array $definition)
54
    {
55 1
        return self::createFbp($definition);
56
    }
57
58
    /**
59
     * @param array $definition
60
     * @return string
61
     */
62 2
    private static function createFbp(array $definition)
63
    {
64 2
        $fbp = [];
65
66
        try {
67
68 2
            if (self::hasElement(self::PROPERTIES_LABEL, $definition)) {
69 2
                foreach($definition[self::PROPERTIES_LABEL] as $name => $element) {
70 2
                    if (!empty($element)) {
71 1
                        $fbp[] = '# ' . (string)$element;
72 1
                    }
73 2
                }
74 2
            }
75
76
            // first check for process definitions
77 2
            if (self::hasElement(self::PROCESSES_LABEL, $definition)) {
78 2
                self::$processes = $definition[self::PROCESSES_LABEL];
79 2
            }
80
81
            // handle initializer
82 2
            if (!empty($definition[self::INITIALIZERS_LABEL])) {
83 1
                foreach ($definition[self::INITIALIZERS_LABEL] as $initializer) {
84 1
                    if (empty($initializer[self::DATA_LABEL])) {
85
                        self::throwDumperException('no_definition', self::DATA_LABEL);
86
                    }
87 1
                    if (empty($initializer[self::TARGET_LABEL])) {
88
                        self::throwDumperException('no_definition', self::TARGET_LABEL);
89
                    }
90 1
                    array_push(
91 1
                        $fbp,
92 1
                        self::connectPorts(
93 1
                            $initializer[self::DATA_LABEL],
94 1
                            self::examineProcess(self::TARGET_LABEL, $initializer[self::TARGET_LABEL])
95 1
                        )
96 1
                    );
97 1
                }
98 1
            }
99
100 2
            foreach ($definition[self::CONNECTIONS_LABEL] as $connection) {
101 2
                array_push($fbp, self::examineConnectionTouple($connection));
102 2
            }
103
104 2
            return implode(self::FILE_LINEFEED, $fbp);
105
        } catch (\Exception $e) {
106
            throw new DumperException(
107
                "Unexpected dumper error \"{$e->getMessage()}\" in {$e->getFile()} on Line {$e->getLine()}"
108
            );
109
        }
110
    }
111
112
    /**
113
     * Look for all needed fields and build a port -> port connection.
114
     *
115
     * @param array $connectionTouple
116
     * @return string
117
     */
118 1
    private static function examineConnectionTouple(array $connectionTouple)
119
    {
120 1
        self::hasElement(self::SOURCE_LABEL, $connectionTouple);
121 1
        self::hasElement(self::TARGET_LABEL, $connectionTouple);
122
123 1
        return self::connectPorts(
124 1
            self::examineProcess(self::SOURCE_LABEL, $connectionTouple[self::SOURCE_LABEL]),
125 1
            self::examineProcess(self::TARGET_LABEL, $connectionTouple[self::TARGET_LABEL])
126 1
        );
127
    }
128
129
    /**
130
     * @param string $type
131
     * @param array $processPart
132
     * @throws DumperException
133
     * @return string
134
     */
135 2
    private static function examineProcess($type, array $processPart)
136
    {
137 2
        self::hasElement(self::PROCESS_LABEL, $processPart);
138 2
        self::hasElement(self::PORT_LABEL, $processPart);
139
140 2
        $inport = '';
141 2
        $outport = '';
142 2
        $process = $processPart[self::PROCESS_LABEL];
143 2
        $port = $processPart[self::PORT_LABEL];
144
145 2
        if (self::hasElement($process, self::$processes, false)) {
146 2
            $meta = "(" . self::$processes[$process][self::COMPONENT_LABEL] . ")";
147 2
        } else {
148
            self::throwDumperException('process', $process);
149
        }
150
151 2
        if (self::SOURCE_LABEL == $type) {
152 2
            $outport = " {$port}";
153 2
        } else {
154 2
            $inport = "{$port} ";
155
        }
156
157 2
        return "{$inport}{$process}{$meta}{$outport}";
158
    }
159
160
    /**
161
     * @param string $needle
162
     * @param array $haystack
163
     * @param bool $triggerException
164
     * @return bool
165
     */
166 2
    private static function hasElement($needle, array $haystack, $triggerException = true)
167
    {
168 2
        if (empty($haystack[$needle])) {
169
            if ($triggerException) {
170
                self::throwDumperException('elmeent', $needle);
171
            } else {
172
                return false;
173
            }
174
        }
175
176 2
        return true;
177
    }
178
179
    /**
180
     * @param string $sourcePort
181
     * @param string $targetPort
182
     * @return string
183
     */
184 1
    private static function connectPorts($sourcePort, $targetPort)
185
    {
186 1
        return implode(
187 1
            " " . self::SOURCE_TARGET_SEPARATOR . " ",
188
            [
189 1
                $sourcePort,
190
                $targetPort
191 1
            ]
192 1
        );
193
    }
194
195
    private static function throwDumperException($type, $value)
196
    {
197
        switch ($type) {
198
            case 'element':
199
                throw new DumperException("Element has no {$value}");
200
                break;
201
            case 'process':
202
                throw new DumperException("{$value} is not defined in " . self::PROCESSES_LABEL);
203
                break;
204
            case 'no_definition':
205
                throw new DumperException("Defintion has " .
206
                    self::INITIALIZERS_LABEL . " but no {$value} node"
207
                );
208
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
209
        }
210
    }
211
}
212