Test Failed
Push — master ( c71310...b1cf76 )
by Julien
20:09
created

Bootstrap::getRouter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * This file is part of the Zemit Framework.
5
 *
6
 * (c) Zemit Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zemit;
13
14
use Phalcon\Application\AbstractApplication;
15
use Phalcon\Di\Di;
16
use Phalcon\Di\DiInterface;
17
use Phalcon\Di\FactoryDefault;
18
use Phalcon\Events;
19
use Phalcon\Http\ResponseInterface;
20
use Zemit\Support\Helper;
21
use Zemit\Config\ConfigInterface;
22
use Zemit\Cli\Console;
23
use Zemit\Events\EventsAwareTrait;
24
use Zemit\Mvc\Application;
25
use Zemit\Provider\Config\ServiceProvider as ConfigServiceProvider;
26
use Zemit\Provider\Router\ServiceProvider as RouterServiceProvider;
27
use Zemit\Router\RouterInterface;
28
use Zemit\Support\Php;
29
use Docopt;
30
31
/**
32
 * Zemit Core's Bootstrap for the MVC Application & CLI Console mode
33
 */
34
class Bootstrap
35
{
36
    use EventsAwareTrait;
37
    
38
    public const string MODE_CLI = 'cli';
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 112
    public function __construct(string $mode = null)
89
    {
90 112
        $this->setMode($mode);
91 112
        $this->setEventsManager(new Events\Manager());
92 112
        $this->setDI();
93 112
        $this->initialize();
94 112
        $this->registerConfig();
95 112
        $this->registerServices();
96 112
        $this->bootServices();
97 112
        $this->registerModules();
98 112
        $this->registerRouter();
99
    }
100
    
101
    /**
102
     * Initialisation
103
     */
104 112
    public function initialize(): void
105
    {
106 112
    }
107
    
108
    /**
109
     * Set the default DI
110
     */
111 112
    public function setDI(?DiInterface $di = null): void
112
    {
113 112
        $di ??= $this->isCli()
114 17
            ? new FactoryDefault\Cli()
115 95
            : new FactoryDefault();
116
        
117 112
        $this->di = $di;
118 112
        $this->di->setShared('bootstrap', $this);
119 112
        Di::setDefault($this->di);
120
    }
121
    
122 112
    public function setMode(?string $mode = null): void
123
    {
124 112
        $this->mode = $mode ?? (
125 112
            Php::isCli()
126
            ? self::MODE_CLI
127
            : self::MODE_MVC
128
        );
129
    }
130
    
131 114
    public function getMode(): string
132
    {
133 114
        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 112
    public function getConfig(): ConfigInterface
156
    {
157 112
        assert($this->config instanceof ConfigInterface);
158 112
        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 112
    public function registerConfig(): void
181
    {
182 112
        if (!$this->di->has('config')) {
183 112
            $configService = new ConfigServiceProvider($this->di);
184 112
            $configService->register($this->di);
185
        }
186 112
        $this->config ??= $this->di->get('config');
187
    }
188
    
189
    /**
190
     * Register Service Providers
191
     * @throws Exception
192
     */
193 112
    public function registerServices(?array $providers = null): void
194
    {
195 112
        $providers ??= $this->getConfig()->pathToArray('providers') ?? [];
196 112
        foreach ($providers as $key => $provider) {
197 112
            if (!is_string($provider)) {
198
                throw new Exception('Service Provider `' . $key . '` class name must be a string.', 400);
199
            }
200 112
            if (!class_exists($provider)) {
201
                throw new Exception('Service Provider `' . $key . '` class  `' . $provider . '` not found.', 404);
202
            }
203 112
            if ($this->di instanceof Di) {
204 112
                $this->di->register(new $provider($this->di));
205
            }
206
        }
207
    }
208
    
209
    /**
210
     * Register Router
211
     */
212 112
    public function registerRouter(): void
213
    {
214 112
        if (!$this->di->has('router')) {
215
            $configService = new RouterServiceProvider($this->di);
216
            $configService->register($this->di);
217
        }
218 112
        $this->router ??= $this->di->get('router');
219
    }
220
    
221
    /**
222
     * Boot Service Providers
223
     */
224 112
    public function bootServices(): void
225
    {
226 112
        $this->di->get('debug');
227
    }
228
    
229
    /**
230
     * Register modules
231
     */
232 112
    public function registerModules(AbstractApplication $application = null, ?array $modules = null, ?string $defaultModule = null): void
233
    {
234 112
        $application ??= $this->isMvc()
235 95
            ? $this->di->get('application')
236 17
            : $this->di->get('console');
237 112
        assert($application instanceof AbstractApplication);
238
        
239 112
        $config = $this->getConfig();
240
        
241 112
        $modules ??= $config->pathToArray('modules') ?? [];
242 112
        $application->registerModules($modules);
243
        
244 112
        $defaultModule ??= $config->path('router.defaults.module') ?? '';
245 112
        $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 114
    public function isCli(): bool
334
    {
335 114
        return $this->getMode() === self::MODE_CLI;
336
    }
337
    
338
    /**
339
     * Return true if the bootstrap mode is set to 'mvc'
340
     */
341 112
    public function isMvc(): bool
342
    {
343 112
        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
    }
363
}
364