Passed
Pull Request — master (#267)
by Felipe
07:20
created

ContainerUtils::createContainer()   B

Complexity

Conditions 10
Paths 4

Size

Total Lines 58
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 34
nc 4
nop 1
dl 0
loc 58
rs 7.6666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-RC9-3-gd93ec300
5
 */
6
7
namespace PHPPgAdmin;
8
9
use Psr\Container\ContainerInterface;
10
use Slim\App;
11
12
\defined('BASE_PATH') || \define('BASE_PATH', \dirname(__DIR__, 2));
13
\defined('THEME_PATH') || \define('THEME_PATH', BASE_PATH . '/assets/themes');
14
\defined('SUBFOLDER') || \define(
15
    'SUBFOLDER',
16
    \str_replace($_SERVER['DOCUMENT_ROOT'] ?? '', '', BASE_PATH)
17
);
18
\defined('DEBUGMODE') || \define('DEBUGMODE', false);
19
\defined('IN_TEST') || \define('IN_TEST', false);
20
21
/**
22
 * @file
23
 * A class that adds convenience methods to the container
24
 */
25
26
/**
27
 * A class that adds convenience methods to the container.
28
 */
29
class ContainerUtils
30
{
31
    use \PHPPgAdmin\Traits\HelperTrait;
32
    /**
33
     * @var string
34
     */
35
    const BASE_PATH = BASE_PATH;
36
    /**
37
     * @var string
38
     */
39
    const SUBFOLDER = SUBFOLDER;
40
    /**
41
     * @var string
42
     */
43
    const DEBUGMODE = DEBUGMODE;
44
45
    /**
46
     *
47
     * @var string
48
     */
49
    const THEME_PATH = THEME_PATH;
50
    /**
51
     * @var ContainerInterface
52
     */
53
    protected $container;
54
55
    /**
56
     * @var App
57
     */
58
    protected $_app;
59
60
    /**
61
     * @var self
62
     */
63
    protected static $_instance;
64
65
    /**
66
     * Constructor of the ContainerUtils class.
67
     */
68
    public function __construct()
69
    {
70
        $composerinfo = \json_decode(\file_get_contents(BASE_PATH . '/composer.json'));
71
        $appVersion   = $composerinfo->extra->version;
72
73
        $phpMinVer = (\str_replace(['<', '>', '='], '', $composerinfo->require->php));
74
        //$this->dump($composerinfo);
75
        $settings = [
76
            'determineRouteBeforeAppMiddleware' => true,
77
            'base_path'                         => self::BASE_PATH,
78
            'debug'                             => self::DEBUGMODE,
79
80
            // Configuration file version.  If this is greater than that in config.inc.php, then
81
            // the app will refuse to run.  This and $conf['version'] should be incremented whenever
82
            // backwards incompatible changes are made to config.inc.php-dist.
83
            'base_version'                      => 60,
84
            // Application version
85
            'appVersion'                        => 'v' . $appVersion,
86
            // Application name
87
            'appName'                           => 'phpPgAdmin6',
88
89
            // PostgreSQL and PHP minimum version
90
            'postgresqlMinVer'                  => '9.3',
91
            'phpMinVer'                         => $phpMinVer,
92
            'displayErrorDetails'               => self::DEBUGMODE,
93
            'addContentLengthHeader'            => false,
94
        ];
95
96
        if (!self::DEBUGMODE && !IN_TEST) {
97
            $settings['routerCacheFile'] = self::BASE_PATH . '/temp/route.cache.php';
98
        }
99
        $config = [
100
            'msg'       => '',
101
            'appThemes' => [
102
                'default'    => 'Default',
103
                'cappuccino' => 'Cappuccino',
104
                'gotar'      => 'Blue/Green',
105
                'bootstrap'  => 'Bootstrap3',
106
            ],
107
            'settings'  => $settings,
108
        ];
109
110
        $this->_app = new App($config);
111
112
        // Fetch DI Container
113
        $container                = $this->_app->getContainer();
114
        $container['utils']       = $this;
115
        $container['version']     = 'v' . $appVersion;
116
        $container['errors']      = [];
117
        $container['requestobj']  = $container['request'];
118
        $container['responseobj'] = $container['response'];
119
        $this->container          = $container;
120
    }
121
122
    public static function getContainerInstance()
123
    {
124
        $_instance = self::getInstance();
125
126
        if (!$container = $_instance->container) {
127
            throw new \Exception('Could not get a container');
128
        }
129
130
        return $container;
131
    }
132
133
    public static function getInstance()
134
    {
135
        if (!self::$_instance) {
136
            self::$_instance = new self();
137
        }
138
139
        return self::$_instance;
140
    }
141
142
    public static function createContainer($conf)
143
    {
144
        $container = self::getContainerInstance();
145
        // Complete missing conf keys
146
        $container['conf'] = static function ($c) use ($conf) {
147
            $display_sizes = $conf['display_sizes'] ?? false;
148
149
            $conf['display_sizes'] = [
150
                'schemas' => (bool) $display_sizes,
151
                'tables'  => (bool) $display_sizes,
152
            ];
153
154
            if (\is_array($display_sizes)) {
155
                $conf['display_sizes'] = [
156
                    'schemas' => $display_sizes['schemas'] ?? \in_array('schemas', $display_sizes, true),
157
                    'tables'  => $display_sizes['tables'] ?? \in_array('tables', $display_sizes, true),
158
                ];
159
            }
160
161
            // Plugins are removed
162
            $conf['plugins'] = [];
163
164
            if (!isset($conf['theme'])) {
165
                $conf['theme'] = 'default';
166
            }
167
168
            foreach ($conf['servers'] as &$server) {
169
                if (!isset($server['port'])) {
170
                    $server['port'] = 5432;
171
                }
172
173
                if (!isset($server['sslmode'])) {
174
                    $server['sslmode'] = 'unspecified';
175
                }
176
            }
177
178
            return $conf;
179
        };
180
        $requestUri = $container->request->getUri() ?? null;
0 ignored issues
show
Bug introduced by
Accessing request on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
181
182
        if ($requestBasePath = $requestUri->getBasePath() ?? null) {
0 ignored issues
show
Bug introduced by
The method getBasePath() does not exist on null. ( Ignorable by Annotation )

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

182
        if ($requestBasePath = $requestUri->/** @scrutinizer ignore-call */ getBasePath() ?? null) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
183
            $subfolder = $requestBasePath;
184
        } elseif (\PHP_SAPI === 'cli-server') {
185
            $subfolder = '/index.php';
186
        } elseif (isset($conf['subfolder']) && \is_string($conf['subfolder'])) {
187
            $subfolder = $conf['subfolder'];
188
        } else {
189
            $subfolder = \str_replace(
190
                $container->environment->get('DOCUMENT_ROOT'),
191
                '',
192
                \dirname(__DIR__, 2)
193
            );
194
        }
195
196
        $container->subfolder = $subfolder ?? self::SUBFOLDER;
0 ignored issues
show
Bug introduced by
Accessing subfolder on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
197
        $container->subfolder = $subfolder ?? self::SUBFOLDER;
198
        //ddd($container->subfolder);
199
        return [$container, self::$_instance->_app];
200
    }
201
202
    public function maybeRenderIframes($response, $subject, $query_string)
203
    {
204
        $c = self::getContainerInstance();
205
206
        $in_test = $c->view->offsetGet('in_test');
0 ignored issues
show
Bug introduced by
Accessing view on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
207
208
        if ('1' === $in_test) {
209
            $className  = '\PHPPgAdmin\Controller\\' . \ucfirst($subject) . 'Controller';
210
            $controller = new $className($c);
211
212
            return $controller->render();
213
        }
214
215
        $viewVars = [
216
            'url'            => '/src/views/' . $subject . ($query_string ? '?' . $query_string : ''),
217
            'headertemplate' => 'header.twig',
218
        ];
219
220
        return $c->view->render($response, 'iframe_view.twig', $viewVars);
221
    }
222
223
    /**
224
     * Gets the theme from
225
     * 1. The $_REQUEST global (when it's chosen from start screen)
226
     * 2. Server specific config theme 3.- $_SESSION global (subsequent requests after 1.) 4.- $_COOKIE global (mostly
227
     *    fallback for $_SESSION after 1.- and 3.-) 5.- theme as set in config 6.- 'default' theme.
228
     *
229
     * @param array      $conf         The conf
230
     * @param null|mixed $_server_info
231
     *
232
     * @return string the theme
233
     */
234
    public function getTheme(array $conf, $_server_info = null)
235
    {
236
        $_theme = null;
237
        // List of themes
238
        $themefolders = $this->getThemeFolders();
239
        // Check if theme is in $_REQUEST, $_SESSION or $_COOKIE
240
        // 1.- First priority: $_REQUEST, this happens when you use the selector
241
        if (\array_key_exists('theme', $_REQUEST) &&
242
            \array_key_exists($_REQUEST['theme'], $themefolders)) {
243
            $_theme = $_REQUEST['theme'];
244
        } elseif ( // otherwise, see if there's a theme associated with this particular server
0 ignored issues
show
Coding Style introduced by
First condition of a multi-line IF statement must directly follow the opening parenthesis
Loading history...
245
            null !== $_server_info &&
246
            \array_key_exists('theme', $_server_info) &&
247
            \is_string($_server_info['theme']) &&
248
            \array_key_exists($_COOKIE['ppaTheme'], $themefolders)) {
249
            $_theme = $_server_info['theme'];
250
        } elseif (\array_key_exists('ppaTheme', $_SESSION) &&
251
            \array_key_exists($_SESSION['ppaTheme'], $themefolders)) {
252
            // otherwise check $_SESSION
253
            $_theme = $_SESSION['ppaTheme'];
254
        } elseif (\array_key_exists('ppaTheme', $_SESSION) &&
255
            \array_key_exists($_COOKIE['ppaTheme'], $themefolders)) {
256
            // oterwise check $_COOKIE
257
            $_theme = $_COOKIE['ppaTheme'];
258
        } elseif ( // see if there's a valid theme set in config file
0 ignored issues
show
Coding Style introduced by
First condition of a multi-line IF statement must directly follow the opening parenthesis
Loading history...
259
            \array_key_exists('theme', $conf) &&
260
            \is_string($conf['theme']) &&
261
            \array_key_exists($conf['theme'], $themefolders)) {
262
            $_theme = $conf['theme'];
263
        } else {
264
            // okay then, use default theme
265
            $_theme = 'default';
266
        }
267
268
        return $_theme;
269
    }
270
271
    /**
272
     * Determines the redirection url according to query string.
273
     *
274
     * @return string the redirect url
275
     */
276
    public function getRedirectUrl()
277
    {
278
        $query_string = $this->container->requestobj->getUri()->getQuery();
0 ignored issues
show
Bug introduced by
Accessing requestobj on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
279
280
        // if server_id isn't set, then you will be redirected to intro
281
        if (null === $this->container->requestobj->getQueryParam('server')) {
282
            $destinationurl = self::SUBFOLDER . '/src/views/intro';
283
        } else {
284
            // otherwise, you'll be redirected to the login page for that server;
285
            $destinationurl = self::SUBFOLDER . '/src/views/login' . ($query_string ? '?' . $query_string : '');
286
        }
287
288
        return $destinationurl;
289
    }
290
291
    /**
292
     * Adds a flash message to the session that will be displayed on the next request.
293
     *
294
     * @param mixed  $content msg content (can be object, array, etc)
295
     * @param string $key     The key to associate with the message. Defaults to the stack
296
     *                        trace of the closure or method that called addFlassh
297
     */
298
    public function addFlash($content, $key = ''): void
299
    {
300
        if ('' === $key) {
301
            $key = self::getBackTrace();
302
        }
303
        // $this->dump(__METHOD__ . ': addMessage ' . $key . '  ' . json_encode($content));
304
305
        $this->container->flash->addMessage($key, $content);
0 ignored issues
show
Bug introduced by
Accessing flash on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
306
    }
307
308
    /**
309
     * Gets the destination with the last active tab selected for that controller
310
     * Usually used after going through a redirect route.
311
     *
312
     * @param string $subject The subject, usually a view name like 'server' or 'table'
313
     *
314
     * @return string The destination url with last tab set in the query string
315
     */
316
    public function getDestinationWithLastTab($subject)
317
    {
318
        $_server_info = $this->container->misc->getServerInfo();
0 ignored issues
show
Bug introduced by
Accessing misc on the interface Psr\Container\ContainerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
319
        $this->addFlash($subject, 'getDestinationWithLastTab');
320
        // If username isn't set in server_info, you should login
321
        if (!isset($_server_info['username'])) {
322
            $destinationurl = $this->getRedirectUrl();
323
        } else {
324
            $url = $this->container->misc->getLastTabURL($subject);
325
            $this->addFlash($url, 'getLastTabURL for ' . $subject);
326
            // Load query vars into superglobal arrays
327
            if (isset($url['urlvars'])) {
328
                $urlvars = [];
329
330
                foreach ($url['urlvars'] as $key => $urlvar) {
331
                    $urlvars[$key] = \PHPPgAdmin\Decorators\Decorator::get_sanitized_value($urlvar, $_REQUEST);
332
                }
333
                $_REQUEST = \array_merge($_REQUEST, $urlvars);
334
                $_GET     = \array_merge($_GET, $urlvars);
335
            }
336
337
            $actionurl      = \PHPPgAdmin\Decorators\Decorator::actionurl($url['url'], $_GET);
338
            $destinationurl = $actionurl->value($_GET);
339
        }
340
        $destinationurl = \str_replace('views/?', "views/{$subject}?", $destinationurl);
341
        // $this->prtrace('destinationurl for ' . $subject, $destinationurl);
342
        return $destinationurl;
343
    }
344
345
    /**
346
     * Adds an error to the errors array property of the container.
347
     *
348
     * @param string $errormsg The error msg
349
     *
350
     * @return ContainerInterface The app container
351
     */
352
    public function addError(string $errormsg): ContainerInterface
353
    {
354
        $errors   = $this->container->get('errors');
355
        $errors[] = $errormsg;
356
        $this->container->offsetSet('errors', $errors);
357
358
        return $this->container;
359
    }
360
361
    /**
362
     * Traverse THEME_PATH, consider as theme folders those which
363
     * contain a `global.css` stylesheet.
364
     *
365
     * @return array the theme folders
366
     */
367
    private function getThemeFolders()
368
    {
369
        // no THEME_PATH (how?) then return empty array
370
        if (!$gestor = \opendir(self::THEME_PATH)) {
371
            \closedir($gestor);
0 ignored issues
show
Bug introduced by
It seems like $gestor can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, 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

371
            \closedir(/** @scrutinizer ignore-type */ $gestor);
Loading history...
372
373
            return [];
374
        }
375
        $themefolders = [];
376
377
        /* This is the right way to iterate on a folder */
378
        while (false !== ($foldername = \readdir($gestor))) {
379
            if ('.' === $foldername || '..' === $foldername) {
380
                continue;
381
            }
382
383
            $folderpath = \sprintf('%s%s%s', self::THEME_PATH, \DIRECTORY_SEPARATOR, $foldername);
384
            $stylesheet = \sprintf('%s%s%s', $folderpath, \DIRECTORY_SEPARATOR, 'global.css');
385
            // if $folderpath if indeed a folder and contains a global.css file, then it's a theme
386
            if (\is_dir($folderpath) &&
387
                \is_file($stylesheet)) {
388
                $themefolders[$foldername] = $folderpath;
389
            }
390
        }
391
392
        \closedir($gestor);
393
394
        return $themefolders;
395
    }
396
}
397