ApiVersioningHandler::clearConfigsFilePath()   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
namespace Bugloos\ApiVersioningBundle\Service;
4
5
use Symfony\Component\Routing\Route;
6
use Symfony\Component\Routing\RouterInterface;
7
8
class ApiVersioningHandler
9
{
10
    private RouterInterface $router;
11
12
    private string $routeConfigs = '';
13
14
    private string $filePath = '';
15
16
    private array $previousVersionRoutes = [];
17
18
    private string $baseVersion;
19
20
    private array $baseVersionRoutes = [];
21
22
    private array $nextVersions;
23
24
    private array $nextVersionRoutes = [];
25
26
    private array $deletedRoutes;
27
28
    private array $routesThatShouldBeWrite = [];
29
30
    public function __construct(
31
        RouterInterface $router,
32
        string $baseVersion,
33
        array $nextVersions,
34
        array $deletedRoutes
35
    ) {
36
        $this->router = $router;
37
        $this->baseVersion = $baseVersion;
38
        $this->nextVersions = $nextVersions;
39
        $this->deletedRoutes = $deletedRoutes;
40
    }
41
42
    public function generateRouteFiles()
43
    {
44
        $routes = $this->router->getRouteCollection()->all();
45
46
        foreach ($routes as $routeName => $route) {
47
            if ($this->isNotAControllerRoute($routeName)) {
48
                continue;
49
            }
50
51
            if ($this->isBaseVersionRoute($routeName)) {
52
                $this->setAsBaseVersionRoute($routeName, $route);
53
            }
54
55
            $this->setAsOtherVersionRoutes($routeName, $route);
56
        }
57
58
        $this->setPreviousVersionRoutes($this->baseVersionRoutes);
59
60
        foreach ($this->nextVersions as $version) {
61
            $currentVersionRoutes = $this->getCurrentVersionRoute($version);
62
63
            $this->routesThatShouldBeWrite = array_diff_key($this->previousVersionRoutes, $currentVersionRoutes);
64
65
            $this->removeDeletedRoutes($version);
66
67
            $this->setConfigsFilePath($version);
68
69
            foreach ($this->routesThatShouldBeWrite as $routeName => $route) {
70
                $preparedRouteConfig = $this->getPreparedRouteConfig($routeName, $version, $route);
71
72
                $this->appendToRouteConfigs($preparedRouteConfig);
73
            }
74
75
            $this->addRouteConfigsToConfigFile();
76
77
            $this->setPreviousVersionRoutes(
78
                array_merge($this->routesThatShouldBeWrite, $currentVersionRoutes)
79
            );
80
81
            $this->clearRouteConfigs();
82
83
            $this->clearConfigsFilePath();
84
85
            $this->clearRoutesThatShouldBeWrite();
86
        }
87
    }
88
89
    private function appendToRouteConfigs(string $config): void
90
    {
91
        $this->routeConfigs .= $config;
92
    }
93
94
    private function clearRouteConfigs(): void
95
    {
96
        $this->routeConfigs = '';
97
    }
98
99
    private function addRouteConfigsToConfigFile(): void
100
    {
101
        file_put_contents($this->filePath, $this->routeConfigs);
102
    }
103
104
    private function clearConfigsFilePath()
105
    {
106
        $this->filePath = '';
107
    }
108
109
    private function setConfigsFilePath(string $version): void
110
    {
111
        $this->filePath = sprintf('%s/config/routes/routes_%s.yaml', getcwd(), $version);
112
    }
113
114
    private function getPreparedRouteConfig($routeName, $version, $route): string
115
    {
116
        $routeConfig = $this->getPreparedRouteName($routeName, $version);
117
        $routeConfig .= $this->getPreparedRoutePath($version, $route);
118
        $routeConfig .= $this->getPreparedControllerName($route);
119
        $routeConfig .= $this->getPreparedRouteMethods($route);
120
121
        if (!empty($route->getRequirements())) {
122
            $routeConfig .= $this->getPreparedRouteRequirements($route);
123
        }
124
125
        return $routeConfig;
126
    }
127
128
    private function getPreparedRouteName(string $routeName, string $version): string
129
    {
130
        return sprintf("%s_%s:\n", $routeName, $version);
131
    }
132
133
    private function getPreparedRoutePath(string $version, Route $route): string
134
    {
135
        $decoratedPath = str_replace($route->getOption('version'), $version, $route->getPath());
136
        return sprintf("    path: %s\n", $decoratedPath);
137
    }
138
139
    private function getPreparedControllerName(Route $route): string
140
    {
141
        return "    controller: " . $route->getDefault('_controller') . "\n";
142
    }
143
144
    private function getPreparedRouteMethods(Route $route): string
145
    {
146
        return "    methods: " . implode('|', $route->getMethods()) . "\n";
147
    }
148
149
    private function getPreparedRouteRequirements(Route $route): string
150
    {
151
        $routeRequirements = "    requirements:\n";
152
        foreach ($route->getRequirements() as $requirementName => $requirementValue) {
153
            $routeRequirements .= "        $requirementName: " . "'$requirementValue'\n";
154
        }
155
156
        return $routeRequirements;
157
    }
158
159
    private function isNotAControllerRoute(string $routeName): bool
160
    {
161
        return substr($routeName, -5, 2) !== '_v';
162
    }
163
164
    private function isBaseVersionRoute(string $routeName): bool
165
    {
166
        return str_ends_with($routeName, $this->baseVersion);
167
    }
168
169
    private function detectVersionFromRouteName(string $routeName): string
170
    {
171
        return substr($routeName, -4, 4);
172
    }
173
174
    private function detectRouteNameWithoutVersion(string $routeName): string
175
    {
176
        return substr($routeName, 0, -5);
177
    }
178
179
    private function setPreviousVersionRoutes(array $routes)
180
    {
181
        $this->previousVersionRoutes = $routes;
182
    }
183
184
    private function setAsBaseVersionRoute(string $routeName, Route $route): void
185
    {
186
        $routeNameWithoutVersion = $this->detectRouteNameWithoutVersion($routeName);
187
188
        $route->setOption('version', $this->baseVersion);
189
190
        $this->baseVersionRoutes[$routeNameWithoutVersion] = $route;
191
192
    }
193
194
    private function setAsOtherVersionRoutes(string $routeName, Route $route): void
195
    {
196
        $version = $this->detectVersionFromRouteName($routeName);
197
198
        $routeNameWithoutVersion = $this->detectRouteNameWithoutVersion($routeName);
199
200
        $route->setOption('version', $version);
201
202
        $this->nextVersionRoutes[$version][$routeNameWithoutVersion] = $route;
203
    }
204
205
    private function getCurrentVersionRoute(string $version): array
206
    {
207
        return $this->nextVersionRoutes[$version] ?? [];
208
    }
209
210
    private function removeDeletedRoutes(string $version): void
211
    {
212
        if (isset($this->deletedRoutes[$version]) && !empty($this->deletedRoutes[$version])) {
213
            $deletableRoutesInCurrentVersion = array_combine(
214
                $this->deletedRoutes[$version],
215
                $this->deletedRoutes[$version]
216
            );
217
            $this->routesThatShouldBeWrite = array_diff_key(
218
                $this->routesThatShouldBeWrite,
219
                $deletableRoutesInCurrentVersion
220
            );
221
        }
222
    }
223
224
    private function clearRoutesThatShouldBeWrite(): void
225
    {
226
        $this->routesThatShouldBeWrite = [];
227
    }
228
}
229