Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
App
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
8 / 8
16
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 init
n/a
0 / 0
n/a
0 / 0
0
 process
n/a
0 / 0
n/a
0 / 0
0
 fullInit
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 fullProcess
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 addMiddleware
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 runMiddlewares
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 finish
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 loadConfigs
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 handleException
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace Dynart\Micro;
4
5use Exception;
6
7/**
8 * Micro PHP Application
9 */
10abstract class App {
11
12    const CONFIG_BASE_URL = 'app.base_url';
13    const CONFIG_ROOT_PATH = 'app.root_path';
14    const CONFIG_ENVIRONMENT = 'app.environment';
15    const PRODUCTION_ENVIRONMENT = 'prod';
16    const EVENT_INIT_FINISHED = 'app.init_finished';
17
18    /** Stores the middleware class names in a list */
19    protected array $middlewares = [];
20    protected ?ConfigInterface $config = null;
21    protected ?LoggerInterface $logger = null;
22    /** @var string[] */
23    protected array $configPaths;
24    protected bool $exitOnFinish = true;
25
26    public function __construct(array $configPaths) {
27        $this->configPaths = $configPaths;
28        Micro::add(ConfigInterface::class, Config::class);
29        Micro::add(LoggerInterface::class, Logger::class);
30        Micro::add(EventServiceInterface::class, EventService::class);
31    }
32
33    /**
34     * Abstract function for initialize the application
35     */
36    abstract public function init(): void;
37
38    /**
39     * Abstract function for processing the application
40     */
41    abstract public function process(): void;
42
43    /**
44     * Fully initializes the application
45     *
46     * Creates the `Config`, loads the configs, creates the `Logger`, calls the `init()` method
47     * then runs all the middlewares. If an exception happens, handles it with the `handleException()` method.
48     */
49    public function fullInit(): void {
50        try {
51            $this->config = Micro::get(ConfigInterface::class);
52            $this->loadConfigs();
53            $this->logger = Micro::get(LoggerInterface::class);
54            $this->init();
55            $this->runMiddlewares();
56            Micro::get(EventServiceInterface::class)->emit(self::EVENT_INIT_FINISHED);
57        } catch (Exception $e) {
58            $this->handleException($e);
59        }
60    }
61
62    /**
63     * Calls the `process()` method within a try/catch, handles exception with the `handleException()` method
64     */
65    public function fullProcess(): void {
66        try {
67            $this->process();
68        } catch (Exception $e) {
69            $this->handleException($e);
70        }
71    }
72
73    /**
74     * Adds a middleware
75     *
76     * It adds only if not presents.
77     */
78    public function addMiddleware(string $interface): void {
79        if (!in_array($interface, $this->middlewares)) {
80            Micro::add($interface);
81            $this->middlewares[] = $interface;
82        }
83    }
84
85    /**
86     * Runs all the added middlewares
87     */
88    protected function runMiddlewares(): void {
89        foreach ($this->middlewares as $m) {
90            Micro::get($m)->run();
91        }
92    }
93
94    /**
95     * Finishes the application
96     *
97     * If the `$exitOnFinish` true (default) calls the exit, otherwise just prints out the content.
98     *
99     * @param string|int $content Content for the output. If it's an int, it is the return code of the process.
100     */
101    public function finish(string|int $content = 0): void {
102        $this->exitOnFinish ? exit($content) : print($content);
103    }
104
105    /**
106     * Loads all the configs by the `$configPaths`
107     */
108    protected function loadConfigs(): void {
109        foreach ($this->configPaths as $path) {
110            $this->config->load($path);
111        }
112    }
113
114    /**
115     * Handles the exception
116     *
117     * Sends the type, the line, the exception message and the stacktrace to the standard error output.
118     * If the `Config` or the `Logger` wasn't initialised throws a `MicroException`.
119     *
120     * @throws MicroException
121     */
122    protected function handleException(Exception $e): void {
123        $type = get_class($e);
124        $file = $e->getFile();
125        $line = $e->getLine();
126        $message = $e->getMessage();
127        $trace = $e->getTraceAsString();
128        $text = "`$type` in $file on line $line with message: $message\n$trace";
129        if (!$this->config) {
130            throw new MicroException("Couldn't instantiate Config::class, original exception:\n".$text);
131        }
132        if (!$this->logger) {
133            throw new MicroException("Couldn't instantiate Logger::class, original exception:\n".$text);
134        }
135        $this->logger->error($text);
136    }
137
138}