Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.95% covered (success)
80.95%
51 / 63
50.00% covered (warning)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Application
80.95% covered (success)
80.95%
51 / 63
50.00% covered (warning)
50.00%
3 / 6
24.05
0.00% covered (danger)
0.00%
0 / 1
 load
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 prepare
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getConsole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 cliError
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
3.33
 initDb
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
8
 check
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Kettle;
16
17use Pop\Console\Console;
18use Pop\Db;
19use Pop\Kettle\Controller\ApplicationController;
20
21/**
22 * Main module class
23 *
24 * @category   Pop\Kettle
25 * @package    Pop\Kettle
26 * @author     Nick Sagona, III <nick@popphp.org>
27 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
28 * @license    https://www.popphp.org/license     New BSD License
29 * @version    3.0.0
30 */
31class Application extends \Pop\Application
32{
33
34    /**
35     * Application name
36     * @var string
37     */
38    const string NAME = 'pop-kettle';
39
40    /**
41     * Application full name
42     * @var string
43     */
44    const string FULL_NAME = 'Pop Kettle';
45
46    /**
47     * Application version
48     * @var string
49     */
50    const string VERSION = '3.0.0';
51
52    /**
53     * Application name
54     * @var ?string
55     */
56    protected ?string $name = self::NAME;
57
58    /**
59     * Application full name
60     * @var ?string
61     */
62    protected ?string $fullName = self::FULL_NAME;
63
64    /**
65     * Version
66     * @var ?string
67     */
68    protected ?string $version = self::VERSION;
69
70    /**
71     * Shared console object
72     * @var ?Console
73     */
74    protected ?Console $console = null;
75
76    /**
77     * Load application
78     *
79     * @return Application
80     */
81    public function load(): Application
82    {
83        $dir = getcwd();
84        if (file_exists($dir . '/app/config/database.php')) {
85            $this->initDb(include $dir . '/app/config/database.php');
86        }
87
88        $this->console = new Console(120);
89        $this->console->write(PHP_EOL . $this->console->header(self::FULL_NAME, '=', null, 'left', true, true));
90
91        $this->on('app.route.pre', function () {
92            Event\Console::maintenanceDisplay($this->console);
93            Event\Console::productionDisplay($this->console);
94        })->on('app.dispatch.post', function() {
95            $this->console->write();
96        });
97
98        return $this;
99    }
100
101    /**
102     * Prepare application
103     *   - determine if the route is a kettle native route or a custom application route
104     *
105     * @return \Pop\Application
106     */
107    public function prepare(): \Pop\Application
108    {
109        $app = $this;
110
111        if (($this->router !== null)) {
112            $this->router->getRouteMatch()->match();
113            $dispatchable = $this->router->getRouteMatch()->getDispatchable();
114
115            // If it's a custom command
116            if (!str_starts_with($dispatchable, 'Pop\Kettle')) {
117                $resolved = (new Model\Application())->resolveAppInstance(getcwd(), $this->autoloader(), $this->config['routes']);
118                if ($resolved !== null) {
119                    $app = $resolved;
120                }
121            }
122        }
123
124        return $app;
125    }
126
127    /**
128     * Get the shared console object
129     *
130     * @return ?Console
131     */
132    public function getConsole(): ?Console
133    {
134        return $this->console;
135    }
136
137    /**
138     * CLI error handler method
139     *
140     * @param  \Exception $exception
141     * @param  bool       $exit
142     * @return void
143     */
144    public function cliError(\Exception $exception, bool $exit = true): void
145    {
146        (new Console())->alertDanger(strip_tags($exception->getMessage()));
147
148        echo (stripos(PHP_OS, 'win') === false) ?
149            "    Try \x1b[1;33m./kettle help\x1b[0m for help" . PHP_EOL . PHP_EOL :
150            '    Try \'./kettle help\' for help' . PHP_EOL . PHP_EOL;
151
152        if ($exit) {
153            exit(127);
154        }
155    }
156
157    /**
158     * Initialize database service
159     *
160     * @param  array $database
161     * @throws \Pop\Db\Adapter\Exception
162     * @return void
163     */
164    public function initDb(array $database): void
165    {
166        foreach ($database as $db => $dbConfig) {
167            if (!empty($dbConfig['adapter']) && !empty($dbConfig['database'])) {
168                $adapter = $dbConfig['adapter'];
169                $options = [
170                    'database' => $dbConfig['database'],
171                    'username' => $dbConfig['username'] ?? null,
172                    'password' => $dbConfig['password'] ?? null,
173                    'host'     => $dbConfig['host'] ?? null,
174                    'type'     => $dbConfig['type'] ?? null
175                ];
176
177                $check = Db\Db::check($adapter, $options);
178
179                if ($check !== true) {
180                    throw new \Pop\Db\Adapter\Exception((string)$check);
181                }
182
183                $dbService = 'database';
184                if ($db != 'default') {
185                    $dbService .= '_' . $db;
186                }
187
188                $this->services()->set($dbService, [
189                    'call'   => 'Pop\Db\Db::connect',
190                    'params' => [
191                        'adapter' => $adapter,
192                        'options' => $options
193                    ]
194                ]);
195
196                if ($db == 'default') {
197                    if ($this->services()->isAvailable('database')) {
198                        Db\Record::setDb($this->services['database']);
199                    }
200                }
201            }
202        }
203    }
204
205    /**
206     * Application install check (post-install-cmd for main framework installation)
207     *
208     * @return void
209     */
210    public static function check(): void
211    {
212        if (!file_exists(getcwd() . '/.env')) {
213            $console = new Console(120);
214            $console->write();
215            $appInit = $console->prompt(
216                'Do you want to initialize your application now? [Y/N] ', ['y', 'n']
217            );
218            $console->write();
219            if (strtolower($appInit) == 'y') {
220                (new ApplicationController(new self(include __DIR__ . '/../config/app.console.php'), $console))->init();
221            }
222        }
223    }
224
225}