Total Complexity | 44 |
Total Lines | 328 |
Duplicated Lines | 0 % |
Coverage | 67.86% |
Changes | 0 |
Complex classes like Bootstrap often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Bootstrap, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | class Bootstrap |
||
35 | { |
||
36 | use EventsAwareTrait; |
||
37 | |||
38 | public const string MODE_CLI = 'cli'; |
||
1 ignored issue
–
show
|
|||
39 | public const string MODE_MVC = 'mvc'; |
||
40 | |||
41 | public const string MODE_DEFAULT = self::MODE_MVC; |
||
42 | public const string MODE_CONSOLE = self::MODE_CLI; |
||
43 | |||
44 | public string $mode; |
||
45 | |||
46 | public ?array $args; |
||
47 | |||
48 | public DiInterface $di; |
||
49 | |||
50 | public ?ConfigInterface $config = null; |
||
51 | |||
52 | public ?RouterInterface $router = null; |
||
53 | |||
54 | public ?ResponseInterface $response = null; |
||
55 | |||
56 | public string $cliDoc = <<<DOC |
||
57 | Zemit CLI |
||
58 | |||
59 | Usage: |
||
60 | zemit <module> <task> [<action>] [--help | --quiet | --verbose] [--debug] [--format=<format>] [<params>...] |
||
61 | zemit (-h | --help) |
||
62 | zemit (-v | --version) |
||
63 | zemit (-i | --info) |
||
64 | |||
65 | Options: |
||
66 | -h --help show this help message |
||
67 | -v --version print version number |
||
68 | -i --info print information |
||
69 | -q --quiet suppress output |
||
70 | -V --verbose increase verbosity |
||
71 | -d --debug enable debug mode |
||
72 | --format=<format> change output returned value format (json, xml, serialized, raw, dump) |
||
73 | |||
74 | Tasks: |
||
75 | cache Wipe the cache |
||
76 | cron Run the scheduled task |
||
77 | database Create, optimize, truncate or drop tables within the database |
||
78 | data-life-cycle Delete old data based on the data life cycle definitions |
||
79 | scaffold Generating files and folders structure |
||
80 | test Return the memory usage to see if the CLI works |
||
81 | user Manage the users and passwords |
||
82 | |||
83 | DOC; |
||
84 | |||
85 | /** |
||
86 | * @throws Exception |
||
87 | */ |
||
88 | 113 | public function __construct(string $mode = null) |
|
89 | { |
||
90 | 113 | $this->setMode($mode); |
|
91 | 113 | $this->setEventsManager(new Events\Manager()); |
|
92 | 113 | $this->setDI(); |
|
93 | 113 | $this->initialize(); |
|
94 | 113 | $this->registerConfig(); |
|
95 | 113 | $this->registerServices(); |
|
96 | 113 | $this->bootServices(); |
|
97 | 113 | $this->registerModules(); |
|
98 | 113 | $this->registerRouter(); |
|
99 | } |
||
100 | |||
101 | /** |
||
102 | * Initialisation |
||
103 | */ |
||
104 | 113 | public function initialize(): void |
|
105 | { |
||
106 | 113 | } |
|
107 | |||
108 | /** |
||
109 | * Set the default DI |
||
110 | */ |
||
111 | 113 | public function setDI(?DiInterface $di = null): void |
|
112 | { |
||
113 | 113 | $di ??= $this->isCli() |
|
114 | 17 | ? new FactoryDefault\Cli() |
|
115 | 96 | : new FactoryDefault(); |
|
116 | |||
117 | 113 | $this->di = $di; |
|
118 | 113 | $this->di->setShared('bootstrap', $this); |
|
119 | 113 | Di::setDefault($this->di); |
|
120 | } |
||
121 | |||
122 | 113 | public function setMode(?string $mode = null): void |
|
123 | { |
||
124 | 113 | $this->mode = $mode ?? ( |
|
125 | 113 | Php::isCli() |
|
126 | ? self::MODE_CLI |
||
127 | : self::MODE_MVC |
||
128 | ); |
||
129 | } |
||
130 | |||
131 | 115 | public function getMode(): string |
|
132 | { |
||
133 | 115 | return $this->mode; |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * Get the default DI |
||
138 | */ |
||
139 | 2 | public function getDI(): DiInterface |
|
140 | { |
||
141 | 2 | return $this->di; |
|
142 | } |
||
143 | |||
144 | /** |
||
145 | * Set the Config |
||
146 | */ |
||
147 | 1 | public function setConfig(ConfigInterface $config): void |
|
148 | { |
||
149 | 1 | $this->config = $config; |
|
150 | } |
||
151 | |||
152 | /** |
||
153 | * Get the Config |
||
154 | */ |
||
155 | 113 | public function getConfig(): ConfigInterface |
|
156 | { |
||
157 | 113 | assert($this->config instanceof ConfigInterface); |
|
158 | 113 | return $this->config; |
|
159 | } |
||
160 | |||
161 | /** |
||
162 | * Set the MVC or CLI Router |
||
163 | */ |
||
164 | public function setRouter(RouterInterface $router): void |
||
165 | { |
||
166 | $this->router = $router; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Get the MVC or CLI Router |
||
171 | */ |
||
172 | public function getRouter(): ?RouterInterface |
||
173 | { |
||
174 | return $this->router; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Register Config |
||
179 | */ |
||
180 | 113 | public function registerConfig(): void |
|
181 | { |
||
182 | 113 | if (!$this->di->has('config')) { |
|
183 | 113 | $configService = new ConfigServiceProvider($this->di); |
|
184 | 113 | $configService->register($this->di); |
|
185 | } |
||
186 | 113 | $this->config ??= $this->di->get('config'); |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * Register Service Providers |
||
191 | * @throws Exception |
||
192 | */ |
||
193 | 113 | public function registerServices(?array $providers = null): void |
|
194 | { |
||
195 | 113 | $providers ??= $this->getConfig()->pathToArray('providers') ?? []; |
|
196 | 113 | foreach ($providers as $key => $provider) { |
|
197 | 113 | if (!is_string($provider)) { |
|
198 | throw new Exception('Service Provider `' . $key . '` class name must be a string.', 400); |
||
199 | } |
||
200 | 113 | if (!class_exists($provider)) { |
|
201 | throw new Exception('Service Provider `' . $key . '` class `' . $provider . '` not found.', 404); |
||
202 | } |
||
203 | 113 | if ($this->di instanceof Di) { |
|
204 | 113 | $this->di->register(new $provider($this->di)); |
|
205 | } |
||
206 | } |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Register Router |
||
211 | */ |
||
212 | 113 | public function registerRouter(): void |
|
213 | { |
||
214 | 113 | if (!$this->di->has('router')) { |
|
215 | $configService = new RouterServiceProvider($this->di); |
||
216 | $configService->register($this->di); |
||
217 | } |
||
218 | 113 | $this->router ??= $this->di->get('router'); |
|
219 | } |
||
220 | |||
221 | /** |
||
222 | * Boot Service Providers |
||
223 | */ |
||
224 | 113 | public function bootServices(): void |
|
225 | { |
||
226 | 113 | $this->di->get('debug'); |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Register modules |
||
231 | */ |
||
232 | 113 | public function registerModules(AbstractApplication $application = null, ?array $modules = null, ?string $defaultModule = null): void |
|
233 | { |
||
234 | 113 | $application ??= $this->isMvc() |
|
235 | 96 | ? $this->di->get('application') |
|
236 | 17 | : $this->di->get('console'); |
|
237 | 113 | assert($application instanceof AbstractApplication); |
|
238 | |||
239 | 113 | $config = $this->getConfig(); |
|
240 | |||
241 | 113 | $modules ??= $config->pathToArray('modules') ?? []; |
|
242 | 113 | $application->registerModules($modules); |
|
243 | |||
244 | 113 | $defaultModule ??= $config->path('router.defaults.module') ?? ''; |
|
245 | 113 | $application->setDefaultModule($defaultModule); |
|
246 | } |
||
247 | |||
248 | /** |
||
249 | * Handle cli or mvc application |
||
250 | * @throws \Exception |
||
251 | */ |
||
252 | public function run(): ?string |
||
253 | { |
||
254 | $this->fire('beforeRun'); |
||
255 | |||
256 | if ($this->isMvc()) { |
||
257 | |||
258 | $application = $this->di->get('application'); |
||
259 | $content = $this->handleApplication($application); |
||
260 | } |
||
261 | elseif ($this->isCli()) { |
||
262 | |||
263 | $console = $this->di->get('console'); |
||
264 | $content = $this->handleConsole($console); |
||
265 | } |
||
266 | else { |
||
267 | throw new \Exception('Application or Console not found', 404); |
||
268 | } |
||
269 | |||
270 | $this->fire('afterRun', $content); |
||
271 | |||
272 | return $content; |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * Handle Console (For CLI only) |
||
277 | */ |
||
278 | public function handleConsole(Console $console): ?string |
||
279 | { |
||
280 | $response = null; |
||
281 | try { |
||
282 | ob_start(); |
||
283 | $console->handle($this->getArgs()); |
||
284 | $response = ob_get_clean() ?: null; |
||
285 | } |
||
286 | catch (\Zemit\Exception $e) { |
||
287 | new Cli\ExceptionHandler($e); |
||
288 | } |
||
289 | catch (\Exception $exception) { |
||
290 | new Cli\ExceptionHandler($exception); |
||
291 | } |
||
292 | catch (\Throwable $throwable) { |
||
293 | new Cli\ExceptionHandler($throwable); |
||
294 | } |
||
295 | |||
296 | return $response; |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Handle Application |
||
301 | * @throws \Exception |
||
302 | */ |
||
303 | public function handleApplication(Application $application): string |
||
304 | { |
||
305 | $this->response = $application->handle($_SERVER['REQUEST_URI'] ?? '/') ?: null; |
||
306 | return $this->response ? $this->response->getContent() : ''; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Get & format args from the $this->args property |
||
311 | */ |
||
312 | 1 | public function getArgs(): array |
|
313 | { |
||
314 | 1 | $args = []; |
|
315 | |||
316 | 1 | if ($this->isCli()) { |
|
317 | 1 | $argv = array_slice($_SERVER['argv'] ?? [], 1); |
|
318 | 1 | $response = (new Docopt())->handle($this->cliDoc, ['argv' => $argv, 'optionsFirst' => true]); |
|
319 | 1 | foreach ($response as $key => $value) { |
|
320 | 1 | if (!is_null($value) && preg_match('/(<(.*?)>|\-\-(.*))/', $key, $match)) { |
|
321 | 1 | $key = lcfirst(Helper::camelize(Helper::uncamelize(array_pop($match)))); |
|
322 | 1 | $args[$key] = $value; |
|
323 | } |
||
324 | } |
||
325 | } |
||
326 | |||
327 | 1 | return $args; |
|
328 | } |
||
329 | |||
330 | /** |
||
331 | * Return true if the bootstrap mode is set to 'cli' |
||
332 | */ |
||
333 | 115 | public function isCli(): bool |
|
334 | { |
||
335 | 115 | return $this->getMode() === self::MODE_CLI; |
|
336 | } |
||
337 | |||
338 | /** |
||
339 | * Return true if the bootstrap mode is set to 'mvc' |
||
340 | */ |
||
341 | 113 | public function isMvc(): bool |
|
342 | { |
||
343 | 113 | return $this->getMode() === self::MODE_MVC; |
|
344 | } |
||
345 | |||
346 | /** |
||
347 | * Alias for the ->isCli() method |
||
348 | * @deprecated |
||
349 | */ |
||
350 | 2 | public function isConsole(): bool |
|
351 | { |
||
352 | 2 | return $this->isCli(); |
|
353 | } |
||
354 | |||
355 | /** |
||
356 | * Alias for the ->isMvc() method |
||
357 | * @deprecated |
||
358 | */ |
||
359 | 2 | public function isDefault(): bool |
|
360 | { |
||
361 | 2 | return $this->isMvc(); |
|
362 | } |
||
364 |