diff options
Diffstat (limited to 'src/classes/ContainerUtils.php')
-rw-r--r-- | src/classes/ContainerUtils.php | 504 |
1 files changed, 185 insertions, 319 deletions
diff --git a/src/classes/ContainerUtils.php b/src/classes/ContainerUtils.php index 36e4b2a6..dffc30e0 100644 --- a/src/classes/ContainerUtils.php +++ b/src/classes/ContainerUtils.php @@ -7,238 +7,143 @@ namespace PHPPgAdmin; use Psr\Container\ContainerInterface; -use Slim\App; - -\defined('BASE_PATH') || \define('BASE_PATH', \dirname(__DIR__, 2)); -\defined('THEME_PATH') || \define('THEME_PATH', BASE_PATH . '/assets/themes'); - -\defined('DEBUGMODE') || \define('DEBUGMODE', false); -\defined('IN_TEST') || \define('IN_TEST', false); +use Slim\Collection; +use Slim\DefaultServicesProvider; /** - * A class that adds convenience methods to the container. + * @property array $deploy_info + * @property \Slim\Flash\Messages $flash + * @property \GuzzleHttp\Client $fcIntranetClient + * @property \PHPPgAdmin\Misc $misc + * @property \PHPPgAdmin\ViewManager $view + * @property \Slim\Http\Request $request + * @property \Slim\Http\Response $response + * @property string $BASE_PATH + * @property string $THEME_PATH + * @property string $subFolder + * @property bool $DEBUGMODE + * @property bool $IN_TEST + * @property string $server + * @property string $database + * @property string $schema + * @property */ -class ContainerUtils +class ContainerUtils extends \Slim\Container implements ContainerInterface { use \PHPPgAdmin\Traits\HelperTrait; - /** - * @var string - */ - const BASE_PATH = BASE_PATH; - /** - * @var string - */ - const SUBFOLDER = PHPPGA_SUBFOLDER; - /** - * @var string - */ - const DEBUGMODE = DEBUGMODE; - - /** - * @var string - */ - const THEME_PATH = THEME_PATH; /** - * @var ContainerInterface + * @var null|self */ - protected $container; + private static $instance; /** - * @var App + * $appInstance. + * + * @var null|\Slim\App */ - protected $_app; + private static $appInstance; /** + * Default settings. + * * @var array */ - protected $conf; + private $defaultSettings = [ + 'httpVersion' => '1.1', + 'responseChunkSize' => 4096, + 'outputBuffering' => 'append', + 'determineRouteBeforeAppMiddleware' => false, + 'displayErrorDetails' => false, + 'addContentLengthHeader' => true, + 'routerCacheFile' => false, + ]; /** - * @var self + * Undocumented variable. + * + * @var array */ - protected static $_instance; + private static $envConfig = [ + 'BASE_PATH' => '', + 'subFolder' => '', + 'DEBUGMODE' => false, + 'THEME_PATH' => '', + ]; /** - * Constructor of the ContainerUtils class. + * @param array $values the parameters or objects */ - public function __construct() + final public function __construct(array $values = []) { - $composerinfo = \json_decode(\file_get_contents(BASE_PATH . '/composer.json')); - $appVersion = $composerinfo->extra->version; - - $phpMinVer = (\str_replace(['<', '>', '='], '', $composerinfo->require->php)); - //$this->prtrace($appVersion); - //$this->dump($composerinfo); - $settings = [ - 'determineRouteBeforeAppMiddleware' => true, - 'base_path' => self::BASE_PATH, - 'subfolder' => self::SUBFOLDER, - 'debug' => self::DEBUGMODE, - - // Configuration file version. If this is greater than that in config.inc.php, then - // the app will refuse to run. This and $conf['version'] should be incremented whenever - // backwards incompatible changes are made to config.inc.php-dist. - 'base_version' => 61, - // Application version - 'appVersion' => 'v' . $appVersion, - // Application name - 'appName' => 'phpPgAdmin6', - - // PostgreSQL and PHP minimum version - 'postgresqlMinVer' => '9.3', - 'phpMinVer' => $phpMinVer, - 'displayErrorDetails' => self::DEBUGMODE, - 'addContentLengthHeader' => false, - ]; - - if (!self::DEBUGMODE && !IN_TEST) { - $settings['routerCacheFile'] = self::BASE_PATH . '/temp/route.cache.php'; - } - $config = [ - 'msg' => '', - 'appThemes' => [ - 'default' => 'Default', - 'cappuccino' => 'Cappuccino', - 'gotar' => 'Blue/Green', - 'bootstrap' => 'Bootstrap3', - ], - 'settings' => $settings, - ]; - - $this->_app = new App($config); + parent::__construct($values); - // Fetch DI Container - $container = $this->_app->getContainer(); - $container['utils'] = $this; - $container['version'] = 'v' . $appVersion; - $container['errors'] = []; - $container['requestobj'] = $container['request']; - $container['responseobj'] = $container['response']; + $userSettings = $values['settings'] ?? []; + $this->registerDefaultServices($userSettings); - $this->container = $container; + self::$instance = $this; } /** - * Gets the container instance. + * Gets the subfolder. * - * @throws \Exception (description) + * @param string $path The path * - * @return ContainerInterface the container instance + * @return string the subfolder */ - public static function getContainerInstance() + public function getSubfolder(string $path = ''): string { - $_instance = self::getInstance(); - - if (!$container = $_instance->container) { - throw new \Exception('Could not get a container'); - } - - return $container; + return \implode(\DIRECTORY_SEPARATOR, [$this->subFolder, $path]); } - /** - * Gets the instance. - * - * @return self the instance - */ - public static function getInstance() + public static function getAppInstance(array $config = []): \Slim\App { - if (!self::$_instance) { - self::$_instance = new self(); - } + $config = \array_merge(self::getDefaultConfig($config['debugmode'] ?? false), $config); - return self::$_instance; - } + $container = self::getContainerInstance($config); - /** - * Creates a container. - * - * @param array $conf The conf - * - * @return [ContainerInterface,App] ( description_of_the_return_value ) - */ - public static function createContainer($conf) - { - $_instance = self::getInstance(); - - $_instance - ->setConf($conf) - ->setExtra() - ->setMisc() - ->setViews(); + if (!self::$appInstance) { + self::$appInstance = new \Slim\App($container); + } - //ddd($container->subfolder); - return [$_instance->container, self::$_instance->_app]; + return self::$appInstance; } - public function maybeRenderIframes($response, $subject, $query_string) + public static function getContainerInstance(array $config = []): self { - $c = self::getContainerInstance(); - - $in_test = $c->view->offsetGet('in_test'); - - if ('1' === $in_test) { - $className = '\PHPPgAdmin\Controller\\' . \ucfirst($subject) . 'Controller'; - $controller = new $className($c); + self::$envConfig = [ + 'msg' => '', + 'appThemes' => [ + 'default' => 'Default', + 'cappuccino' => 'Cappuccino', + 'gotar' => 'Blue/Green', + 'bootstrap' => 'Bootstrap3', + ], + 'BASE_PATH' => $config['BASE_PATH'] ?? \dirname(__DIR__, 2), + 'subFolder' => $config['subfolder'] ?? '', + 'debug' => $config['debugmode'] ?? false, + 'THEME_PATH' => $config['theme_path'] ?? \dirname(__DIR__, 2) . '/assets/themes', + 'IN_TEST' => $config['IN_TEST'] ?? false, + 'webdbLastTab' => [], + ]; - return $controller->render(); - } + self::$envConfig = \array_merge(self::$envConfig, $config); - $viewVars = [ - 'url' => '/src/views/' . $subject . ($query_string ? '?' . $query_string : ''), - 'headertemplate' => 'header.twig', - ]; + if (!self::$instance) { + self::$instance = new static(self::$envConfig); - return $c->view->render($response, 'iframe_view.twig', $viewVars); - } + self::$instance + ->withConf(self::$envConfig); - /** - * Gets the theme from - * 1. The $_REQUEST global (when it's chosen from start screen) - * 2. Server specific config theme 3.- $_SESSION global (subsequent requests after 1.) 4.- $_COOKIE global (mostly - * fallback for $_SESSION after 1.- and 3.-) 5.- theme as set in config 6.- 'default' theme. - * - * @param array $conf The conf - * @param null|mixed $_server_info - * - * @return string the theme - */ - public function getTheme(array $conf, $_server_info = null) - { - $_theme = null; - // List of themes - $themefolders = $this->getThemeFolders(); - // Check if theme is in $_REQUEST, $_SESSION or $_COOKIE - // 1.- First priority: $_REQUEST, this happens when you use the selector - if (\array_key_exists('theme', $_REQUEST) && - \array_key_exists($_REQUEST['theme'], $themefolders)) { - $_theme = $_REQUEST['theme']; - } elseif ( // otherwise, see if there's a theme associated with this particular server - null !== $_server_info && - \array_key_exists('theme', $_server_info) && - \is_string($_server_info['theme']) && - \array_key_exists($_COOKIE['ppaTheme'], $themefolders)) { - $_theme = $_server_info['theme']; - } elseif (\array_key_exists('ppaTheme', $_SESSION) && - \array_key_exists($_SESSION['ppaTheme'], $themefolders)) { - // otherwise check $_SESSION - $_theme = $_SESSION['ppaTheme']; - } elseif (\array_key_exists('ppaTheme', $_SESSION) && - \array_key_exists($_COOKIE['ppaTheme'], $themefolders)) { - // oterwise check $_COOKIE - $_theme = $_COOKIE['ppaTheme']; - } elseif ( // see if there's a valid theme set in config file - \array_key_exists('theme', $conf) && - \is_string($conf['theme']) && - \array_key_exists($conf['theme'], $themefolders)) { - $_theme = $conf['theme']; - } else { - // okay then, use default theme - $_theme = 'default'; + $handlers = new ContainerHandlers(self::$instance); + $handlers->setExtra() + ->setMisc() + ->setViews() + ->storeMainRequestParams() + ->setHaltHandler(); } - - return $_theme; + //ddd($container->subfolder); + return self::$instance; } /** @@ -248,14 +153,15 @@ class ContainerUtils */ public function getRedirectUrl() { - $query_string = $this->container->requestobj->getUri()->getQuery(); + $container = self::getContainerInstance(); + $query_string = $container->request->getUri()->getQuery(); // if server_id isn't set, then you will be redirected to intro - if (null === $this->container->requestobj->getQueryParam('server')) { - $destinationurl = self::SUBFOLDER . '/src/views/intro'; + if (null === $container->request->getQueryParam('server')) { + $destinationurl = self::$envConfig['subFolder'] . '/src/views/intro'; } else { // otherwise, you'll be redirected to the login page for that server; - $destinationurl = self::SUBFOLDER . '/src/views/login' . ($query_string ? '?' . $query_string : ''); + $destinationurl = self::$envConfig['subFolder'] . '/src/views/login' . ($query_string ? '?' . $query_string : ''); } return $destinationurl; @@ -273,9 +179,10 @@ class ContainerUtils if ('' === $key) { $key = self::getBackTrace(); } + $container = self::getContainerInstance(); // $this->dump(__METHOD__ . ': addMessage ' . $key . ' ' . json_encode($content)); - if ($this->container->flash) { - $this->container->flash->addMessage($key, $content); + if ($container->flash) { + $container->flash->addMessage($key, $content); } } @@ -289,33 +196,37 @@ class ContainerUtils */ public function getDestinationWithLastTab($subject) { - $_server_info = $this->container->misc->getServerInfo(); + $container = self::getContainerInstance(); + $_server_info = $container->misc->getServerInfo(); $this->addFlash($subject, 'getDestinationWithLastTab'); //$this->prtrace('$_server_info', $_server_info); // If username isn't set in server_info, you should login + $url = $container->misc->getLastTabURL($subject) ?? ['url' => 'alldb', 'urlvars' => ['subject' => 'server']]; + $destinationurl = $this->getRedirectUrl(); + if (!isset($_server_info['username'])) { - $destinationurl = $this->getRedirectUrl(); - } else { - $url = $this->container->misc->getLastTabURL($subject); - $this->addFlash($url, 'getLastTabURL for ' . $subject); - // Load query vars into superglobal arrays - if (isset($url['urlvars'])) { - $urlvars = []; - - foreach ($url['urlvars'] as $key => $urlvar) { - //$this->prtrace($key, $urlvar); - $urlvars[$key] = \PHPPgAdmin\Decorators\Decorator::get_sanitized_value($urlvar, $_REQUEST); - } - $_REQUEST = \array_merge($_REQUEST, $urlvars); - $_GET = \array_merge($_GET, $urlvars); - } + return $destinationurl; + } - $actionurl = \PHPPgAdmin\Decorators\Decorator::actionurl($url['url'], $_GET); - $destinationurl = $actionurl->value($_GET); + if (!\is_array($url)) { + return $this->getRedirectUrl($subject); } - $destinationurl = \str_replace('views/?', "views/{$subject}?", $destinationurl); - // $this->prtrace('destinationurl for ' . $subject, $destinationurl); - return $destinationurl; + $this->addFlash($url, 'getLastTabURL for ' . $subject); + // Load query vars into superglobal arrays + if (isset($url['urlvars'])) { + $urlvars = []; + + foreach ($url['urlvars'] as $key => $urlvar) { + //$this->prtrace($key, $urlvar); + $urlvars[$key] = \PHPPgAdmin\Decorators\Decorator::get_sanitized_value($urlvar, $_REQUEST); + } + $_REQUEST = \array_merge($_REQUEST, $urlvars); + $_GET = \array_merge($_GET, $urlvars); + } + $actionurl = \PHPPgAdmin\Decorators\Decorator::actionurl($url['url'], $_GET); + $destinationurl = $actionurl->value($_GET); + + return \str_replace('views/?', "views/{$subject}?", $destinationurl); } /** @@ -323,24 +234,60 @@ class ContainerUtils * * @param string $errormsg The error msg * - * @return ContainerInterface The app container + * @return\Slim\Container The app container */ - public function addError(string $errormsg): ContainerInterface + public function addError(string $errormsg): \Slim\Container { - //dump($errormsg); - $errors = $this->container->get('errors'); + $container = self::getContainerInstance(); + $errors = $container->get('errors'); $errors[] = $errormsg; - $this->container->offsetSet('errors', $errors); + $container->offsetSet('errors', $errors); + + return $container; + } - return $this->container; + /** + * Returns a string with html <br> variant replaced with a new line. + * + * @param string $msg message to parse (<br> separated) + * + * @return string parsed message (linebreak separated) + */ + public static function br2ln($msg) + { + return \str_replace(['<br>', '<br/>', '<br />'], \PHP_EOL, $msg); } - private function setConf($conf) + public static function getDefaultConfig(bool $debug = false): array + { + return [ + 'settings' => [ + 'displayErrorDetails' => $debug, + 'determineRouteBeforeAppMiddleware' => true, + 'base_path' => \dirname(__DIR__, 2), + 'debug' => $debug, + 'phpMinVer' => '7.2', // PHP minimum version + 'addContentLengthHeader' => false, + 'appName' => 'PHPPgAdmin6', + ], + ]; + } + + /** + * @param array $conf + */ + private function withConf($conf): self { $container = self::getContainerInstance(); $conf['plugins'] = []; - $container['conf'] = static function ($c) use ($conf) { + $container->BASE_PATH = $conf['BASE_PATH']; + $container->subFolder = $conf['subfolder']; + $container->debug = $conf['debugmode']; + $container->THEME_PATH = $conf['theme_path']; + $container->IN_TEST = $conf['IN_TEST']; + $container['errors'] = []; + $container['conf'] = static function (\Slim\Container $c) use ($conf): array { $display_sizes = $conf['display_sizes']; if (\is_array($display_sizes)) { @@ -371,115 +318,34 @@ class ContainerUtils return $conf; }; - $container->subfolder = self::SUBFOLDER; + + $container->subFolder = $conf['subfolder']; return $this; } /** - * Sets the views. + * This function registers the default services that Slim needs to work. * - * @return self ( description_of_the_return_value ) + * All services are shared, they are registered such that the + * same instance is returned on subsequent calls. + * + * @param array $userSettings Associative array of application settings */ - private function setViews() + private function registerDefaultServices($userSettings): void { - $container = self::getContainerInstance(); + $defaultSettings = $this->defaultSettings; /** - * return ViewManager. + * This service MUST return an array or an instance of ArrayAccess. + * + * @return array|ArrayAccess */ - $container['view'] = static function ($c) { - $misc = $c->misc; - $view = new ViewManager(BASE_PATH . '/assets/templates', [ - 'cache' => BASE_PATH . '/temp/twigcache', - 'auto_reload' => $c->get('settings')['debug'], - 'debug' => $c->get('settings')['debug'], - ], $c); - - $misc->setView($view); - - return $view; - }; - - return $this; - } - - /** - * Sets the instance of Misc class. - * - * @return self ( description_of_the_return_value ) - */ - private function setMisc() - { - $container = self::getContainerInstance(); - $container['misc'] = static function ($c) { - $misc = new \PHPPgAdmin\Misc($c); - - $conf = $c->get('conf'); - - // 4. Check for theme by server/db/user - $_server_info = $misc->getServerInfo(); - - /* starting with PostgreSQL 9.0, we can set the application name */ - if (isset($_server_info['pgVersion']) && 9 <= $_server_info['pgVersion']) { - \putenv('PGAPPNAME=' . $c->get('settings')['appName'] . '_' . $c->get('settings')['appVersion']); - } - - return $misc; + $this['settings'] = static function () use ($userSettings, $defaultSettings): \Slim\Collection { + return new Collection(\array_merge($defaultSettings, $userSettings)); }; - return $this; - } - - private function setExtra() - { - $container = self::getContainerInstance(); - $container['flash'] = static function () { - return new \Slim\Flash\Messages(); - }; - - $container['lang'] = static function ($c) { - $translations = new \PHPPgAdmin\Translations($c); - - return $translations->lang; - }; - - return $this; - } - - /** - * Traverse THEME_PATH, consider as theme folders those which - * contain a `global.css` stylesheet. - * - * @return array the theme folders - */ - private function getThemeFolders() - { - // no THEME_PATH (how?) then return empty array - if (!$gestor = \opendir(self::THEME_PATH)) { - \closedir($gestor); - - return []; - } - $themefolders = []; - - /* This is the right way to iterate on a folder */ - while (false !== ($foldername = \readdir($gestor))) { - if ('.' === $foldername || '..' === $foldername) { - continue; - } - - $folderpath = \sprintf('%s%s%s', self::THEME_PATH, \DIRECTORY_SEPARATOR, $foldername); - $stylesheet = \sprintf('%s%s%s', $folderpath, \DIRECTORY_SEPARATOR, 'global.css'); - // if $folderpath if indeed a folder and contains a global.css file, then it's a theme - if (\is_dir($folderpath) && - \is_file($stylesheet)) { - $themefolders[$foldername] = $folderpath; - } - } - - \closedir($gestor); - - return $themefolders; + $defaultProvider = new DefaultServicesProvider(); + $defaultProvider->register($this); } } |