Completed
Push — master ( c4d705...5571d6 )
by Filipe
03:31
created

RouteBuilder::addGeneralDefaults()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
/**
4
 * This file is part of slick/web_stack package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\WebStack\Router;
11
12
use Aura\Router\Map;
13
use Aura\Router\RouterContainer;
14
use Slick\WebStack\Exception\RoutesFileNotFoundException;
15
use Slick\WebStack\Exception\RoutesFileParserException;
16
use Slick\WebStack\Router\Builder\FactoryInterface;
17
use Symfony\Component\Yaml\Exception\ParseException;
18
use Symfony\Component\Yaml\Parser;
19
20
/**
21
 * RouteBuilder
22
 *
23
 * @package Slick\WebStack\Router
24
 */
25
class RouteBuilder implements RouteBuilderInterface
26
{
27
28
    /**
29
     * @var string
30
     */
31
    private $routesFile;
32
33
    /**
34
     * @var Parser
35
     */
36
    private $parser;
37
38
    /**
39
     * @var FactoryInterface
40
     */
41
    private $routeFactory;
42
43
    /**
44
     * @var array
45
     */
46
    private $parsedData;
47
48
    /**
49
     * @var array
50
     */
51
    private $defaults = ['tokens', 'defaults', 'host', 'accepts'];
52
53
    /**
54
     * Creates a route builder
55
     *
56
     * @param string           $routesFile
57
     * @param Parser           $parser
58
     * @param FactoryInterface $routeFactory
59
     */
60
    public function __construct(
61
        $routesFile,
62
        Parser $parser,
63
        FactoryInterface $routeFactory
64
    ) {
65
        $this->routesFile = $routesFile;
66
        $this->parser = $parser;
67
        $this->routeFactory = $routeFactory;
68
    }
69
70
    /**
71
     * Map builder handler
72
     *
73
     * @see http://auraphp.com/packages/3.x/Router/custom-maps.html#1-4-5
74
     *
75
     * @param Map $map
76
     *
77
     * @return RouteBuilder|RouteBuilderInterface
78
     */
79
    public function build(Map $map)
80
    {
81
        $this->setDefaults($map);
82
        $this->addRoutes($map);
83
        return $this;
84
    }
85
86
    /**
87
     * Registers the callback for map creations
88
     *
89
     * @param RouterContainer $container
90
     * @return self|RouteBuilderInterface
91
     */
92
    public function register(RouterContainer $container)
93
    {
94
        $container->setMapBuilder([$this, 'build']);
95
        return $this;
96
    }
97
98
    /**
99
     * Get YML parsed data array
100
     *
101
     * @return array
102
     */
103
    private function getParsedData()
104
    {
105
        if (is_array($this->parsedData)) {
106
            return $this->parsedData;
107
        }
108
109
        $this->parsedData = [
110
            'routes' => []
111
        ];
112
113
        $content = $this->getYmlFileContent();
114
        try {
115
            $parsedData = $this->parser->parse($content);
116
            $this->addGeneralDefaults($parsedData);
117
            $this->addDataRoutes($parsedData);
118
        } catch (ParseException $caught) {
119
            throw new RoutesFileParserException(
120
                $caught->getMessage(),
121
                0,
122
                $caught
123
            );
124
        }
125
        return $this->parsedData;
126
    }
127
128
    /**
129
     * Get contents form YML file
130
     *
131
     * @param string|null $fileName
132
     * @return string
133
     */
134
    private function getYmlFileContent(string $fileName = null): string
135
    {
136
        $fileName = $fileName ?: $this->routesFile;
137
        if (!is_file($fileName)) {
138
            throw new RoutesFileNotFoundException(
139
                "The routes file '{$fileName}' was not found on your system."
140
            );
141
        }
142
143
        return file_get_contents($fileName);
144
    }
145
146
    /**
147
     * Set map defaults
148
     *
149
     * @param Map $map
150
     */
151
    private function setDefaults(Map $map)
152
    {
153
        foreach ($this->getParsedData() as $name => $value) {
154
            if (in_array($name, $this->defaults)) {
155
                $map->$name($value);
156
            }
157
        }
158
    }
159
160
    /**
161
     * Add routes to the provided route map
162
     *
163
     * @param Map $map
164
     */
165
    private function addRoutes(Map $map)
166
    {
167
        $data = $this->getParsedData();
168
        $routes = (array_key_exists('routes', $data))
169
            ? $data['routes']
170
            : [];
171
        foreach ($routes as $name => $definition) {
172
            $this->routeFactory->parse($name, $definition, $map);
173
        }
174
    }
175
176
    private function addGeneralDefaults($parsedData)
177
    {
178
        foreach ($parsedData as $name => $value) {
179
            if (in_array($name, $this->defaults)) {
180
                $this->parsedData[$name] = $value;
181
            }
182
        }
183
    }
184
185
    private function addDataRoutes($parsedData, string $prefix = '', string $parent = ''): void
186
    {
187
        if (!is_array($parsedData)) {
188
            return;
189
        }
190
191
        $routes = (array_key_exists('routes', $parsedData))
192
            ? $parsedData['routes']
193
            : $parsedData;
194
195
        foreach ($routes as $name => $data) {
196
            if (is_array($data)) {
197
                $this->parsedData['routes'][ltrim("{$prefix}:{$name}", ':')] = $data;
198
                continue;
199
            }
200
201
            $this->addChildFile($name, $data, $parent);
202
        }
203
    }
204
205
    private function addChildFile(string $name, string $fileName, string $parent = '')
206
    {
207
        $basePath = dirname($this->routesFile);
208
209
        $childFile = str_replace('//', '/', "{$basePath}/{$parent}/{$fileName}.yml");
210
        $data = $this->parser->parse($this->getYmlFileContent($childFile));
211
        $this->addDataRoutes($data, $name, str_replace($basePath, '', dirname($childFile)));
212
    }
213
}
214