FbpDumper::createFbp()   F
last analyzed

Complexity

Conditions 11
Paths 281

Size

Total Lines 49
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 12.3274

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 28
cts 36
cp 0.7778
rs 3.8181
c 0
b 0
f 0
cc 11
eloc 26
nc 281
nop 1
crap 12.3274

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
declare(strict_types=1);
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) : string
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, int $inline = 3) : string
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) : string
54
    {
55 1
        return self::createFbp($definition);
56
    }
57
58
    /**
59
     * @param array $definition
60
     * @return string
61
     * @throws DumperException
62 2
     */
63
    private static function createFbp(array $definition) : string
64 2
    {
65
        $fbp = [];
66
67
        try {
68 2
69 2
            if (self::hasElement(self::PROPERTIES_LABEL, $definition)) {
70 2
                foreach($definition[self::PROPERTIES_LABEL] as $name => $element) {
71 1
                    if (!empty($element)) {
72 1
                        $fbp[] = '# ' . (string)$element;
73 2
                    }
74 2
                }
75
            }
76
77 2
            // first check for process definitions
78 2
            if (self::hasElement(self::PROCESSES_LABEL, $definition)) {
79 2
                self::$processes = $definition[self::PROCESSES_LABEL];
80
            }
81
82 2
            // handle initializer
83 1
            if (!empty($definition[self::INITIALIZERS_LABEL])) {
84 1
                foreach ($definition[self::INITIALIZERS_LABEL] as $initializer) {
85
                    if (empty($initializer[self::DATA_LABEL])) {
86
                        self::throwDumperException('no_definition', self::DATA_LABEL);
87 1
                    }
88
                    if (empty($initializer[self::TARGET_LABEL])) {
89
                        self::throwDumperException('no_definition', self::TARGET_LABEL);
90 1
                    }
91 1
                    array_push(
92 1
                        $fbp,
93 1
                        self::connectPorts(
94 1
                            $initializer[self::DATA_LABEL],
95 1
                            self::examineProcess(self::TARGET_LABEL, $initializer[self::TARGET_LABEL])
96 1
                        )
97 1
                    );
98 1
                }
99
            }
100 2
101 2
            foreach ($definition[self::CONNECTIONS_LABEL] as $connection) {
102 2
                array_push($fbp, self::examineConnectionTouple($connection));
103
            }
104 2
105
            return implode(self::FILE_LINEFEED, $fbp);
106
        } catch (\Exception $e) {
107
            throw new DumperException(
108
                "Unexpected dumper error \"{$e->getMessage()}\" in {$e->getFile()} on Line {$e->getLine()}"
109
            );
110
        }
111
    }
112
113
    /**
114
     * Look for all needed fields and build a port -> port connection.
115
     *
116
     * @param array $connectionTouple
117
     * @return string
118 1
     */
119
    private static function examineConnectionTouple(array $connectionTouple) : string
120 1
    {
121 1
        self::hasElement(self::SOURCE_LABEL, $connectionTouple);
122
        self::hasElement(self::TARGET_LABEL, $connectionTouple);
123 1
124 1
        return self::connectPorts(
125 1
            self::examineProcess(self::SOURCE_LABEL, $connectionTouple[self::SOURCE_LABEL]),
126 1
            self::examineProcess(self::TARGET_LABEL, $connectionTouple[self::TARGET_LABEL])
127
        );
128
    }
129
130
    /**
131
     * @param string $type
132
     * @param array $processPart
133
     * @throws DumperException
134
     * @return string
135 2
     */
136
    private static function examineProcess(string $type, array $processPart) : string
137 2
    {
138 2
        self::hasElement(self::PROCESS_LABEL, $processPart);
139
        self::hasElement(self::PORT_LABEL, $processPart);
140 2
141 2
        $inport = '';
142 2
        $outport = '';
143 2
        $process = $processPart[self::PROCESS_LABEL];
144
        $port = $processPart[self::PORT_LABEL];
145 2
146 2
        if (self::hasElement($process, self::$processes, false)) {
147 2
            $meta = "(" . self::$processes[$process][self::COMPONENT_LABEL] . ")";
148
        } else {
149
            self::throwDumperException('process', $process);
150
        }
151 2
152 2
        if (self::SOURCE_LABEL == $type) {
153 2
            $outport = " {$port}";
154 2
        } else {
155
            $inport = "{$port} ";
156
        }
157 2
158
        return "{$inport}{$process}{$meta}{$outport}";
159
    }
160
161
    /**
162
     * @param string $needle
163
     * @param array $haystack
164
     * @param bool $triggerException
165
     * @return bool
166 2
     */
167
    private static function hasElement(
168 2
        string $needle,
169
        array $haystack,
170
        bool $triggerException = true
171
    ) : bool {
172
        if (empty($haystack[$needle])) {
173
            if ($triggerException) {
174
                self::throwDumperException('elmeent', $needle);
175
            } else {
176 2
                return false;
177
            }
178
        }
179
180
        return true;
181
    }
182
183
    /**
184 1
     * @param string $sourcePort
185
     * @param string $targetPort
186 1
     * @return string
187 1
     */
188
    private static function connectPorts(string $sourcePort, string $targetPort) : string
189 1
    {
190
        return implode(
191 1
            " " . self::SOURCE_TARGET_SEPARATOR . " ",
192 1
            [
193
                $sourcePort,
194
                $targetPort
195
            ]
196
        );
197
    }
198
199
    /**
200
     * @param string $type
201
     * @param string $value
202
     * @throws DumperException
203
     */
204
    private static function throwDumperException(string $type, string $value)
205
    {
206
        switch ($type) {
207
            case 'element':
208
                throw new DumperException("Element has no {$value}");
209
                break;
210
            case 'process':
211
                throw new DumperException("{$value} is not defined in " . self::PROCESSES_LABEL);
212
                break;
213
            case 'no_definition':
214
                throw new DumperException("Defintion has " .
215
                    self::INITIALIZERS_LABEL . " but no {$value} node"
216
                );
217
                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...
218
        }
219
    }
220
}
221