1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of Flight Routing. |
7
|
|
|
* |
8
|
|
|
* PHP version 7.1 and above required |
9
|
|
|
* |
10
|
|
|
* @author Divine Niiquaye Ibok <[email protected]> |
11
|
|
|
* @copyright 2019 Biurad Group (https://biurad.com/) |
12
|
|
|
* @license https://opensource.org/licenses/BSD-3-Clause License |
13
|
|
|
* |
14
|
|
|
* For the full copyright and license information, please view the LICENSE |
15
|
|
|
* file that was distributed with this source code. |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
namespace Flight\Routing\Traits; |
19
|
|
|
|
20
|
|
|
use Flight\Routing\Interfaces\RouteMatcherInterface; |
21
|
|
|
use Flight\Routing\Matchers\SimpleRouteMatcher; |
22
|
|
|
use Flight\Routing\Route; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @codeCoverageIgnore |
26
|
|
|
*/ |
27
|
|
|
trait DumperTrait |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* @internal |
31
|
|
|
* |
32
|
|
|
* @param mixed $value |
33
|
|
|
*/ |
34
|
|
|
protected static function export($value): string |
35
|
|
|
{ |
36
|
|
|
if (null === $value) { |
37
|
|
|
return 'null'; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
if (!\is_array($value)) { |
41
|
|
|
if ($value instanceof Route) { |
42
|
|
|
return self::exportRoute($value); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
return \str_replace("\n", '\'."\n".\'', \var_export($value, true)); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
if (!$value) { |
|
|
|
|
49
|
|
|
return '[]'; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
$i = 0; |
53
|
|
|
$export = '['; |
54
|
|
|
|
55
|
|
|
foreach ($value as $k => $v) { |
56
|
|
|
if ($i === $k) { |
57
|
|
|
++$i; |
58
|
|
|
} else { |
59
|
|
|
$export .= self::export($k) . ' => '; |
60
|
|
|
|
61
|
|
|
if (\is_int($k) && $i < $k) { |
62
|
|
|
$i = 1 + $k; |
63
|
|
|
} |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
if (\is_string($v) && 0 === \strpos($v, 'unserialize')) { |
67
|
|
|
$v = '\\' . $v . ', '; |
68
|
|
|
} elseif ($v instanceof Route) { |
69
|
|
|
$v .= self::exportRoute($v); |
70
|
|
|
} else { |
71
|
|
|
$v = self::export($v) . ', '; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
$export .= $v; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
return \substr_replace($export, ']', -2); |
|
|
|
|
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @param Route $route |
82
|
|
|
* |
83
|
|
|
* @return string |
84
|
|
|
*/ |
85
|
|
|
protected static function exportRoute(Route $route): string |
86
|
|
|
{ |
87
|
|
|
$properties = $route->getAll(); |
88
|
|
|
|
89
|
|
|
if (!\is_string($controller = $properties['controller'])) { |
90
|
|
|
$properties['controller'] = \sprintf('unserialize(\'%s\')', \serialize($controller)); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
if (isset($properties['defaults']['_compiler'])) { |
94
|
|
|
$properties['defaults']['_compiler'] = \sprintf( |
95
|
|
|
'unserialize(\'%s\')', |
96
|
|
|
\serialize($properties['defaults']['_compiler']) |
97
|
|
|
); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
$exported = self::export($properties); |
101
|
|
|
|
102
|
|
|
return \sprintf('%s::__set_state(%s)', Route::class, $exported); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Export the matcher, this method can be override if |
107
|
|
|
* RouteMatcherInterfaqce implementation changes. |
108
|
|
|
* |
109
|
|
|
* @param mixed $compiledRoutes |
110
|
|
|
* @param RouteMatcherInterface $matcher |
111
|
|
|
* |
112
|
|
|
* @return string |
113
|
|
|
*/ |
114
|
|
|
protected function exportMatcher($compiledRoutes, RouteMatcherInterface $matcher): string |
115
|
|
|
{ |
116
|
|
|
$code = ''; |
117
|
|
|
|
118
|
|
|
if ($matcher instanceof SimpleRouteMatcher) { |
119
|
|
|
[$staticRoutes, $dynamicRoutes] = $compiledRoutes; |
120
|
|
|
$code .= '[ // $staticRoutes' . "\n"; |
121
|
|
|
|
122
|
|
|
foreach ($staticRoutes as $path => $route) { |
123
|
|
|
$code .= \sprintf(' %s => ', self::export($path)); |
124
|
|
|
$code .= self::export($route); |
125
|
|
|
$code .= ", \n"; |
126
|
|
|
} |
127
|
|
|
$code .= "],\n"; |
128
|
|
|
|
129
|
|
|
$code .= '[ // $dynamicRoutes' . "\n"; |
130
|
|
|
|
131
|
|
|
foreach ($dynamicRoutes as $name => $route) { |
132
|
|
|
$code .= \sprintf(' %s => ', self::export($name)); |
133
|
|
|
$code .= self::export($route); |
134
|
|
|
$code .= ", \n"; |
135
|
|
|
} |
136
|
|
|
$code .= "],\n"; |
137
|
|
|
} else { |
138
|
|
|
$code .= self::export($compiledRoutes); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
return $code; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Warm up routes to speed up routes handling. |
146
|
|
|
* |
147
|
|
|
* @internal |
148
|
|
|
* |
149
|
|
|
* @param string $cacheFile |
150
|
|
|
* @param RouteMatcherInterface $matcher |
151
|
|
|
*/ |
152
|
|
|
private function generateCompiledRoutes(string $cacheFile, RouteMatcherInterface $matcher): void |
153
|
|
|
{ |
154
|
|
|
if (false === $compiledRoutes = $matcher->getCompiledRoutes()) { |
155
|
|
|
return; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$generatedCode = (string) \preg_replace( |
159
|
|
|
'/^./m', |
160
|
|
|
\str_repeat(' ', 1) . '$0', |
161
|
|
|
$this->exportMatcher($compiledRoutes, $matcher) |
162
|
|
|
); |
163
|
|
|
|
164
|
|
|
$dumpCode = <<<EOF |
165
|
|
|
<?php |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* This file has been auto-generated by the Flight Routing. |
169
|
|
|
*/ |
170
|
|
|
|
171
|
|
|
return [ |
172
|
|
|
{$generatedCode}]; |
173
|
|
|
|
174
|
|
|
EOF; |
175
|
|
|
|
176
|
|
|
\file_put_contents($cacheFile, $dumpCode); |
177
|
|
|
|
178
|
|
|
if ( |
179
|
|
|
\function_exists('opcache_invalidate') && |
180
|
|
|
\filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) |
181
|
|
|
) { |
182
|
|
|
@opcache_invalidate($cacheFile, true); |
|
|
|
|
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.