Passed
Push — master ( 4b3582...7f619e )
by Julien
06:12
created

Bootstrap::handleConsole()   A

Complexity

Conditions 5
Paths 10

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 19
ccs 0
cts 12
cp 0
rs 9.5555
cc 5
nc 10
nop 1
crap 30
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';
1 ignored issue
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 38 at column 24
Loading history...
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
    }
363
}
364