AbstractGenerate::generateSwitch()   A
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 5
nop 2
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 4
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Jasny\SwitchRoute\Generator;
6
7
use Jasny\SwitchRoute\Endpoint;
8
use Jasny\SwitchRoute\InvalidRouteException;
9
10
/**
11
 * Base class for switch script generation.
12
 */
13
abstract class AbstractGenerate
14
{
15
    /**
16
     * Generate routing code for an endpoint.
17
     *
18
     * @param string $key
19
     * @param array  $route
20
     * @param array  $vars
21
     * @return string
22
     * @throws InvalidRouteException
23
     */
24
    abstract protected function generateRoute(string $key, array $route, array $vars): string;
25
26
    /**
27
     * Generate the PHP script with a switch for routing.
28
     *
29
     * @param array<string,Endpoint|array> $structure
30
     * @param int                          $level      Structure depth
31
     * @return string
32
     */
33 12
    protected function generateSwitch(array $structure, int $level = 0): string
34
    {
35 12
        $indent = str_repeat(' ', $level * 8);
36
37 12
        $code = [];
38 12
        $code[] = $indent . sprintf("switch (\$segments[{$level}] ?? %s) {", '"\0"');
39
40 12
        foreach ($structure as $segment => $sub) {
41 9
            $code[] = $indent . '    ' . ($segment === '*' ? 'default' : 'case "' . addslashes($segment) . '"') . ':';
42
43 9
            if ($sub instanceof Endpoint) {
44 9
                $code[] = self::indent($this->generateEndpoint($sub), ($level + 1) * 8);
45
            } else {
46 3
                $code[] = $this->generateSwitch($sub, $level + 1); // recursion
47
            }
48 7
            $code[] = $indent . "        break " . ($level + 1) . ";";
49
        }
50
51 10
        $code[] = $indent . "}";
52
53 10
        return join("\n", $code);
54
    }
55
56
    /**
57
     * Generate a statement for an endpoint.
58
     *
59
     * @param Endpoint $endpoint
60
     * @return string
61
     */
62 12
    protected function generateEndpoint(Endpoint $endpoint): string
63
    {
64 12
        $code = [];
65 12
        $code[] = "switch (\$method) {";
66
67 12
        foreach ($endpoint->getUniqueRoutes() as [$methods, $route, $vars]) {
68 9
            foreach ($methods as $method) {
69 9
                $code[] = sprintf("    case '%s':", $method);
70
            }
71
72 9
            $key = join('|', $methods) . ' ' . $endpoint->getPath();
73 9
            $routeCode = $this->generateRoute($key, $route, $endpoint->getVars($methods[0]));
74 7
            $code[] = AbstractGenerate::indent($routeCode, 8);
75
        }
76
77 10
        $code[] = "}";
78
79 10
        return join("\n", $code);
80
    }
81
82
    /**
83
     * Generate namespace code and extract class name from fqcn.
84
     *
85
     * @param string $class
86
     * @return array
87
     */
88 12
    protected function generateNs(string $class): array
89
    {
90 12
        $parts = explode('\\', $class);
91 12
        $className = array_pop($parts);
92 12
        $namespace = $parts !== [] ? "\n" . 'namespace ' . join('\\', $parts) . ";\n" : '';
93
94 12
        return [$namespace, $className];
95
    }
96
97
    /**
98
     * Indent code with spaces.
99
     * {@internal PSR-2 requires the use of 4 spaces for indentation. Other variants like tabs will not be supported.}}
100
     *
101
     * @param string $code
102
     * @param int    $spaces
103
     * @return string
104
     */
105 10
    final protected static function indent(string $code, int $spaces = 4): string
106
    {
107 10
        $indentation = str_repeat(' ', $spaces);
108
109 10
        return $indentation . str_replace("\n", "\n" . $indentation, $code);
110
    }
111
}
112