Passed
Pull Request — develop (#340)
by Felipe
04:23
created

ContainerUtils::getSubfolder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * PHPPgAdmin 6.0.0
5
 */
6
7
namespace PHPPgAdmin;
8
9
use Psr\Container\ContainerInterface;
10
use Slim\Collection;
11
use Slim\DefaultServicesProvider;
12
13
/**
14
 * @property array $deploy_info
15
 * @property \Slim\Flash\Messages $flash
16
 * @property \GuzzleHttp\Client $fcIntranetClient
17
 * @property \PHPPgAdmin\Misc $misc
18
 * @property \PHPPgAdmin\ViewManager $view
19
 * @property \Slim\Http\Request $request
20
 * @property \Slim\Http\Response $response
21
 * @property string $BASE_PATH
22
 * @property string $THEME_PATH
23
 * @property string $subFolder
24
 * @property bool $DEBUGMODE
25
 * @property bool $IN_TEST
26
 * @property string  $server
27
 * @property string $database
28
 * @property string  $schema
29
 * @property
30
 */
31
class ContainerUtils extends \Slim\Container implements ContainerInterface
32
{
33
    use \PHPPgAdmin\Traits\HelperTrait;
34
35
    /**
36
     * @var null|self
37
     */
38
    private static $instance;
39
40
    /**
41
     * $appInstance.
42
     *
43
     * @var null|\Slim\App
44
     */
45
    private static $appInstance;
46
47
    /**
48
     * Default settings.
49
     *
50
     * @var array
51
     */
52
    private $defaultSettings = [
53
        'httpVersion' => '1.1',
54
        'responseChunkSize' => 4096,
55
        'outputBuffering' => 'append',
56
        'determineRouteBeforeAppMiddleware' => false,
57
        'displayErrorDetails' => false,
58
        'addContentLengthHeader' => true,
59
        'routerCacheFile' => false,
60
    ];
61
62
    /**
63
     * Undocumented variable.
64
     *
65
     * @var array
66
     */
67
    private static $envConfig = [
68
        'BASE_PATH' => '',
69
        'subFolder' => '',
70
        'DEBUGMODE' => false,
71
        'THEME_PATH' => '',
72
    ];
73
74
    /**
75
     * @param array $values the parameters or objects
76
     */
77
    final public function __construct(array $values = [])
78
    {
79
        parent::__construct($values);
80
81
        $userSettings = $values['settings'] ?? [];
82
        $this->registerDefaultServices($userSettings);
83
84
        self::$instance = $this;
85
    }
86
87
    /**
88
     * Gets the subfolder.
89
     *
90
     * @param string $path The path
91
     *
92
     * @return string the subfolder
93
     */
94
    public function getSubfolder(string $path = ''): string
95
    {
96
        return \implode(\DIRECTORY_SEPARATOR, [$this->subFolder, $path]);
97
    }
98
99
    public static function getAppInstance(array $config = []): \Slim\App
100
    {
101
        $config = \array_merge(self::getDefaultConfig($config['debugmode'] ?? false), $config);
102
103
        $container = self::getContainerInstance($config);
104
105
        if (!self::$appInstance) {
106
            self::$appInstance = new \Slim\App($container);
107
        }
108
109
        return self::$appInstance;
110
    }
111
112
    public static function getContainerInstance(array $config = []): self
113
    {
114
        self::$envConfig = [
115
            'msg' => '',
116
            'appThemes' => [
117
                'default' => 'Default',
118
                'cappuccino' => 'Cappuccino',
119
                'gotar' => 'Blue/Green',
120
                'bootstrap' => 'Bootstrap3',
121
            ],
122
            'BASE_PATH' => $config['BASE_PATH'] ?? \dirname(__DIR__, 2),
123
            'subFolder' => $config['subfolder'] ?? '',
124
            'debug' => $config['debugmode'] ?? false,
125
            'THEME_PATH' => $config['theme_path'] ?? \dirname(__DIR__, 2) . '/assets/themes',
126
            'IN_TEST' => $config['IN_TEST'] ?? false,
127
            'webdbLastTab' => [],
128
        ];
129
130
        self::$envConfig = \array_merge(self::$envConfig, $config);
131
132
        if (!self::$instance) {
133
            self::$instance = new static(self::$envConfig);
134
135
            self::$instance
136
                ->withConf(self::$envConfig)
137
                ->setExtra()
138
                ->setMisc()
139
                ->setViews();
140
        }
141
        //ddd($container->subfolder);
142
        return self::$instance;
143
    }
144
145
    /**
146
     * Determines the redirection url according to query string.
147
     *
148
     * @return string the redirect url
149
     */
150
    public function getRedirectUrl()
151
    {
152
        $container = self::getContainerInstance();
153
        $query_string = $container->request->getUri()->getQuery();
154
155
        // if server_id isn't set, then you will be redirected to intro
156
        if (null === $container->request->getQueryParam('server')) {
157
            $destinationurl = self::$envConfig['subFolder'] . '/src/views/intro';
158
        } else {
159
            // otherwise, you'll be redirected to the login page for that server;
160
            $destinationurl = self::$envConfig['subFolder'] . '/src/views/login' . ($query_string ? '?' . $query_string : '');
161
        }
162
163
        return $destinationurl;
164
    }
165
166
    /**
167
     * Adds a flash message to the session that will be displayed on the next request.
168
     *
169
     * @param mixed  $content msg content (can be object, array, etc)
170
     * @param string $key     The key to associate with the message. Defaults to the stack
171
     *                        trace of the closure or method that called addFlassh
172
     */
173
    public function addFlash($content, $key = ''): void
174
    {
175
        if ('' === $key) {
176
            $key = self::getBackTrace();
177
        }
178
        $container = self::getContainerInstance();
179
        // $this->dump(__METHOD__ . ': addMessage ' . $key . '  ' . json_encode($content));
180
        if ($container->flash) {
181
            $container->flash->addMessage($key, $content);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type array<string,mixed|string>; however, parameter $key of Slim\Flash\Messages::addMessage() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
            $container->flash->addMessage(/** @scrutinizer ignore-type */ $key, $content);
Loading history...
182
        }
183
    }
184
185
    /**
186
     * Gets the destination with the last active tab selected for that controller
187
     * Usually used after going through a redirect route.
188
     *
189
     * @param string $subject The subject, usually a view name like 'server' or 'table'
190
     *
191
     * @return string The destination url with last tab set in the query string
192
     */
193
    public function getDestinationWithLastTab($subject)
194
    {
195
        $container = self::getContainerInstance();
196
        $_server_info = $container->misc->getServerInfo();
197
        $this->addFlash($subject, 'getDestinationWithLastTab');
198
        //$this->prtrace('$_server_info', $_server_info);
199
        // If username isn't set in server_info, you should login
200
        $url = $container->misc->getLastTabURL($subject) ?? ['url' => 'alldb', 'urlvars' => ['subject' => 'server']];
201
        $destinationurl = $this->getRedirectUrl();
202
203
        if (!isset($_server_info['username'])) {
204
            return $destinationurl;
205
        }
206
207
        if (!\is_array($url)) {
208
            return $this->getRedirectUrl($subject);
0 ignored issues
show
Unused Code introduced by
The call to PHPPgAdmin\ContainerUtils::getRedirectUrl() has too many arguments starting with $subject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
            return $this->/** @scrutinizer ignore-call */ getRedirectUrl($subject);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
209
        }
210
        $this->addFlash($url, 'getLastTabURL for ' . $subject);
211
        // Load query vars into superglobal arrays
212
        if (isset($url['urlvars'])) {
213
            $urlvars = [];
214
215
            foreach ($url['urlvars'] as $key => $urlvar) {
216
                //$this->prtrace($key, $urlvar);
217
                $urlvars[$key] = \PHPPgAdmin\Decorators\Decorator::get_sanitized_value($urlvar, $_REQUEST);
218
            }
219
            $_REQUEST = \array_merge($_REQUEST, $urlvars);
220
            $_GET = \array_merge($_GET, $urlvars);
221
        }
222
        $actionurl = \PHPPgAdmin\Decorators\Decorator::actionurl($url['url'], $_GET);
223
        $destinationurl = $actionurl->value($_GET);
224
225
        return \str_replace('views/?', "views/{$subject}?", $destinationurl);
226
    }
227
228
    /**
229
     * Adds an error to the errors array property of the container.
230
     *
231
     * @param string $errormsg The error msg
232
     *
233
     * @return\Slim\Container The app container
234
     */
235
    public function addError(string $errormsg): \Slim\Container
236
    {
237
        $container = self::getContainerInstance();
238
        $errors = $container->get('errors');
239
        $errors[] = $errormsg;
240
        $container->offsetSet('errors', $errors);
241
242
        return $container;
243
    }
244
245
    /**
246
     * Returns a string with html <br> variant replaced with a new line.
247
     *
248
     * @param string $msg message to parse (<br> separated)
249
     *
250
     * @return string parsed message (linebreak separated)
251
     */
252
    public static function br2ln($msg)
253
    {
254
        return \str_replace(['<br>', '<br/>', '<br />'], \PHP_EOL, $msg);
255
    }
256
257
    public static function getDefaultConfig(bool $debug = false): array
258
    {
259
        return  [
260
            'settings' => [
261
                'displayErrorDetails' => $debug,
262
                'determineRouteBeforeAppMiddleware' => true,
263
                'base_path' => \dirname(__DIR__, 2),
264
                'debug' => $debug,
265
                'phpMinVer' => '7.2', // PHP minimum version
266
                'addContentLengthHeader' => false,
267
                'appName' => 'PHPPgAdmin6',
268
            ],
269
        ];
270
    }
271
272
    /**
273
     * @param array $conf
274
     */
275
    private function withConf($conf): self
276
    {
277
        $container = self::getContainerInstance();
278
        $conf['plugins'] = [];
279
280
        $container->BASE_PATH = $conf['BASE_PATH'];
281
        $container->subFolder = $conf['subfolder'];
282
        $container->debug = $conf['debugmode'];
283
        $container->THEME_PATH = $conf['theme_path'];
284
        $container->IN_TEST = $conf['IN_TEST'];
285
        $container['errors'] = [];
286
        $container['conf'] = static function (\Slim\Container $c) use ($conf): array {
287
            $display_sizes = $conf['display_sizes'];
288
289
            if (\is_array($display_sizes)) {
290
                $conf['display_sizes'] = [
291
                    'schemas' => (bool) isset($display_sizes['schemas']) && true === $display_sizes['schemas'],
292
                    'tables' => (bool) isset($display_sizes['tables']) && true === $display_sizes['tables'],
293
                ];
294
            } else {
295
                $conf['display_sizes'] = [
296
                    'schemas' => (bool) $display_sizes,
297
                    'tables' => (bool) $display_sizes,
298
                ];
299
            }
300
301
            if (!isset($conf['theme'])) {
302
                $conf['theme'] = 'default';
303
            }
304
305
            foreach ($conf['servers'] as &$server) {
306
                if (!isset($server['port'])) {
307
                    $server['port'] = 5432;
308
                }
309
310
                if (!isset($server['sslmode'])) {
311
                    $server['sslmode'] = 'unspecified';
312
                }
313
            }
314
315
            return $conf;
316
        };
317
318
        $container->subFolder = $conf['subfolder'];
319
320
        return $this;
321
    }
322
323
    /**
324
     * Sets the views.
325
     *
326
     * @return self ( description_of_the_return_value )
327
     */
328
    private function setViews()
329
    {
330
        $container = self::getContainerInstance();
331
332
        /**
333
         * @return \PHPPgAdmin\ViewManager
334
         */
335
        $container['view'] = static function (\Slim\Container $c): \PHPPgAdmin\ViewManager {
336
            $misc = $c->misc;
337
            $view = new ViewManager(BASE_PATH . '/assets/templates', [
338
                'cache' => BASE_PATH . '/temp/twigcache',
339
                'auto_reload' => $c->get('settings')['debug'],
340
                'debug' => $c->get('settings')['debug'],
341
            ], $c);
342
343
            $misc->setView($view);
344
345
            return $view;
346
        };
347
348
        return $this;
349
    }
350
351
    /**
352
     * Sets the instance of Misc class.
353
     *
354
     * @return self ( description_of_the_return_value )
355
     */
356
    private function setMisc()
357
    {
358
        $container = self::getContainerInstance();
359
        /**
360
         * @return \PHPPgAdmin\Misc
361
         */
362
        $container['misc'] = static function (\Slim\Container $c): \PHPPgAdmin\Misc {
363
            $misc = new \PHPPgAdmin\Misc($c);
364
365
            $conf = $c->get('conf');
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
366
367
            // 4. Check for theme by server/db/user
368
            $_server_info = $misc->getServerInfo();
369
370
            /* starting with PostgreSQL 9.0, we can set the application name */
371
            if (isset($_server_info['pgVersion']) && 9 <= $_server_info['pgVersion']) {
372
                \putenv('PGAPPNAME=' . $c->get('settings')['appName'] . '_' . $c->get('settings')['appVersion']);
373
            }
374
375
            return $misc;
376
        };
377
378
        return $this;
379
    }
380
381
    private function setExtra()
382
    {
383
        $container = self::getContainerInstance();
384
        $container['flash'] = static function (): \Slim\Flash\Messages {
385
            return new \Slim\Flash\Messages();
386
        };
387
388
        $container['lang'] = static function (\Slim\Container $c): array {
389
            $translations = new \PHPPgAdmin\Translations($c);
390
391
            return $translations->lang;
392
        };
393
394
        return $this;
395
    }
396
397
    /**
398
     * This function registers the default services that Slim needs to work.
399
     *
400
     * All services are shared, they are registered such that the
401
     * same instance is returned on subsequent calls.
402
     *
403
     * @param array $userSettings Associative array of application settings
404
     */
405
    private function registerDefaultServices($userSettings): void
406
    {
407
        $defaultSettings = $this->defaultSettings;
408
409
        /**
410
         * This service MUST return an array or an instance of ArrayAccess.
411
         *
412
         * @return array|ArrayAccess
413
         */
414
        $this['settings'] = static function () use ($userSettings, $defaultSettings): \Slim\Collection {
415
            return new Collection(\array_merge($defaultSettings, $userSettings));
416
        };
417
418
        $defaultProvider = new DefaultServicesProvider();
419
        $defaultProvider->register($this);
420
    }
421
}
422